I've defined a remote service in an Android Library project using AIDL. The service is supposed to simply increment an int. I try to bind to it from another project, an application using the library. The application's call to bindService(...) always returns false. What am I doing wrong?
The main activity of the application project:
MainActivity.java
package com.example.serviceusera;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.example.service.IncService;
import com.example.service.IncServiceConnection;
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private IncServiceConnection mConnection;
private int mCount = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
try {
mConnection = bindService();
} catch (RemoteException e) {
Log.e(TAG, "Failed to bind service", e);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private IncServiceConnection bindService() throws RemoteException {
IncServiceConnection connection = new IncServiceConnection();
Intent service = new Intent(IncService.class.getName());
boolean bound = bindService(service, connection, Context.BIND_AUTO_CREATE);
Log.d(TAG, "bindService() = " + bound);
if (bound) {
return connection;
} else {
throw new RemoteException("Failed to bind service");
}
}
private void init() {
// Show the current value of the counter
final EditText text = (EditText) findViewById(R.id.editText1);
text.setText(Integer.toString(mCount));
// Set button to increment counter
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
mCount = mConnection.inc(mCount);
text.setText(Integer.toString(mCount));
} catch (RemoteException e) {
Log.e(TAG, "Failed to use service", e);
}
}
});
}
}
The library project:
IIncService.aidl
package com.example.service;
interface IIncService {
int inc(in int i);
}
IncService.java
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class IncService extends Service {
private final IIncService.Stub mBinder = new IIncService.Stub() {
#Override
public int inc(int i) throws RemoteException {
return i + 1;
}
};
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
IncServiceConnection.java
package com.example.service;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
public class IncServiceConnection implements ServiceConnection {
private IIncService mService;
public int inc(int i) throws RemoteException {
return mService.inc(i);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IIncService.Stub.asInterface(service);
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}
I've added the service to the library's manifest:
AndroidManifest.xml
...
<application
...
<service
android:name="com.example.service.IncService"
android:process=":remote" >
</service>
</application>
...
and enabled mainfest merging in the application:
project.properties
...
manifestmerger.enabled=true
I've tried Your code using IntelliJ Idea 13 and have found the issue.
Firstly, I ensured that:
Library project is exported;
Application project has Enable manifest merging on under Android Compiler properties;
Using that configuration it didn't work and I've observed Unable to start service Intent.
The issue here is in incorrect Intent creation. Seems that class name You obtain by IncService.class.getName() doesn't specify the component completely (if logs checked it looks like so, because intent contains only class name, but package name is missed). So, to specify component properly, I've used another way:
final Intent service = new Intent(this, IncService.class);
And it worked fine.
Instead of binding Ibinder, try using binding with Handler. I have recently done an application the way you did and I could not figure out the fault. But working with Messager made things easier.
Instead of return binder object. It returns message obj. Here is the reference.
Source: Android Remote Bound Services
Related
I have a service type class which starts a timertask in onCreate method and I need to stop the timer from MainActivity when user press the button. I know I have to keep the reference to the timer in my service, but I cannot figure out how to do that and need some help, please!
please take a look at my code
package com.example.timertest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button.setOnClickListener(this);
startService(new Intent(this, TimeService.class));
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.button){
// i need here to call mTimer.cancel() in TimeService.class
//
}
}
}
// and here is the TimeService.java
package com.example.timertest;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimeService extends Service {
public Timer mTimer;
private Handler mHandler = new Handler();
long NOTIFY_INTERVAL = 60 * 1000 * 1; // 1 min
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
if (mTimer != null) {
mTimer.cancel();
} else {
mTimer = new Timer();
}
mTimer.scheduleAtFixedRate(new RefreshDataTimerTask(), 0, NOTIFY_INTERVAL);
}
class RefreshDataTimerTask extends TimerTask {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), getDateTime(), Toast.LENGTH_LONG).show();
}
});
}
private String getDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("[yyyy/MM/dd - HH:mm:ss]");
return sdf.format(new Date());
}
}
}
//and service registered in manifest
<service android:name=".TimeService"/>
I have tried to call the mTimer.cancel(), but got a null reference, because seems I have created a new instance of the service class.
This example shows a Toast with date and time each minute, i want when for example 15 seconds have past and i press the button, the timer to be canceled and to start counting 60 seconds again from the beginning. Inside this service i have many other things like notifications,channels, shared preferences and so on, so it will be good if i can operate only with the timer object.
Take a look on this API documentaion and this. There is example of how to bind service to activity after what you can get direct access to service methods.
After successful binding you can add method inside your service to stop the timer:
public void stopMyTimer() {
mTimer.cancel();
}
And call this method from Activity
This might not be best practice, but you can access public values by directly referring to the class:
TimeService.mTimer.cancel()
Which should work because Services function similarly to Singletons, in that each call of startService should be calling the same instance.
I want to create a notification for my android app. I have it working fine when I run it with the rest of my code inside a class, everything executes when I click a button and the notification works fine. However, because there is a lot of work to be done, the application is running slowly when I click the button. To help this, I have separated the notification part into a class of it's own and I am running it on a different thread.
I do not have a lot of experience with threads, or notifications for that matter and I would appreciate some help with this problem. Should I be separating the notification part into a class of it's own?
HomeActivity class is where the thread gets called to start, using the start() method when the button is clicked:
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import Model.Data;
public class HomeActivity extends FragmentActivity {
private com.atmlocator.hooper.kenneth.atmlocator.Notification n;
public void addListenerOnButton() {
locationSpinner = (Spinner) findViewById(R.id.spinner1);
options1Spinner = (Spinner) findViewById(R.id.spinner2);
options2Spinner = (Spinner) findViewById(R.id.spinner3);
Button locate = (Button) findViewById(R.id.locateBtn);
locate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Context context = getApplicationContext();
String text = "Loading...";
//call notification thread here
n.start();
//rest of code here...
}
}
}
}
and then the Notification class is:
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentActivity;
public class Notification extends FragmentActivity implements Runnable {
private Thread t;
private String name;
Context context;
Notification(String name, Context c)
{
this.name = name;
this.context = c;
}
public void run()
{
// Intent is triggered if the notification is selected
Intent intent = new Intent(context, HomeActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), intent, 0);
// Build notification
android.app.Notification not = new android.app.Notification.Builder(context)
.setContentTitle("Notification")
.setContentText("New email").setSmallIcon(R.drawable.atm)
.setContentIntent(pIntent).build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
not.flags |= android.app.Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, not);
}
public void start()
{
t = new Thread (this, name);
t.start ();
}
}
Should I be separating the notification part into a class of it's own?
There should not be any problem with this!
Also you should show your notification outside a thread.
You can use a handler instead to show notification instead of thread
like this :
}
....
// write this outside your code block
Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
showNotification();
}
};
// call it like this instead of thread start
mHandler.sendEmptyMessage(0);
check this link for more info : https://developer.android.com/training/multiple-threads/communicate-ui.html
This will virtually always work:
public static void toast(final String text, final int length, final Context context) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(context, text, length).show();
}
});
}
(Background: all I want is a unique and persistent Google Play identifier for the user. (even after uninstalls, or on different devices) This is the only reason I am doing this.)
I am using Cordova. This is my main activity.
Problem: the onConnected function never runs. I am able to sign in fine, however. (I can see the sign in window, the sign in circle, and everything else) but it just never runs.
NOTE: onConnectionFailed runs once, with a SIGN_IN_REQUIRED statusCode.
package com.myapp;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.games.Players;
import com.google.android.gms.games.Games;
import android.os.Bundle;
import org.apache.cordova.*;
import android.util.Log;
public class MyApp extends CordovaActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String LOGTAG = "GooglePlayServices";
// Client used to interact with Google APIs.
private GoogleApiClient mGoogleApiClient;
private CordovaActivity activity;
boolean mResolvingError;
#Override public void onCreate (Bundle savedInstanceState) {
activity = this;
super.onCreate (savedInstanceState);
super.init ();
mGoogleApiClient = new GoogleApiClient.Builder (this)
.addConnectionCallbacks (this)
.addOnConnectionFailedListener (this)
.addApi (Games.API)
.addScope(Games.SCOPE_GAMES)
.build ();
mGoogleApiClient.connect ();
super.loadUrl(Config.getStartUrl());
}
#Override public void onConnectionFailed (ConnectionResult result) {
if (mResolvingError) return;
if (!result.hasResolution()) {mResolvingError = true; return;}
Log.d (LOGTAG, result.toString());
try {
mResolvingError = true;
result.startResolutionForResult (this, result.getErrorCode());
} catch (SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect ();
}
}
#Override public void onConnected (Bundle connectionHint) {
// This never runs... this is the most critical part. I need the player ID!
String playerId = Games.Players.getCurrentPlayerId (mGoogleApiClient);
Log.w (LOGTAG, playerId);
}
// I saw this one with an #Override in others' code, but it won't compile if I add that.
public void onDisconnected () {}
protected void onStart () {super.onStart (); mGoogleApiClient.connect ();}
protected void onStop () {
super.onStop ();
if (mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect ();
}
protected void onActivityResult (int requestCode, int responseCode, Intent intent) {
if (!mGoogleApiClient.isConnecting()) mGoogleApiClient.connect ();
}
public void onConnectionSuspended (int cause) {mGoogleApiClient.connect ();}
}
"Your Oauth2 client CAN NOT be created from Google APIs Console, it MUST be created from the Google Play UI."
I'm very new to android. I want to create an application that turns off all sounds at the selected time. I created a service with some code and in Eclipse there's no errors, but when I press the button nothing happens. I can see in Application Manager that my program and the service SilentHours are running. Here's my code:
MainActivity.java
package com.example.silencecontrol;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
public final static String EXTRA_NAME = "sending silentHour value to service SilenceHours";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#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, menu);
return true;
}
public void setSilenceHours(View view) {
EditText editText1 = (EditText)findViewById(R.id.editText1);
TextView textView1 = (TextView)findViewById(R.id.textView1);
if(editText1.length() > 0) {
Intent intent = new Intent(this, SilentHours.class);
String editText1String = editText1.getText().toString();
int silentHour = Integer.parseInt(editText1String);
intent.putExtra(EXTRA_NAME, silentHour);
this.startService(intent);
} else {
textView1.setText("Please enter the silence hour. ");
}
}
}
SilentHours.java
package com.example.silencecontrol;
import java.util.Calendar;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.IBinder;
public class SilentHours extends Service {
public SilentHours() {
}
protected void onHandleIntent(Intent intent) {
int silentHour = Integer.parseInt(intent.getStringExtra(MainActivity.EXTRA_NAME));
Calendar calendar = Calendar.getInstance();
int currentTime = calendar.get(Calendar.HOUR_OF_DAY);
if(currentTime >= silentHour) {
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamVolume(AudioManager.STREAM_RING, 0, 0);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
And by the way I can't #Override the onHandleIntent method. If I put the #Override annotation I get error:
The method onHandleIntent(Intent) of type SilentHours must override or implement a supertype method.
Is that annotation necessary?
The method you are looking for is named onStartCommand, not onHandleIntent.
And no, it's not necessary to add this annotation to an overriden method, it's just a very good practice as you can get sure that you respected the signature of the super class.
Let you IDE help you when you code. Simply type "on" then ask for completion to see which method you can override.
I'm trying to change between activities in my Android app (2.1-update1), but it doesn't work.
Any suggestions?
The only thing that happens when I debug the app is that it stops on this part of the code in Instrumentation.java:
public void waitForIdle() {
synchronized (this) {
while (!mIdle) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
}
Eclipse says that it is in Thread 1 on
Instrumentation.checkStartActivityResult(int, Object) line: 1537. If I
resume the app, the next stop is in ZygoteInit.java trying to run
Throwable cause = ex.getCause(); ... Eclipse says
ZygoteInit$MethodAndArgsCaller.run() line: 864.
Here is the source code:
HappyHomes.java
package com.example.app;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class HappyHomes extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button login = (Button) findViewById(R.id.btnLogin);
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ProgressDialog laddRuta = ProgressDialog.show(HappyHomes.this, "",
"Loggar in, vänligen vänta...", true);
Intent myIntent = new Intent(view.getContext(), Kategorier.class);
myIntent.
startActivity(myIntent);
}
});
}
}
Kategorier.java
package com.example.app;
import android.app.Activity;
import android.os.Bundle;
public class Kategorier extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.kategorier);
}
}
Thanks for helping!
Make sure that Kategorier is registered in your AndroidManifest.xml file.
Change myIntent.startActivity(myIntent); to HappyHomes.this.startActivity(myIntent);
There is no any startActivity() method in Intent class . you must be doing wrong.
just write startActivity(myIntent)
All the Services, Broadcast Receivers and Activites must be declared in manifest file.