dual sim android phone which sim receive a call - android

I have an android application that detect the incoming calls, i need to improve this app to work on a duos mobile device.
so i create a broadcast receiver registered in manifest for actions: phone state changed and on my onReceive method i need to check which sim receive the call. This is my code
Protected void onReceive(Context c, Intent i)
{
Int whichSim = intent
getIntExtra("simSlot",-1);
// so this methof return 0 for sim 1 and 1 for sim2
If(whichSim==-1)
WhichSim=intent.getIntExtra("com.androie.phone.extra.slot",-1);
}
I run this app on a device 4.2
2 and its working normally but when i run it on a device 4
4.4 so this method does not work, i mean that which sim return -1 in all cases. Can anyone help me?

Android does not support dual sim phone until Android 5.1 and therefore any extension to support it may be device and version specific. The following is specific for the class of phones using a variant of MultiSimTelephonyManager to handle dual sims, including Samsung duos galaxy J1 under Android 4.4.4.
Basically this class of dual sim phones use two instances of MultiSimTelephonyManager, subclassed from the regular TelephonyManager and each responsible for one SIM slot, as an interface to control the phone.
One of the means to detect the incoming call is to use the PhoneStateListener class (instead of using a receiver) to detect change in phone states. The PhoneStateListener in these phones are modified (rather than subclassed) to include a mSubscription field which should indicate the SIM slot of the listener.
Both the MultiSimTelephonyManager class and the mSubscription field of PhoneStateListener are not in the standard SDK. To compile the app to use these interface, Java Reflection is needed.
The following code should roughly illustrate how you could get the sim slot information from incoming calls. I do not have the device to test, so the code may need refinements.
Set up the listener during your initialization stage -
try {
final Class<?> tmClass = Class.forName("android.telephony.MultiSimTelephonyManager");
// MultiSimTelephonyManager Class found
// getDefault() gets the manager instances for specific slots
Method methodDefault = tmClass.getDeclaredMethod("getDefault", int.class);
methodDefault.setAccessible(true);
try {
for (int slot = 0; slot < 2; slot++) {
MultiSimTelephonyManager telephonyManagerMultiSim = (MultiSimTelephonyManager)methodDefault.invoke(null, slot);
telephonyManagerMultiSim.listen(new MultiSimListener(slot), PhoneStateListener.LISTEN_CALL_STATE);
}
} catch (ArrayIndexOutOfBoundsException e) {
// (Not tested) the getDefault method might cause the exception if there is only 1 slot
}
} catch (ClassNotFoundException e) {
//
} catch (NoSuchMethodException e) {
//
} catch (IllegalAccessException e) {
//
} catch (InvocationTargetException e) {
//
} catch (ClassCastException e) {
//
}
Override PhoneStateListener and set the mSubscription field to listen to phone state changes:
public class MultiSimListener extends PhoneStateListener {
private Field subscriptionField;
private int simSlot = -1;
public MultiSimListener (int simSlot) {
super();
try {
// Get the protected field mSubscription of PhoneStateListener and set it
subscriptionField = this.getClass().getSuperclass().getDeclaredField("mSubscription");
subscriptionField.setAccessible(true);
subscriptionField.set(this, simSlot);
this.simSlot = simSlot;
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
}
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
// Handle the event here, with state, incomingNumber and simSlot
}
}
You will also need to create a file named MultiSimTelephonyManager.java at the [project]/src/android/telephony directory.
package android.telephony;
public interface MultiSimTelephonyManager {
public void listen(PhoneStateListener listener,int events);
}
You should probably do some error checking and especially check if the phone is the target model, when using the code.
Please be warned (again) that the above would not work in most other phones and other Android versions of the same phone.

This question suggests "com.android.phone.extra.slot" may also work on some phones. Maybe try both and use the one that didn't return -1?

Have you Try this Method :-
in this method you will get 0 for 1 Sim and for second sim you will get 1.
//Working code For 4.4 Phones KitKat
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
whichSIM = intent.getExtras().getInt("subscription");
if (whichSIM == 0) {
whichSIM = 1;
editor.putLong("ChooseSim", whichSIM);
editor.commit();
// Incoming call for SIM1
} else if (whichSIM == 1) {
whichSIM = 2;
editor.putLong("ChooseSim", whichSIM);
editor.commit();
}

Related

How do I programmatically dismiss a crash dialog?

I'm building a DPC (Device Policy Controller), and one of the issues I'm seeing is that while the Play Store and Play Services are being updated, the Google Contact Sync service crashes -- leaving the typical crash dialog on the screen. Since part of the idea of the initial set up process is to have as little user interaction as possible, how can I dismiss this dialog programmatically (since I seem to be pretty much guaranteed that this will happen)?
I've tried dismissing system dialogs...
ctx.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
... but that doesn't seem to do the trick.
Since this is a DPC, anything that requires device ownership/administration is fine.
edit: Usually I have no UI on screen at the time, so if one is necessary please do mention it. Also, preferably the solution should work on at least 6.0+, if not 4.0+.
Try to do it onWindowsFocusChanged method like this for example :
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) {
Intent ctx= new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(ctx);
}
}
I'm not sure about app crash Dialog but maybe it'll help you
AppErrorDialog can be dismissed by broadcasting ACTION_CLOSE_SYSTEM_DIALOGS if Android version is N.
ctx.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
However, AppErrorDialog won't be displayed if phone is locked.
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown
&& mLockScreenShown != LOCK_SCREEN_SHOWN;
} // ActivityManagerService
Please try this code.
try {
Class ActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
Class IActivityManager = Class.forName("android.app.IActivityManager");
Method getDefault = ActivityManagerNative.getMethod("getDefault", null);
Object am = IActivityManager.cast(getDefault.invoke(ActivityManagerNative, null));
Method closeSystemDialogs = am.getClass().getMethod("closeSystemDialogs", String.class);
closeSystemDialogs.invoke(am, "DPC close");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}

Repeating JmDNS device search

I want to scan for Bonjour devices (_http._tcp.local.) every 5 seconds and get a arraylist with the found devices (the names, so strings). I need to do it in a service (and in a background thread).
Now I'm making every 5 seconds a new instance of JmDNS (JmDNS.create()) and that leaks memory ;).
I think there must be a better way to do it, but I don't know it... Who can help me?
try {
final JmDNS jm;
ArrayList<String> foundDevices = new ArrayList<String>();
jm = JmDNS.create();
jm.addServiceListener("_http._tcp.local.", listener = new ServiceListener() {
#Override
public void serviceAdded(ServiceEvent event) {
jm.requestServiceInfo(event.getType(), event.getName(), 1);
}
#Override
public void serviceRemoved(ServiceEvent event) {
}
#Override
public void serviceResolved(ServiceEvent event) {
JSONObject obj = null;
ServiceInfo info = event.getInfo();
//Log.e("TCLogging", "RAW: " + info);
String Name = info.getName();
foundDevices.add(Name);
} catch (Exception e) {
Log.e("TCLogging", "Error");
}
}
});
ServiceInfo serviceInfo = ServiceInfo.create("_http._tcp.", "TC_" + android.os.Build.MODEL, 0, "AndroidApp");
jm.registerService(serviceInfo);
} catch (Exception e) {
Log.e("TCLogging", e.toString());
}
You could just call JmDNS.list(String type) every N seconds, which would return the ServiceInfo for the services it found. This first call will take time (you can control that via an overload of list(String type, long timeout)), default seems to be 6secs.
Something I didn't know about JmDNS was that you get notified when a device is discovered or disappears in the network. I wanted to scan every N seconds to see what devices are in the network. But it's much easier (and less resource intensive) to just wait until you get notified of any device changes.
The accepted answer did work for me to achieve the scan every N seconds, but it's not the most ideal way to do it!

Keeping Wifi-Direct Turned on AOSP devices

My friend and I are developing an app that streams synchronized music between android devices using wifi-direct. Our issue is that while the app works fairly well once phones are connected, it takes some doing to get phones to connect because on all AOSP devices it appears that wifi direct is only turned on upon entering the wifi direct menu (and immediately closed upon exiting). This makes in-application connection rather difficult. We were wondering if there is any way to turn on wifi direct from the code and keep it on (if anyone could refer us to a detailed description of how to do this using Reflection that would be fantastic).
Thanks! Here is our current code:
public class Reflector {
static Method turnOnICS;
static Method turnOnJB;
static Method turnOffICS;
public static void turnOnP2P(WifiP2pManager m, Channel c) {
//Log.v("button", "turnOnP2P");
if (android.os.Build.VERSION.SDK_INT == 14 || android.os.Build.VERSION.SDK_INT == 15) {
//Log.v("version", "Version is ICS");
try {
turnOnICS = WifiP2pManager.class.getDeclaredMethod("enableP2p",WifiP2pManager.Channel.class);
turnOnICS.setAccessible(true);
turnOnICS.invoke(m, c);
} catch (NoSuchMethodException e) {
Log.v("ics_error", "ICS enableP2p() not found");
} catch (Exception e) {
Log.v("ics_error", "turnOnICS invocation failure");
}
} else if (android.os.Build.VERSION.SDK_INT == 16 || android.os.Build.VERSION.SDK_INT == 17) {
//Log.v("version", "Version is JB");
try {
turnOnJB = NsdManager.class.getDeclaredMethod("setEnabled", boolean.class);
turnOnJB.setAccessible(true);
turnOnJB.invoke(NsdManager.class, true);
//must feed it an nsdmanager, but none exists in wifidirectactivity
Log.v("nsd", "problem");
} catch (NoSuchMethodException e) {
Log.v("jb_error", "JB setEnabled() not found");
} catch (Exception e) {
Log.v("jb_error", "turnOnJB invocation failure");
e.printStackTrace();
}
}
}
public static void turnOffP2P(WifiP2pManager m, Channel c) {
//Log.v("button", "turnOffP2P");
if (android.os.Build.VERSION.SDK_INT == 14 || android.os.Build.VERSION.SDK_INT == 15) {
//Log.v("version", "Version is ICS");
try {
turnOffICS = WifiP2pManager.class.getDeclaredMethod("disableP2p", WifiP2pManager.Channel.class);
turnOffICS.setAccessible(true);
turnOffICS.invoke(m, c);
} catch (NoSuchMethodException e) {
Log.v("ics_error", "ICS disableP2P() not found");
} catch (Exception e) {
Log.v("ics_error", "turnOffICS invocation failure");
}
}
}
public static void printAll(){
Method[] list = WifiP2pManager.class.getDeclaredMethods();
for(Method m : list){
Log.v("tag",m.getName());
}
}
}
Thank you for asking this question... it's been a question we've been wrestling with as we add WiFi Direct features to our app.
After looking through the settings on several phones from different manufacturers, and reading pages like this and this (which admittedly are not very precise in the details, but it's the best we could find), we've come to the conclusion that there's no need to separately turn on WiFi Direct per se: it's enabled whenever WiFi is enabled. So, at most, your app would need to turn on WiFi.
However, WiFi Direct scanning (and visibility to being scanned) is what you initiate by going to the WiFi Direct settings page.
Leaving that page may stop the scanning (though 3rd-party apps can and do initiate their own scanning), but should not disable WiFi Direct. That would make no sense at all... as you say, that would make it difficult (impossible) for apps to use WiFi Direct, but apps do use it successfully. What did you see that made it seem like WiFi Direct was being disabled when you left that settings page?

Android to detect possibilities of no data connection

I have an application which needs to communicate with the server at some random interval through GPRS or EDGE.. But there are few possibilities at which internet cannot be accessed by the application when the user is in call or deactivated etc. At these time i have two scenario's recoverable and non recoverable.
Recoverable scenarios
On phone call ( User will hang up and data connection will be active
again)
No Signal (Sometimes signal may drop and the phone will get
signal again)
Non Recoverable Scenarios
Flight mode
Deactivating Data Connection
When its recoverable i can try again for the connection after some defined interval. And during non recoverable i have to alert user. For instance if the user deactivates data connection or enables flight mode i have to alert the user.
EDIT:I can able to detect flight mode through one of the intents. I couldn't able to find for others.
The below code return if valid connections are available
public boolean isConnectionsAvailable() {
boolean lRet = false;
try{
ConnectivityManager conMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info= conMgr.getActiveNetworkInfo();
if(info != null && info.isConnected()) {
lRet = true ;
}else{
lRet = false ;
}
}catch (Exception e) {
Log.d("Connection Error", e.toString());
lRet = false ;
}
return lRet;
}
After this, if you have low signal strength then you make a HTTP request by setting relevant time out to it. If timeout happened give relevant alert msg to user as below
public void serverCall(String pURL){
if (isConnectionsAvailable()){
// Call server by setting proper timeout
}
}
Edit:
To check the Airplane mode status:
private static boolean isAirplaneModeOn(Context context) {
return Settings.System.getInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) != 0;
}
You could try surrounding your method with try and catch. If the method fails because it cannot connect to your server for whatever reason you could call postDelayed from a Handler and re-run your method again in a pre-determined length of time.
Handler mHandler = new Handler();
Runnable yourMethodRunnable = new Runnable(){
#Override
public void run(){
yourMethod();
}
};
private void yourMethod(){
try{
// talk to server
} catch (InCallException e) {
mHandler.postDelayed(yourMethodRunnable, delay)
} catch (NoSignalException e) {
// etc...
} catch (OtherException e) {
// etc...
}
}
The exceptions are just examples, and likely don't exist, get the exceptions that you want to catch either from the Android Developer Docs, or by looking at the output from LogCat when you re-enact each time that the connection to the server would fail.

How can I enable NFC reader via API?

There is any way I can enable Android NFC reader using API?
So apparently there is no way to enable the NFC from the API, even though Google does so within their source code (see below).
If you look at a line from the API for NfcAdapter.isEnabled():
Return true if this NFC Adapter has
any features enabled.
Application may use this as a helper
to suggest that the user should turn
on NFC in Settings.
If this method returns false, the NFC
hardware is guaranteed not to generate
or respond to any NFC transactions.
It looks like there is no way to do it within the API. Bummer. Your best bet is a dialog to inform the user they need to enable it in the settings, and perhaps launch a settings intent.
EDIT: The following is from the source, but it looks like they didn't allow the user to implement the methods in the API (I'm confused about this).
I found this from the android source code to help enable and disable the adapter.
Relevant source:
public boolean onPreferenceChange(Preference preference,
Object value) {
// Turn NFC on/off
final boolean desiredState = (Boolean) value;
mCheckbox.setEnabled(false);
// Start async update of the NFC adapter state, as the API is
// unfortunately blocking...
new Thread("toggleNFC") {
public void run() {
Log.d(TAG, "Setting NFC enabled state to: "
+ desiredState);
boolean success = false;
if (desiredState) {
success = mNfcAdapter.enable();
} else {
success = mNfcAdapter.disable();
}
if (success) {
Log.d(TAG,
"Successfully changed NFC enabled state to "
+ desiredState);
mHandler.post(new Runnable() {
public void run() {
handleNfcStateChanged(desiredState);
}
});
} else {
Log.w(TAG, "Error setting NFC enabled state to "
+ desiredState);
mHandler.post(new Runnable() {
public void run() {
mCheckbox.setEnabled(true);
mCheckbox
.setSummary(R.string.nfc_toggle_error);
}
});
}
}
}.start();
return false;
}
I got it working through reflection
This code works on API 15, haven't checked it against other verions yet
public boolean changeNfcEnabled(Context context, boolean enabled) {
// Turn NFC on/off
final boolean desiredState = enabled;
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
if (mNfcAdapter == null) {
// NFC is not supported
return false;
}
new Thread("toggleNFC") {
public void run() {
Log.d(TAG, "Setting NFC enabled state to: " + desiredState);
boolean success = false;
Class<?> NfcManagerClass;
Method setNfcEnabled, setNfcDisabled;
boolean Nfc;
if (desiredState) {
try {
NfcManagerClass = Class.forName(mNfcAdapter.getClass().getName());
setNfcEnabled = NfcManagerClass.getDeclaredMethod("enable");
setNfcEnabled.setAccessible(true);
Nfc = (Boolean) setNfcEnabled.invoke(mNfcAdapter);
success = Nfc;
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
} else {
try {
NfcManagerClass = Class.forName(mNfcAdapter.getClass().getName());
setNfcDisabled = NfcManagerClass.getDeclaredMethod("disable");
setNfcDisabled.setAccessible(true);
Nfc = (Boolean) setNfcDisabled.invoke(mNfcAdapter);
success = Nfc;
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
if (success) {
Log.d(TAG, "Successfully changed NFC enabled state to "+ desiredState);
} else {
Log.w(TAG, "Error setting NFC enabled state to "+ desiredState);
}
}
}.start();
return false;
}//end method
This requires 2 permissions though, put them in the manifest:
<!-- change NFC status toggle -->
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
The NFC button's state switches accordingly when the code is used, so there are no issues when doing it manually in the seetings menu.
If you can see the NfcService Application Source Code, there is a Interface file INfcAdapter.aidl. In the file two API's are there namely "boolean enable()" and "boolean disable()". You can directly use this API's to enable and disable NfcService through an android application. But the trick over here is that you can not compile the code using SDK provided by the Android. You have to compile the application using the a makefile. I have successfully build a application.
I hope this forum would be help you to resolve this issue as well to get the clear understanding on the NFC power on/off API barries.
http://ranjithdroid.blogspot.com/2015/11/turn-onoff-android-nfc-by.html

Categories

Resources