In one of my app i wanted to check the service state of the android phone
before sending sms. I have used the following code to do that
//check service
ServiceState pstate = new ServiceState();
if(pstate.getState() != ServiceState.STATE_IN_SERVICE)
{
Log.v(TAG,"service state" +pstate.getState());
Toast.makeText(Myactivity.this, "error string", 2000).show();
return;
}
But the code always returns with OUT_OF_SERVICE ( value of 1 in +pstate.getState)
Please let me know what is the reliable way to check whether the phone is in STATE_IN_SERVICE or not?
This code was checked in FROYO version.
Not a satisfactory answer really, but I've had he same problem and kept wasting time, but it would just not work on my FROYO version aswell.
But using the TelephonyManager and PhoneStateListener this worked perfectly fine. For your case I'd suggest using a wrapper instead of instantiating the ServiceState directly, ie
//declare current state
ServiceState myServiceState = new ServiceState();
PhoneStateListener listener = null; // not sure if this is needed really..
// nifty getter
public ServiceState getServiceState(){ return myServiceState; }
//setup listener (eg. in onCreate)
TelephonyManager tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
listener = new PhoneStateListener() {
#Override
public void onServiceStateChanged(ServiceState serviceState){
myServiceState = serviceState;
}
};
tm.listen(listener,PhoneStateListener.LISTEN_SERVICE_STATE);
// to be called when destroying your context
public void unregisterListener(){
// something like..
tm.listen(listener,PhoneStateListener.LISTEN_NONE);
}
//check service
ServiceState pstate = getServiceState();
if(pstate.getState() != ServiceState.STATE_IN_SERVICE)
{
Log.v(TAG,"service state" +pstate.getState());
Toast.makeText(Myactivity.this, "error string", 2000).show();
return;
}
A lazier solution would be moving the listener-setup into the getter and registering it only when actually called, if ever, and only saving if the service is available. ie
//declaration
boolean isAvailable = false;
PhoneStateListener listener = null;
// more nifty getter
public boolean isServiceAvailable(){
if (listener == null){
//setup listener if not yet done
TelephonyManager tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
listener = new PhoneStateListener() {
#Override
public void onServiceStateChanged(ServiceState serviceState){
isAvailable = serviceState.getState() == ServiceState.STATE_IN_SERVICE;
}
};
tm.listen(listener,PhoneStateListener.LISTEN_SERVICE_STATE);
}
return isAvailable;
}
// to be called when destroying your context
public void unregisterListener(){
// something like..
if (lister != null){
tm.listen(listener,PhoneStateListener.LISTEN_NONE);
}
}
//check service
if(! isServiceAvailable())
{
Log.v(TAG,"service state" +pstate.getState());
Toast.makeText(Myactivity.this, "error string", 2000).show();
return;
}
But be aware, that would require the listener to get called immediately upon registration, otherwise you'll end up with arbitrary results - so make sure to check that.
Related
I'd like to ask you for some help with Android TextToSpeech feature.
Basically, I'd like to develop a simple AI which speaks, asking a question then waits for an answer, and at last, based on answer asks another question and so on, until user pronounces a keyword which stops everything.
Now I know TextToSpeech has to be initialized before using speak method, and I'm trying to take this into account by using onActivityResult method.
Below some code:
Activity class:
public class MainActivity extends AppCompatActivity implements OnInitListener, Button.OnClickListener{
Button sayHello;
TextView textView;
private static final int CHECK_DATA = 0;
private static final Locale defaultLocale = Locale.UK; // British English
private static final String TAG = "TTS";
private TextToSpeech tts;
private boolean isInit = false;
sayIt Method: used to speak:
public void sayIt(String text, boolean flushQ){
if(isInit){
if(flushQ){
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(text, TextToSpeech.QUEUE_ADD, null, null);
}
} else {
Log.i(TAG, "Failure: TTS instance not properly initialized");
}
}
TextToSpeech Listener:
#Override
public void onInit(int status){
if(status == TextToSpeech.SUCCESS){
isInit = true;
// Enable input text field and speak button now that we are initialized
sayHello.setEnabled(true);
// Set to a language locale after checking availability
Log.i(TAG, "available="+tts.isLanguageAvailable(Locale.UK));
tts.setLanguage(defaultLocale);
// Examples of voice controls. Set to defaults of 1.0.
tts.setPitch(1.0F);
tts.setSpeechRate(1.0F);
// Issue a greeting and instructions in the default language
tts.speak("Initialized!", TextToSpeech.QUEUE_FLUSH, null, Integer.toString(12));
} else {
isInit = false;
Log.i(TAG, "Failure: TTS instance not properly initialized");
}
}
Button Listener:
#Override
public void onClick(View v){
if(isInit)
sayIt("You clicked!", true);
}
onActivityResult Method:
// Create the TTS instance if TextToSpeech language data are installed on device. If not
// installed, attempt to install it on the device.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHECK_DATA) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// Success, so create the TTS instance. But can't use it to speak until
// the onInit(status) callback defined below runs, indicating initialization.
Log.i(TAG, "Success, let's talk");
tts = new TextToSpeech(this, this);
// Use static Locales method to list available locales on device
Locale[] locales = Locale.getAvailableLocales();
Log.i(TAG,"Locales Available on Device:");
for(int i=0; i<locales.length; i++){
String temp = "Locale "+i+": "+locales[i]+" Language="
+locales[i].getDisplayLanguage();
if(locales[i].getDisplayCountry() != "") {
temp += " Country="+locales[i].getDisplayCountry();
}
Log.i(TAG, temp);
}
} else {
// missing data, so install it on the device
Log.i(TAG, "Missing Data; Install it");
Intent installIntent = new Intent();
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
And, at last, onCreate Method:
#Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
setContentView(R.layout.activity_main);
sayHello = findViewById(R.id.sayBtn);
textView = findViewById(R.id.textView);
sayHello.setEnabled(false);
sayHello.setOnClickListener(this);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, CHECK_DATA);
/* THIS SPEAK DOES NOT WORK! */
sayIt("Speech from method!", true);
}
Issue is: Button successfully gets enabled when onInit method initialises TextToSpeech and successfully pronounces text.
My goal is to make the Activity speak from onCreate method, since at the moment it only works from onInit and onClick listeners, bot not in onCreate, even if I check for tts initialization using onActivityResult.
Basically I want the TextToSpeech to speak with no Buttons involved.
I know very similar questions were already posted, but none solved my problem. Have some idea?
Hope I've been clear, Thank you!
UPDATE: Log shows ERROR detected occurs in else branch of onInit method, where Log.i(TAG, "Failure: TTS instance not properly initialized"); line is.
SOLUTION:
The only thing to do here is to wait a little time in order to let TextToSpeech initialize for good.
A good way seems to be by using a delayed Handler as follows:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Waiting for RobotTextToSpeech initialization for 1500ms
rtts.speak("This speak will work!");
rtts.speak("This other speak will work too!");
}
}, 1500);
}
By doing this, looks like TextToSpeech works well even in onCreate method, we just have to wait little time.
Hope this can help.
I'm building an app that hooks on the stock Dialer (Marshmallow API). My goal is to get incoming and place outgoing calls, while getting a handle on the Connection objects to manipulate the Connection's methods.
I have registered PhoneAccount with the CAPABILITY_CALL_PROVIDER.
PhoneAccount.Builder builder = new PhoneAccount.Builder(phoneAccountHandle, "CustomAccount");
builder.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER);
PhoneAccount phoneAccount = builder.build();
telecomManager.registerPhoneAccount(phoneAccount);
My account is visible inside the stock Dialer app (Settings-> Calls-> Calling Accounts) and I have enabled it.
I have a Service that monitors Phone State and on CALL_STATE_RINGING it calls TelecomManager's addNewIncomingCall() method.
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
Toast.makeText(getApplicationContext(), "Phone Is Ringing",
Toast.LENGTH_SHORT).show();
Bundle extras = new Bundle();
Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, incomingNumber, null);
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri);
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
telecomManager.addNewIncomingCall(phoneAccountHandle, extras);
}
if (state == TelephonyManager.CALL_STATE_OFFHOOK) {.......}
...
}
My custom Connection Service:
#Override
public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
Toast.makeText(getApplicationContext(), "onCreateIncomingConnection called", Toast.LENGTH_SHORT).show();
Connection incomingCallCannection = createConnection(request);
incomingCallCannection.setRinging();
return incomingCallCannection;
}
#Override
public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
Toast.makeText(getApplicationContext(), "onCreateOutgoingConnection called", Toast.LENGTH_SHORT).show();
Connection outgoingCallConnection = createConnection(request);
outgoingCallConnection.setDialing();
return outgoingCallConnection;
}
private Connection createConnection(ConnectionRequest request) {
mConnection = new Connection() {
#Override
public void onStateChanged(int state) {
super.onStateChanged(state);
}
#Override
public void onDisconnect() {
super.onDisconnect();
mConnection.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
mConnectionsAvailableForConference.clear();
mConnection.destroy();
}
#Override
public void onSeparate() {
super.onSeparate();
}
#Override
public void onAbort() {
super.onAbort();
mConnection.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
mConnection.destroy();
}
#Override
public void onHold() {
super.onHold();
}
#Override
public void onAnswer() {
super.onAnswer();
mConnection.setActive();
}
#Override
public void onReject() {
super.onReject();
mConnection.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
mConnection.destroy();
}
};
mConnection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
mConnection.setExtras(request.getExtras());
return mConnection;
}
Now, both ConnectionService's callback methods get called on incoming and outgoing calls respectively. The problem is, when I go to the Dialer and place an outgoing call (using my PhoneAccount) I get the dialing screen (inCallUI ?), with the right caller info being shown (contact name, tel # etc..), but the line doesn't ring in my earpiece and the call is not established (the telephone number that should be receiving the call doesn't ring).
I tried returning super.onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) in the callback instead of creating my own Connection object, and I get the same behavior.
TLDR: my app communicates with the Dialer, is able to place a call and show the dialing screen, but the phone line doesn't ring and nothing happens.
I have been on this for days finding a solution. But after going through the documentation over again it clearly stated that placing outgoing call with a custom PhoneAccount does not use the phone sim service to make the call, it the app that will handle all the call operation by itself.
CAPABILITY_CALL_PROVIDER: Flag indicating that this PhoneAccount can make phone calls in place of traditional SIM-based telephony
calls.
if you need to transfer data during outgoing call you can use the Bundle to send info to the default call app.
you can read more on the documentation here.
https://developer.android.com/reference/android/telecom/PhoneAccount
https://developer.android.com/guide/topics/connectivity/telecom/selfManaged#outgoing
Can anybody please tell me? I am making a sample and want to detect miss call on a particular number. Suppose I opened the dialler with the number (0123456789) and when call on this number then detect missed call on this number. how can I do that. Please help ..
Check the flowing code ->
In your broadcast receiver check that if the call is received or not. Then you can find the call status.
public class CallBroadcast extends BroadcastReceiver {
private static boolean isMissedCall;
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
String state = bundle.getString(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
// Ringing
isMissedCall = true;
} else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
// Call Received
isMissedCall = false;
} else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
// Call Drop
// If don't receive call then it will be missed call
if(isMissedCall){
// do your code for missed call
}
}
}
}catch (Exception e){e.printStackTrace();}
}
}
I made an app whos purpose is to download and set wallpaper in set intervals.
User can choose to do that only when connected to wifi or not.
Relevant code:
mWallpaperButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mSwitchWifi.isChecked()) {
mConnectivity = mConnectionDetector.isConnectedToWifi();
} else {
mConnectivity = mConnectionDetector.isConnectedToInternet();
}
if (mConnectivity) {
my code here
}
The code above works fine for setting the wallpaper the first time.
My problem is, I need the Service to check if the user wants to update wallpaper only over WIFI before doing so. At the moment, wallpaper is updated regardless of mSwitchWifi state. (which is bad, because it can use mobile data and user sometimes doesn't want that.)
I tried running similar Switch code in Service but I can't because it must be called in a UI Thread.
I also tried couple of workarounds and Intent.putExtra but I get exception:
NullPointerException: Attempt to invoke virtual method on a null object reference
Any idea how to check network state in service?
My service code atm:
public static class Service extends IntentService {
public Service() {
super("wallpaperchanger-download");
}
#Override
protected void onHandleIntent(Intent intent) {
if (url == null) {
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
String getUrl = sharedPreferences.getString(pref_urlKey, null);
if (getUrl != null) {
url = getUrl;
}
}
wm = WallpaperManager.getInstance(this);
try {
InputStream input = new URL(url).openStream();
Log.v(TAG, url);
wm.setStream(input);
input.close();
} catch (Exception e) {
e.printStackTrace();
}
loading = false;
Log.v(TAG, "Service Running Url " + url);
}
}
If you question is how to access the user selection inside a service/runnable/thread then you can use shared preferences to achieve this. So in your case when the user selects the choice for the first time you want to do something like this:
if(mSwitchWifi.isChecked()) { // i guess this is no wifi
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
Editor editor = sharedPeredences.edit()
editor.putBoolean("isWifi", false)
} else { // guessing this is wifi
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
Editor editor = sharedPeredences.edit()
editor.putBoolean("isWifi", true)
}
This is this code to check if it is true or false:
mWallpaperButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Boolean isWifi = isWifi()
if (!isWifi) { // i guess this is if not wifi
mConnectivity = mConnectionDetector.isConnectedToWifi();
} else if (isWifi) { // guessing this is wifi
mConnectivity = mConnectionDetector.isConnectedToInternet();
}
}
}
public Boolean isWifi() { // you can call this inside your service
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
Boolean wifiState = sharedPreferences.getBoolean("isWifi", true)
return wifiState;
}
This is just a very rough implementation to give an idea of how you can do it, you can improve this many ways. For example you could put the if statement thats inside the onClickListener in the isWifi() function and just call isWifi() inside your runnable/thread...
you can set list preferences to auto update functions based on the network ....
You can create separate class to check the connectivity and from that class you can select the preferences like auto update only on wifi or when connected to network or do not auto update ....
I need to get access to com.android.internal.telephony.Call.
doing so:
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones (this);
// Get the default phone
Phone phone = PhoneFactory.getDefaultPhone ();
CallManager mCM = CallManager.getInstance ();
mCM.registerPhone (phone);
Call call = mCM.getFirstActiveBgCall();
but does not extend to initialize the framework.
Help me to initialize Call.
I need to read the state of the call like:
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING.
You need to make use of PhoneStateListener
It will provide you the facility to have your application listen for different state of a phone call. You will need to put <uses-permission android:name="android.permission.READ_PHONE_STATE"/> in your manifest file
You can but there is a critical requirement: the application must be signed at system level, meaning you are the manufacturer.
Here is how you write a Service that will broadcast an intent for every change in the foreground call state.
/*
* This implementation uses the com.android.internal.telephony package: you have
* to extract the framework classes .jar file from the platform (or the
* emulator) to compile this code. Also, add the jar file to the external
* libraries in the Java Build Path/libraries of the android project. </p>
*
* The jar file must match the android version you are building the application
* for. Because this implementation is using the internal packages it cannot be
* guaranteed to operate on later versions of android.
*/
public class CallStateNotificationService extends Service {
private static final String LOG_TAG = CallStateNotificationService.class.getSimpleName();
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if (msg.what == 101) {
CallManager callManager = CallManager.getInstance();
Call.State state = callManager.getActiveFgCallState();
Intent intent = new Intent(PhoneIntents.ACTION_PRECISE_CALL_STATE);
intent.putExtra(PhoneIntents.PRECISE_CALL_STATE, state.name());
Context context = getApplicationContext();
context.sendBroadcast(intent);
}
}
};
#Override
public void onCreate() {
super.onCreate();
try {
CallManager callManager = CallManager.getInstance();
if (callManager != null) {
callManager.registerForPreciseCallStateChanged(mHandler, 101, null);
} else {
Log.w(LOG_TAG, "Can't resolve CallManager reference"); //$NON-NLS-1$
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
super.onDestroy();
CallManager callManager = CallManager.getInstance();
if (callManager != null) {
callManager.unregisterForPreciseCallStateChanged(mHandler);
} else {
Log.w(LOG_TAG, "Can't resolve CallManager reference"); //$NON-NLS-1$
}
}
And here is the definition of the custom broadcasted intents.
/** Intent action and extra argument names for CallStateNotificationService */
public final class PhoneIntents {
public static final String ACTION_PRECISE_CALL_STATE = "com.myorg.myapp.CALL_STATE";
public static final String PRECISE_CALL_STATE = "precise_call_state";
}
To have this code compile and link, you of course need to either build the program as part of the android distribution itself or import the class-framework by a method explained elsewhere on the Internet.
All of this is currently in an app under production.