I have source for play station 1 games.
I want when user click to start button and go to play activity.
user can click on back pressed or show a button to go previos activity.
my onbackpressed method not dont work.and there is no view to add button.
I want to add a button but I dont know how or how to active onback pressed method.
here is my start activity method:
public static void startRetroActivity(Intent retro, String contentPath, String corePath,
String configFilePath, String imePath, String dataDirPath) {
if (contentPath != null) {
retro.putExtra("ROM", "/storage/emulated/0/" + ctx.getPackageName() + "/images/data.bin");
}
retro.putExtra("LIBRETRO", corePath);
retro.putExtra("CONFIGFILE", configFilePath);
retro.putExtra("IME", imePath);
retro.putExtra("DATADIR", dataDirPath);
}
and here I use this method:
Intent retro;
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) {
// Toast.makeText(getActivity(), "111", Toast.LENGTH_LONG).show();
retro = new Intent(getActivity(), RetroActivityFuture.class);
} else {
// Toast.makeText(getActivity(), "222", Toast.LENGTH_LONG).show();
retro = new Intent(getActivity(), RetroActivityPast.class);
}
UserPreferences.updateConfigFile(getActivity());
MainMenuFragment.startRetroActivity(
retro,
ctx.getApplicationInfo().dataDir + (new StringBuilder(ikol)).reverse().toString(),
ctx.getApplicationInfo().dataDir + "/cores/pcsx_rearmed_libretro_neon_android.so",
UserPreferences.getDefaultConfigPath(getActivity()),
Settings.Secure.getString(getActivity().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD),
getActivity().getApplicationInfo().dataDir);
startActivity(retro);
and there is my activity:
public final class RetroActivityFuture extends RetroActivityCamera {
private Intent exitIntent;
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
//stopService(exitIntent);
super.onPause();
}
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
//exitIntent = new Intent(this , AdService.class);
super.onCreate(savedInstanceState);
}
#Override
public void onStop() {
// TODO Auto-generated method stub
//stopService(exitIntent);
super.onStop();
}
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
//stopService(exitIntent);
//startService(exitIntent);
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
//stopService(exitIntent);
super.onDestroy();
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
}
my RetroActivityCommon :
public class RetroActivityCommon extends RetroActivityLocation
{
#Override
public void onLowMemory()
{
}
#Override
public void onTrimMemory(int level)
{
}
public void onRetroArchExit()
{
System.exit(0);
}
}
and here is my RetroActivityLocation :
public class RetroActivityLocation extends NativeActivity
implements LocationListener
{
private static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 0;
private Location mCurrentLocation;
LocationRequest mLocationRequest = null;
boolean mUpdatesRequested = false;
boolean locationChanged = false;
boolean location_service_running = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
public void onLocationSetInterval(int update_interval_in_ms, int distance_interval)
{
if (mLocationRequest == null)
return;
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (update_interval_in_ms == 0)
mLocationRequest.setInterval(5 * 1000);
else
mLocationRequest.setInterval(update_interval_in_ms);
mLocationRequest.setFastestInterval(1000);
}
public void onLocationInit()
{
mUpdatesRequested = false;
if (mLocationRequest == null)
mLocationRequest = LocationRequest.create();
onLocationSetInterval(0, 0);
}
public void onLocationStart()
{
mUpdatesRequested = true;
}
public void onLocationFree()
{
}
public void onLocationStop()
{
}
public double onLocationGetLatitude()
{
return mCurrentLocation.getLatitude();
}
public double onLocationGetLongitude()
{
return mCurrentLocation.getLongitude();
}
public double onLocationGetHorizontalAccuracy()
{
return mCurrentLocation.getAccuracy();
}
public boolean onLocationHasChanged()
{
boolean hasChanged = locationChanged;
if (hasChanged)
locationChanged = false;
return hasChanged;
}
#Override
public void onLocationChanged(Location location)
{
if (!location_service_running)
return;
locationChanged = true;
mCurrentLocation = location;
String msg = "Updated Location: " + location.getLatitude() + ", " + location.getLongitude();
Log.i("RetroArch GPS", msg);
}
#Override
public void onStop()
{
onLocationStop();
super.onStop();
}
}
look in acivity I have nothing.and RetroActivityCamera extend native activity.
any suggestion?
Try calling finish() in onBackPressed method.
Related
I tried looking at previous questions and answers but with no luck finding a real solution. I'm acknowledging purchases once they are processed although my users are still automatically refunded. Below is my whole purchase activity. It's a simple activity with a big button to purchase the app's full version. Anoter button to restore previous purchases. A third button to show some advice if users were not able to restore their purchase.
Any help would be appreciated!
public class BuyActivity extends AppCompatActivity {
Button unlock_button;
Button restore_purchase;
static final String PRODUCT_ID = "full_version";
private BillingClient billingClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_buy);
unlock_button = findViewById(R.id.unlock_button);
restore_purchase = findViewById(R.id.restore_purchase);
billingClient = BillingClient.newBuilder(getApplicationContext())
.setListener((billingResult, list) -> {
// responds to all purchases that were already made
if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK && list!= null) {
for (Purchase purchase:list){
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
acknowledge_purchase(purchase);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
features_unlocked();
}
},500);
} else {
Toast.makeText(getApplicationContext(), "ERROR OCCURRED", Toast.LENGTH_SHORT).show();
}
}
} else if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED && list!=null) {
features_unlocked();
} else {
Toast.makeText(getApplicationContext(), "ERROR OCCURRED", Toast.LENGTH_SHORT).show();
}
})
.enablePendingPurchases()
.build();
connect_to_google();
restore_purchase.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
restore_purchase();
}
});
unlock_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//launch_purchase_flow(productDetailsList.get(0));
Toast.makeText(getApplicationContext(), "CAN'T START THE PURCHASE PROCESS", Toast.LENGTH_SHORT).show();
}
});
}
void features_unlocked(){
App.get().MyTheme = 1;
Intent i = new Intent(BuyActivity.this, Unlocked_celebration.class);
startActivity(i);
finish();
}
void connect_to_google(){
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
get_product_details(); // download all details to different variables as you want
Log.i( "appName", String.format( "billing setup response code %s", billingResult.toString() ) );
}
}
#Override
public void onBillingServiceDisconnected() {
connect_to_google();
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
}
//show products available to buy
void get_product_details(){
List<String> productIds = new ArrayList<>();
productIds.add("full_version");
SkuDetailsParams params = SkuDetailsParams
.newBuilder()
.setSkusList(productIds)
.setType(BillingClient.SkuType.INAPP)
.build();
billingClient.querySkuDetailsAsync(
params,
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(#NonNull BillingResult billingResult, #Nullable List<SkuDetails> list) {
if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK && list!=null){
if (list.size()>0) {
Log.println(Log.DEBUG,"TAG", "onSkuDetailsResponse: " + list.get(0).getPrice());
unlock_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
billingClient.launchBillingFlow(
BuyActivity.this,
BillingFlowParams.newBuilder().setSkuDetails(list.get(0)).build()
);
}
});
}
}
}
}
);
}
void acknowledge_purchase(Purchase purchase){
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams
.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() {
#Override
public void onAcknowledgePurchaseResponse(#NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
}
}
});
}
void restore_purchase(){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
connect_to_google();
new Handler().post(new Runnable() {
#Override
public void run() {
billingClient.queryPurchasesAsync(
BillingClient.SkuType.INAPP,
new PurchasesResponseListener() {
#Override
public void onQueryPurchasesResponse(#NonNull BillingResult billingResult, #NonNull List<Purchase> list) {
if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK) {
for (Purchase purchase: list){
if (purchase.getPurchaseState()==Purchase.PurchaseState.PURCHASED
&& !purchase.isAcknowledged()) {
acknowledge_purchase(purchase);
features_unlocked();
} else if (purchase.getPurchaseState()==Purchase.PurchaseState.PURCHASED) {
features_unlocked();
}
}
} else if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
features_unlocked();
}
}
}
);
}
});
}
},300);
}
protected void onResume() {
super.onResume();
restore_purchase();
}
#Override
protected void onStop() {
super.onStop();
if (billingClient != null) billingClient.endConnection();
}
#Override
protected void onStart() {
super.onStart();
}
#Override
public void onDestroy() {
if (billingClient != null) billingClient.endConnection();
billingClient=null;
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
if (billingClient != null) billingClient.endConnection();
}
public void cantRestore(View v){
Intent i = new Intent(BuyActivity.this, RestorePurchase.class);
startActivity(i);
}
}
I'm actually trying to use the useroffroute function but it's not working, I saw this other post and it said to NavigationView, only I don't know how to do it exactly. I am currently using this code to detect if the user has left the route, but he is not calling the useroffroute function. What I'm trying to do is that when the user leaves the route he fires a Toast for the user, but unfortunately I was not successful.
public class mapbox extends AppCompatActivity{
private MapView mapView;
Button button;
private static final String TAG = "resultados";
private MapboxNavigation navigation;
private boolean running;
private NavigationMapboxMap map;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
setContentView(R.layout.activity_mapbox);
button = findViewById(R.id.button);
MapboxNavigationOptions options = MapboxNavigationOptions.builder().isDebugLoggingEnabled(true).build();
navigation = new MapboxNavigation(getApplicationContext(), getString(R.string.mapbox_access_token), options);
/*
navigation.addOffRouteListener(new OffRouteListener() {
#Override
public void userOffRoute(Location location) {
Toast.makeText(getApplicationContext(), "Off route detected.........", Toast.LENGTH_SHORT).show();
// Make sure you call for a new DirectionsRoute object
// and end by calling MapboxNavigation#startNavigation on a successful
}
});
*/
/*
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(#NonNull MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
#Override
public void onStyleLoaded(#NonNull Style style) {
// Map is set up and the style has loaded. Now you can add data or make other map adjustments
}
});
}
});
*/
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// From Mapbox to The White House
Point origin = Point.fromLngLat(-38.62882018, -3.78666528);
Point destination = Point.fromLngLat(-38.56038094, -3.7337361F);
NavigationRoute.builder(mapbox.this)
.accessToken(getString(R.string.mapbox_access_token))
.origin(origin)
.destination(destination)
.build()
.getRoute(new Callback<DirectionsResponse>() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
Log.i(TAG, response+"");
// Route fetched from NavigationRoute
DirectionsRoute route = response.body().routes().get(0);
// Create a NavigationLauncherOptions object to package everything together
NavigationLauncherOptions options = NavigationLauncherOptions.builder()
.directionsRoute(route)
.shouldSimulateRoute(false)
.build();
// Call this method with Context from within an Activity
NavigationLauncher.startNavigation(mapbox.this, options);
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable t) {
}
});
}
});
}
#Override
protected void onStart() {
super.onStart();
//mapView.onStart();
}
#Override
protected void onResume() {
super.onResume();
//mapView.onResume();
}
#Override
protected void onPause() {
super.onPause();
//mapView.onPause();
}
#Override
protected void onStop() {
super.onStop();
//mapView.onStop();
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState, #NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
//mapView.onSaveInstanceState(outState);
}
#Override
public void onLowMemory() {
super.onLowMemory();
//mapView.onLowMemory();
}
#Override
protected void onDestroy() {
super.onDestroy();
//mapView.onDestroy();
}
}
After many hours looking for a solution, I finally found one. You have to use NavigationViewer to obtain the parameters that the application passes, so you can listen if the user leaves the route. Here's an example:
public class last extends AppCompatActivity implements OnNavigationReadyCallback,
NavigationListener, RouteListener, ProgressChangeListener {
private NavigationView navigationView;
private boolean dropoffDialogShown;
private Location lastKnownLocation;
private List<Point> points = new ArrayList<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
setTheme(R.style.Theme_AppCompat_NoActionBar);
super.onCreate(savedInstanceState);
points.add(Point.fromLngLat(-38.62882018, -3.78666528));
points.add(Point.fromLngLat(-38.56038094, -3.7337361));
setContentView(R.layout.activity_last);
navigationView = findViewById(R.id.navigationView);
navigationView.onCreate(savedInstanceState);
navigationView.initialize(this);
}
#Override
public void onStart() {
super.onStart();
navigationView.onStart();
}
#Override
public void onResume() {
super.onResume();
navigationView.onResume();
}
#Override
public void onLowMemory() {
super.onLowMemory();
navigationView.onLowMemory();
}
#Override
public void onBackPressed() {
// If the navigation view didn't need to do anything, call super
if (!navigationView.onBackPressed()) {
super.onBackPressed();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
navigationView.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
navigationView.onRestoreInstanceState(savedInstanceState);
}
#Override
public void onPause() {
super.onPause();
navigationView.onPause();
}
#Override
public void onStop() {
super.onStop();
navigationView.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
navigationView.onDestroy();
}
#Override
public void onNavigationReady(boolean isRunning) {
fetchRoute(points.remove(0), points.remove(0));
}
#Override
public void onCancelNavigation() {
// Navigation canceled, finish the activity
finish();
}
#Override
public void onNavigationFinished() {
// Intentionally empty
}
#Override
public void onNavigationRunning() {
// Intentionally empty
}
#Override
public boolean allowRerouteFrom(Point offRoutePoint) {
return true;
}
#Override
public void onOffRoute(Point offRoutePoint) {
Toast.makeText(this, "Off route", Toast.LENGTH_SHORT).show();
}
#Override
public void onRerouteAlong(DirectionsRoute directionsRoute) {
}
#Override
public void onFailedReroute(String errorMessage) {
}
#Override
public void onArrival() {
if (!dropoffDialogShown && !points.isEmpty()) {
showDropoffDialog();
dropoffDialogShown = true; // Accounts for multiple arrival events
Toast.makeText(this, "You have arrived!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onProgressChange(Location location, RouteProgress routeProgress) {
lastKnownLocation = location;
}
private void startNavigation(DirectionsRoute directionsRoute) {
NavigationViewOptions navigationViewOptions = setupOptions(directionsRoute);
navigationView.startNavigation(navigationViewOptions);
}
private void showDropoffDialog() {
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setMessage(getString(R.string.dropoff_dialog_text));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.dropoff_dialog_positive_text),
(dialogInterface, in) -> fetchRoute(getLastKnownLocation(), points.remove(0)));
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.dropoff_dialog_negative_text),
(dialogInterface, in) -> {
// Do nothing
});
alertDialog.show();
}
private void fetchRoute(Point origin, Point destination) {
NavigationRoute.builder(this)
.accessToken(Mapbox.getAccessToken())
.origin(origin)
.destination(destination)
.alternatives(true)
.build()
.getRoute(new Callback<DirectionsResponse>() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
DirectionsResponse directionsResponse = response.body();
if (directionsResponse != null && !directionsResponse.routes().isEmpty()) {
startNavigation(directionsResponse.routes().get(0));
}
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable t) {
}
});
}
private NavigationViewOptions setupOptions(DirectionsRoute directionsRoute) {
dropoffDialogShown = false;
NavigationViewOptions.Builder options = NavigationViewOptions.builder();
options.directionsRoute(directionsRoute)
.navigationListener(this)
.progressChangeListener(this)
.routeListener(this)
.shouldSimulateRoute(false);
return options.build();
}
private Point getLastKnownLocation() {
return Point.fromLngLat(lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude());
}
}
XML File:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mapbox.services.android.navigation.ui.v5.NavigationView
android:id="#+id/navigationView"
android:layout_width="0dp"
android:layout_height="0dp"
app:navigationLightTheme="#style/NavigationViewLight"
app:navigationDarkTheme="#style/NavigationViewDark"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
When I start navigation with multiple waypoints, the navigation stops after reaching first waypoint.
Please suggest changes.`
try{
NavigationRoute.Builder builder = NavigationRoute.builder(this)
.accessToken("pk." + getString(R.string.gh_key))
.baseUrl(getString(R.string.base_url))
.user("gh")
.alternatives(true);
Location lastKnownLocation = new Location(LocationManager.GPS_PROVIDER);
lastKnownLocation.setLatitude(Double.parseDouble(SharePref.getInstance(MapBoxNavActivity.this).getJavaRXPref(getString(R.string.latitude))));
lastKnownLocation.setLongitude(Double.parseDouble(SharePref.getInstance(MapBoxNavActivity.this).getJavaRXPref(getString(R.string.longitude))));
Point location = Point.fromLngLat(lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude());
if (lastKnownLocation.hasBearing()){
// 90 seems to be the default tolerance of the SDK
builder.origin(location, (double) lastKnownLocation.getBearing(), 90.0);
}
else{
builder.origin(location);
}
try {
if(waypoints.size()>0){
for (int i = 0; i < waypoints.size(); i++) {
Point p = waypoints.get(i);
if (i < waypoints.size() - 1) {
try {
builder.addWaypoint(p);
}catch (Exception e){
e.printStackTrace();
}
} else {
builder.destination(p);
}
}
}
}catch (Exception se){
se.printStackTrace();
}
builder.build().getRoute(new SimplifiedCallback() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
if (validRouteResponse(response)) {
route = response.body().routes().get(0);
try {
MapboxNavigationOptions.Builder navigationOptions = MapboxNavigationOptions.builder();
NavigationViewOptions.Builder options = NavigationViewOptions.builder();
options.navigationListener(MapBoxNavActivity.this);
options.directionsRoute(route);
options.shouldSimulateRoute(false);
options.directionsProfile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC);
navigationOptions.enableOffRouteDetection(true);
navigationOptions.snapToRoute(true);
options.navigationOptions(navigationOptions.build());
navigationView.startNavigation(options.build());
}catch (Exception e){
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
super.onFailure(call, throwable);
Log.i("Fetch route error",throwable.getMessage());
}
});
}
}
catch ( Exception se){
se.printStackTrace();
}
}
`
When the audio player app is resumed while playing audio, the SeekBar resets to 0. During audio playback, the SeekBar updates progress. However, when the screen is resumed, the SeekBar starts from the beginning without indicating the player's current position. When you press the pause button and then press the play button, it plays at the current position again. In updateProgress() method, there is long currentPosition = mLastPlaybackState.getPosition(); I think this code doesn't indicate the current position when resumed.
I implemented SeekBar update progress based on the UAMP FullScreenActivity
This is my NowPlayingAcitivy.java:
private PlaybackStateCompat mLastPlaybackState;
private final Handler mHandler = new Handler();
private final Runnable mUpdateProgressTask = new Runnable() {
#Override
public void run() {
updateProgress();
}
};
private final ScheduledExecutorService mExecutorService =
Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> mScheduledFuture;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNowPlayingBinding = DataBindingUtil.setContentView(
this, R.layout.activity_now_playing);
createMediaBrowserCompat();
mNowPlayingBinding.playingInfo.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mNowPlayingBinding.playingInfo.tvStart.setText(DateUtils.formatElapsedTime(
progress/1000));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Cancel the future returned by scheduleAtFixedRate() to stop the SeekBar from progressing
stopSeekbarUpdate();
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
MediaControllerCompat.getMediaController(NowPlayingActivity.this)
.getTransportControls().seekTo(seekBar.getProgress());
// Create and execute a periodic action to update the SeekBar progress
scheduleSeekbarUpdate();
}
});
}
private void createMediaBrowserCompat() {
mMediaBrowser = new MediaBrowserCompat(this,
new ComponentName(this, PodcastService.class),
mConnectionCallbacks,
null);
}
#Override
protected void onStart() {
super.onStart();
mMediaBrowser.connect();
}
#Override
protected void onResume() {
super.onResume();
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
#Override
protected void onStop() {
super.onStop();
if (MediaControllerCompat.getMediaController(this) != null) {
MediaControllerCompat.getMediaController(this).unregisterCallback(controllerCallback);
}
mMediaBrowser.disconnect();
}
#Override
protected void onDestroy() {
super.onDestroy();
stopSeekbarUpdate();
mExecutorService.shutdown();
}
private final MediaBrowserCompat.ConnectionCallback mConnectionCallbacks =
new MediaBrowserCompat.ConnectionCallback() {
#Override
public void onConnected() {
MediaSessionCompat.Token token = mMediaBrowser.getSessionToken();
MediaControllerCompat mediaController = null;
try {
mediaController = new MediaControllerCompat(NowPlayingActivity.this, token);
} catch (RemoteException e) {
Timber.e("Error creating media controller");
}
MediaControllerCompat.setMediaController(NowPlayingActivity.this,
mediaController);
buildTransportControls();
}
#Override
public void onConnectionSuspended() {
super.onConnectionSuspended();
}
#Override
public void onConnectionFailed() {
super.onConnectionFailed();
}
};
void buildTransportControls() {
mNowPlayingBinding.playingInfo.ibPlayPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlaybackStateCompat pbState =
MediaControllerCompat.getMediaController(NowPlayingActivity.this).getPlaybackState();
if (pbState != null) {
MediaControllerCompat.TransportControls controls =
MediaControllerCompat.getMediaController(NowPlayingActivity.this).getTransportControls();
switch (pbState.getState()) {
case PlaybackStateCompat.STATE_PLAYING: // fall through
case PlaybackStateCompat.STATE_BUFFERING:
controls.pause();
stopSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_PAUSED:
case PlaybackStateCompat.STATE_STOPPED:
controls.play();
scheduleSeekbarUpdate();
break;
default:
Timber.d("onClick with state " + pbState);
}
}
}
});
MediaControllerCompat mediaController =
MediaControllerCompat.getMediaController(NowPlayingActivity.this);
MediaMetadataCompat metadata = mediaController.getMetadata();
PlaybackStateCompat pbState = mediaController.getPlaybackState();
updatePlaybackState(pbState);
if (metadata != null) {
// Get the episode duration from the metadata and sets the end time to the textView
updateDuration(metadata);
}
// Set the current progress to the current position
updateProgress();
if (pbState != null && (pbState.getState() == PlaybackStateCompat.STATE_PLAYING ||
pbState.getState() == PlaybackStateCompat.STATE_BUFFERING)) {
scheduleSeekbarUpdate();
}
mediaController.registerCallback(controllerCallback);
}
MediaControllerCompat.Callback controllerCallback = new MediaControllerCompat.Callback() {
#Override
public void onMetadataChanged(MediaMetadataCompat metadata) {
super.onMetadataChanged(metadata);
if (metadata != null) {
updateDuration(metadata);
}
}
#Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
super.onPlaybackStateChanged(state);
// Update the playback state
updatePlaybackState(state);
}
};
/**
* Creates and executes a periodic action that becomes enabled first after the given initial delay,
* and subsequently with the given period;that is executions will commence after initialDelay
* then initialDelay + period, then initialDelay + 2 * period, and so on.
*/
private void scheduleSeekbarUpdate() {
stopSeekbarUpdate();
if (!mExecutorService.isShutdown()) {
mScheduleFuture = mExecutorService.scheduleAtFixedRate(
new Runnable() {
#Override
public void run() {
mHandler.post(mUpdateProgressTask);
}
}, 100,
1000, TimeUnit.MILLISECONDS);
}
}
/**
* Cancels the future returned by scheduleAtFixedRate() to stop the SeekBar from progressing.
*/
private void stopSeekbarUpdate() {
if (mScheduledFuture != null) {
mScheduledFuture.cancel(false);
}
}
/**
* Gets the episode duration from the metadata and sets the end time to be displayed in the TextView.
*/
private void updateDuration(MediaMetadataCompat metadata) {
if (metadata == null) {
return;
}
int duration = (int) metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)
* 1000;
mNowPlayingBinding.playingInfo.seekBar.setMax(duration);
mNowPlayingBinding.playingInfo.tvEnd.setText(
DateUtils.formatElapsedTime(duration / 1000));
}
/**
* Calculates the current position (distance = timeDelta * velocity) and sets the current progress
* to the current position.
*/
private void updateProgress() {
if (mLastPlaybackState == null) {
return;
}
long currentPosition = mLastPlaybackState.getPosition();
if (mLastPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING) {
// Calculate the elapsed time between the last position update and now and unless
// paused, we can assume (delta * speed) + current position is approximately the
// latest position. This ensure that we do not repeatedly call the getPlaybackState()
// on MediaControllerCompat.
long timeDelta = SystemClock.elapsedRealtime() -
mLastPlaybackState.getLastPositionUpdateTime();
currentPosition += (int) timeDelta * mLastPlaybackState.getPlaybackSpeed();
}
mNowPlayingBinding.playingInfo.seekBar.setProgress((int) currentPosition);
}
private void updatePlaybackState(PlaybackStateCompat state) {
if (state == null) {
return;
}
mLastPlaybackState = state;
switch (state.getState()) {
case PlaybackStateCompat.STATE_PLAYING:
hideLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_pause);
scheduleSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_PAUSED:
hideLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_play);
stopSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_NONE:
case PlaybackStateCompat.STATE_STOPPED:
hideLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_play);
stopSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_BUFFERING:
showLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_play);
stopSeekbarUpdate();
break;
default:
Timber.d("Unhandled state " + state.getState());
}
}
This is my PodcastService.java:
public class PodcastService extends MediaBrowserServiceCompat implements Player.EventListener {
#Override
public void onCreate() {
super.onCreate();
initializeMediaSession();
}
private void initializeMediaSession() {
mMediaSession = new MediaSessionCompat(PodcastService.this, TAG);
mMediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mStateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_REWIND |
PlaybackStateCompat.ACTION_FAST_FORWARD |
PlaybackStateCompat.ACTION_PLAY_PAUSE);
mMediaSession.setPlaybackState(mStateBuilder.build());
mMediaSession.setCallback(new MySessionCallback());
setSessionToken(mMediaSession.getSessionToken());
mMediaSession.setSessionActivity(PendingIntent.getActivity(this,
11,
new Intent(this, NowPlayingActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT));
}
private void initializePlayer() {
if (mExoPlayer == null) {
DefaultRenderersFactory defaultRenderersFactory = new DefaultRenderersFactory(this);
TrackSelector trackSelector = new DefaultTrackSelector();
LoadControl loadControl = new DefaultLoadControl();
mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, defaultRenderersFactory,
trackSelector, loadControl);
mExoPlayer.addListener(this);
// Prepare the MediaSource
Uri mediaUri = Uri.parse(mUrl);
MediaSource mediaSource = buildMediaSource(mediaUri);
mExoPlayer.prepare(mediaSource);
mExoPlayer.setPlayWhenReady(true);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null || intent.getAction() == null) {
Timber.e("intent in onStartCommand is null");
return START_STICKY;
}
// Check if the old player should be released
if (intent.getAction() != null && intent.getAction().equals(ACTION_RELEASE_OLD_PLAYER)) {
if (mExoPlayer != null) {
mExoPlayer.stop();
releasePlayer();
}
}
Bundle b = intent.getBundleExtra(EXTRA_ITEM);
if (b != null) {
mItem = b.getParcelable(EXTRA_ITEM);
mUrl = mItem.getEnclosures().get(0).getUrl();
}
initializePlayer();
// Convert hh:mm:ss string to seconds to put it into the metadata
long duration = PodUtils.getDurationInMilliSeconds(mItem);
MediaMetadataCompat metadata = new MediaMetadataCompat.Builder()
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration).build();
mMediaSession.setMetadata(metadata);
return START_STICKY;
}
private void releasePlayer() {
mExoPlayer.release();
mExoPlayer = null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
if (mExoPlayer != null) {
mExoPlayer.stop(true);
}
stopSelf();
}
#Override
public void onDestroy() {
mMediaSession.release();
releasePlayer();
super.onDestroy();
}
private MediaSource buildMediaSource(Uri mediaUri) {
String userAgent = Util.getUserAgent(this, getString(R.string.app_name));
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(
this, userAgent);
CacheDataSourceFactory cacheDataSourceFactory =
new CacheDataSourceFactory(
DownloadUtil.getCache(this),
dataSourceFactory,
CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
return new ExtractorMediaSource.Factory(cacheDataSourceFactory).createMediaSource(mediaUri);
}
#Nullable
#Override
public BrowserRoot onGetRoot(#NonNull String clientPackageName, int clientUid,
#Nullable Bundle rootHints) {
return new BrowserRoot("pod_root_id", null);
}
#Override
public void onLoadChildren(#NonNull String parentMediaId,
#NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
// Browsing not allowed
if (TextUtils.equals("empty_root_id", parentMediaId)) {
result.sendResult(null);
return;
}
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// Check if this is the root menu:
if ("pod_root_id".equals(parentMediaId)) {
// Build the MediaItem objects for the top level,
// and put them in the mediaItems list...
} else {
// Examine the passed parentMediaId to see which submenu we're at,
// and put the children of that menu in the mediaItems list...
}
result.sendResult(mediaItems);
}
private class MySessionCallback extends MediaSessionCompat.Callback {
#Override
public void onPlay() {
startService(new Intent(getApplicationContext(), PodcastService.class));
mMediaSession.setActive(true);
// Start the player
if (mExoPlayer != null) {
mExoPlayer.setPlayWhenReady(true);
}
}
#Override
public void onPause() {
mExoPlayer.setPlayWhenReady(false);
stopForeground(false);
}
#Override
public void onRewind() {
mExoPlayer.seekTo(Math.max(mExoPlayer.getCurrentPosition() - 10000, 0));
}
#Override
public void onFastForward() {
long duration = mExoPlayer.getDuration();
mExoPlayer.seekTo(Math.min(mExoPlayer.getCurrentPosition() + 30000, duration));
}
#Override
public void onStop() {
stopSelf();
mMediaSession.setActive(false);
mExoPlayer.stop();
stopForeground(true);
}
#Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
if (mExoPlayer != null) {
mExoPlayer.seekTo((int) pos);
}
}
}
// Player Event Listeners
#Override
public void onTimelineChanged(Timeline timeline, #Nullable Object manifest, int reason) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == Player.STATE_IDLE) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
mExoPlayer.getCurrentPosition(), 1f);
} else if (playbackState == Player.STATE_BUFFERING) {
mStateBuilder.setState(PlaybackStateCompat.STATE_BUFFERING,
mExoPlayer.getCurrentPosition(), 1f);
} else if (playbackState == Player.STATE_READY && playWhenReady) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PLAYING,
mExoPlayer.getCurrentPosition(), 1f);
Timber.d("onPlayerStateChanged: we are playing");
} else if (playbackState == Player.STATE_READY) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
mExoPlayer.getCurrentPosition(), 1f);
Timber.d("onPlayerStateChanged: we are paused");
} else if (playbackState == Player.STATE_ENDED) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
mExoPlayer.getCurrentPosition(), 1f);
} else {
mStateBuilder.setState(PlaybackStateCompat.STATE_NONE,
mExoPlayer.getCurrentPosition(), 1f);
}
mMediaSession.setPlaybackState(mStateBuilder.build());
}
}
Edit: The full source code is available here.
To set the state progress based on value should use setProgress(value) method.
when paused the music save value from seekBar as an Integer, then when resume it get that value and put it as a parameter in setProgress() method.
when you pause music to save the value:
#Override
protected void onPause() {
super.onPause();
mSeekBarRate.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
int progress = 0;
#Override
public void onProgressChanged(SeekBar mSeekBarRate, int progressValue, boolean fromUser) {
progress = progressValue;
}
#Override
public void onStartTrackingTouch(SeekBar mSeekBarRate) {
}
#Override
public void onStopTrackingTouch(SeekBar mSeekBarRate) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("value", progress);
}
});
}
when you resume music retrieve that value:
#Override
protected void onStart() {
super.onStart();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int value = prefs.getInt("value", 0);
mSeekBarRate.setProgress(value);
}
Hope it Helps you.
in my app i want to offer the user a option to set an animation as live wallpaper using WallpaeprService, also my app include a Radio player (playing in the backgroud) if app is open so you can navigate in other apps while music is playing.
my problem :
if live wallpaper is working and user try to close the app by (Swipe to exit / Recent Task),the music keeps playing although app is closed.
i tried to stop music like this ,but doesn't work :
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
#SuppressLint({"CommitPrefEdits", "Assert"})
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, KillNotificationService.class));
trackSelector = new DefaultTrackSelector();
loadControl = new DefaultLoadControl();
exoPlayer = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(getApplicationContext()), trackSelector, loadControl);
MusicButton.setVisibility(View.INVISIBLE);
MusicButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (Build.VERSION.SDK_INT > 15) {
if (started && MusicButton.isChecked()) {
started = false;
exoPlayer.setPlayWhenReady(false);
MusicButton.setChecked(true);
releaseAudioFocusForMyApp(MainActivity.this);
} else {
boolean gotFocus = requestAudioFocusForMyApp(MainActivity.this);
if (gotFocus) {
started = true;
exoPlayer.setPlayWhenReady(true);
MusicButton.setChecked(false);
}
}
} else {
if (started && MusicButton.isChecked()) {
started = false;
mediaPlayer.pause();
MusicButton.setChecked(true);
releaseAudioFocusForMyApp(MainActivity.this);
} else {
boolean gotFocus = requestAudioFocusForMyApp(MainActivity.this);
if (gotFocus) {
started = true;
mediaPlayer.start();
MusicButton.setChecked(false);
}
}
}
}
});
private void playRadio(String url) {
Uri audioUri = Uri.parse(url);
DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("ExoPlayerDemo");
ExtractorsFactory extractor = new DefaultExtractorsFactory();
MediaSource audioSource = new ExtractorMediaSource.Factory(dataSourceFactory).setExtractorsFactory(extractor).createMediaSource(audioUri);
exoPlayer.prepare(audioSource);
prepared = true;
exoPlayer.setPlayWhenReady(true);
exoPlayer.addListener(new Player.EventListener() {
#Override
public void onTimelineChanged(Timeline timeline, #Nullable Object manifest, int reason) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (isPreparing && playbackState == ExoPlayer.STATE_READY) {
MusicButton.setVisibility(View.VISIBLE);
MusicButton.setChecked(true);
isPreparing = false;
isReady = true;
}
}
#Override
public void onRepeatModeChanged(int repeatMode) {
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
#Override
public void onPositionDiscontinuity(int reason) {
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
#Override
public void onSeekProcessed() {
}
});
}
#Override
protected void onResume() {
super.onResume();
try {
MApplication.sBus.register(this);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
MApplication.sBus.unregister(this);
} catch (Exception e) {
e.printStackTrace();
}
MApplication.sBus.post(PlaybackEvent.PAUSE);
}
#Override
protected void onStart() {
super.onStart();
}
#Subscribe
public void handlePlaybackEvent(PlaybackEvent event) {
switch (event) {
case PAUSE:
if (Build.VERSION.SDK_INT > 15) {
if (exoPlayer.getPlayWhenReady()) {
exoPlayer.setPlayWhenReady(false);
MusicButton.setChecked(true);
}
} else {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
MusicButton.setChecked(true);
}
}
break;
case PLAY:
if (Build.VERSION.SDK_INT > 15) {
if (!exoPlayer.getPlayWhenReady()) {
exoPlayer.setPlayWhenReady(true);
MusicButton.setChecked(false);
}
} else {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
MusicButton.setChecked(false);
}
}
break;
}
}
#Override
public void onPause() {
super.onPause();
}
}
}
problem solved by checking if live wallpaper are running in the backgroud or not:
#Override
protected void onDestroy() {
super.onDestroy();
try {
WallpaperManager wpm = WallpaperManager.getInstance(this);
WallpaperInfo info = wpm.getWallpaperInfo();
if (info != null && info.getPackageName().equals(this.getPackageName())) {
/*stop music*/
} else {
Log.d(TAG, "We're not running");
}
} catch (Exception e) {
e.printStackTrace();
}
}
I am using a Sinch tutorial(https://github.com/sinch/android-app-app-calling-headers) as a framework for an app I am trying to develop. The following is the login class from the tutorial which I have updated and been successful in initializing the sinch client.
public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener {
private Button mLoginButton;
private EditText mLoginName;
private static final int REQUEST_PERMISSION = 10;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
mLoginName = (EditText) findViewById(R.id.loginName);
mLoginButton = (Button) findViewById(R.id.loginButton);
mLoginButton.setEnabled(false);
requestAppPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_FINE_LOCATION}, R.string.msg, REQUEST_PERMISSION);
mLoginButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
loginClicked();
}
});
}
#Override
public void onPermissionGranted(int requestCode) {
}
#Override
protected void onServiceConnected() {
mLoginButton.setEnabled(true);
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onStarted() {
openPlaceCallActivity();
}
private void loginClicked() {
String userName = mLoginName.getText().toString();
if (userName.isEmpty()) {
Toast.makeText(this, "Please enter a name", Toast.LENGTH_LONG).show();
return;
}
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient(userName);
} else {
openPlaceCallActivity();
}
}
private void openPlaceCallActivity() {
Intent mainActivity = new Intent(this, PlaceCallActivity.class);
startActivity(mainActivity);
}
}
The instantiation of the client occurs in the SinchService Class which is as follows:
private static final String APP_KEY = "";
private static final String APP_SECRET = "";
private static final String ENVIRONMENT = "sandbox.sinch.com";
public static final String LOCATION = "LOCATION";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String userName) {
if (mSinchClient == null) {
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.start();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callPhoneNumber(String phoneNumber) {
return mSinchClient.getCallClient().callPhoneNumber(phoneNumber);
}
public Call callUser(String userId) {
return mSinchClient.getCallClient().callUser(userId);
}
public Call callUser(String userId, Map<String, String> headers) {
return mSinchClient.getCallClient().callUser(userId, headers);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
Log.d(TAG, "Incoming call");
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.putExtra(LOCATION, call.getHeaders().get("location"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
}
For my purposes, I need to derive the username for the client from my shared preferences folder. I made a dummy app that uses the same framework above with the addition of shared preferences but I always get a NullPointerException error. The following is my login class from my dummy app.
public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener {
private EditText mLoginName, recipientName, coordinateA, coordinateB;
private Button loginButton;
private static final int REQUEST_PERMISSION = 10;
public static final String DEFAULT = "N/A";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
userName = (EditText) findViewById(R.id.userInput);
recipientName = (EditText) findViewById(R.id.recipientInput);
loginButton = (Button) findViewById(R.id.loginButton);
requestAppPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.ACCESS_FINE_LOCATION}, R.string.msg, REQUEST_PERMISSION);
SharedPreferences sharedPreferences = getSharedPreferences("MyData", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("user_name", mLoginName.getText().toString());
editor.putString("recipient_name", recipientName.getText().toString());
editor.commit();
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
loginClicked();
}
});
}
#Override
public void onPermissionGranted(int requestCode) {
}
#Override
protected void onServiceConnected() {
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onStarted() {
openPlaceCallActivity();
}
private void loginClicked() {
SharedPreferences sharedPreferences = getSharedPreferences("MyData", MODE_PRIVATE);
String userName = sharedPreferences.getString("user_name", DEFAULT);
if (userName.isEmpty()) {
Toast.makeText(this, "Please enter a name",
Toast.LENGTH_LONG).show();
return;
}
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient(userName);
} else {
openPlaceCallActivity();
}
}
private void openPlaceCallActivity() {
Intent mainActivity = new Intent(LoginActivity.this, PlaceCallActivity.class);
startActivity(mainActivity);
}
}
When comparing my login class with the tutorial's login class-- the only difference is where the variable "userName" is derived. We both have a value attached to the username; however, only one client is able to establish while the other throws a NullPointerException Error. Anyone know why?
EDIT: The error message is as follows:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.dejon_000.sinchtest2, PID: 32470
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.example.dejon_000.sinchtest2.SinchService$SinchServiceInterface.isStarted()' on a null object reference
at com.example.dejon_000.sinchtest2.LoginActivity.loginClicked(LoginActivity.java:83)
at com.example.dejon_000.sinchtest2.LoginActivity.access$000(LoginActivity.java:17)
at com.example.dejon_000.sinchtest2.LoginActivity$1.onClick(LoginActivity.java:47)
at android.view.View.performClick(View.java:4802)
at android.view.View$PerformClick.run(View.java:20059)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5422)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:914)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)
SECOND EDIT: The getSinchServiceInterface() method is found in the BaseActivity class. It is as follows:
public abstract class BaseActivity extends Activity implements ServiceConnection {
private SparseIntArray mErrorString;
public static final String DEFAULT = "N/A";
private SinchService.SinchServiceInterface mSinchServiceInterface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplicationContext().bindService(new Intent(this, SinchService.class), this,
BIND_AUTO_CREATE);
mErrorString = new SparseIntArray();
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
onServiceConnected();
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = null;
onServiceDisconnected();
}
}
protected void onServiceConnected() {
// for subclasses
}
protected void onServiceDisconnected() {
// for subclasses
}
protected SinchService.SinchServiceInterface getSinchServiceInterface() {
return mSinchServiceInterface;
}
public abstract void onPermissionGranted(int requestCode);
public void requestAppPermissions(final String[] requestedPermissions, final int stringId, final int requestCode) {
mErrorString.put(requestCode, stringId);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
boolean showRequestPermissions = false;
for (String permission : requestedPermissions) {
permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
showRequestPermissions = showRequestPermissions || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
}
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (showRequestPermissions) {
Snackbar.make(findViewById(android.R.id.content), stringId, Snackbar.LENGTH_INDEFINITE).setAction("GRANT", new View.OnClickListener() {
#Override
public void onClick(View view) {
ActivityCompat.requestPermissions(BaseActivity.this, requestedPermissions, requestCode);
}
}).show();
} else {
ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
}
} else {
onPermissionGranted(requestCode);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
for(int permission : grantResults){
permissionCheck = permissionCheck + permission;
}
if((grantResults.length > 0)&& PackageManager.PERMISSION_GRANTED == permissionCheck ){
onPermissionGranted(requestCode);
}else{
Snackbar.make(findViewById(android.R.id.content), mErrorString.get(requestCode), Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.setData(Uri.parse("package:"+ getPackageName()));
i.addCategory(Intent.CATEGORY_DEFAULT);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(i);
}
}).show();
}
}
}
Try this :
on your BaseActivity.java
instead of
protected void onServiceConnected() {
// for subclasses
}
put
protected void onServiceConnected(IBinder iBinder) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
}
and in your LoginActivity.java
Override the function onServiceConnected(IBinder iBinder)
#Override
protected void onServiceConnected(IBinder iBinder) {
super.onServiceConnected(iBinder);
getSinchServiceInterface().setStartListener(this);
}