I'm working on a system app(signed with os signature),
I need to programmatically switch data between 2 SIMs. After spend a lot of time reading Settings app source code of AOSP (here)
I found that when you manually click on switch data in Settings app, this code executes:
(you can find it here)
public static void setMobileDataEnabled(Context context, int subId, boolean enabled,
boolean disableOtherSubscriptions) {
final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
.createForSubscriptionId(subId);
final SubscriptionManager subscriptionManager = context.getSystemService(
SubscriptionManager.class);
telephonyManager.setDataEnabled(enabled);
if (disableOtherSubscriptions) {
final List<SubscriptionInfo> subInfoList =
subscriptionManager.getActiveSubscriptionInfoList();
if (subInfoList != null) {
for (SubscriptionInfo subInfo : subInfoList) {
// We never disable mobile data for opportunistic subscriptions.
if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) {
context.getSystemService(TelephonyManager.class).createForSubscriptionId(
subInfo.getSubscriptionId()).setDataEnabled(false);
}
}
}
}
}
But when I tried this code, it just turned off the current data without turning on data on other SIM! I can also see in phone Settings app that data had been changed to the other SIM, and it's UI switch is on, but actually there is no network data(It seems like just UI had been changed, but still the default data remain on previous SIM card)
It seems I've missed something. Looking forward for your helps. Thanks!
Related
I want to write Api for getdataroaming method which is already there in Aosp.
Just now I have written code like this.
ContentResolver cr=mPhone.getContext().getContentResolver();
if (Settings.Secure.getInt(cr.getContentResolver(),Settings.Secure.DATA_ROAMING) == 1) {
//Data Roaming Enabled
flag = true;
} else {
// Data Roaming Disabled
flag = false;
}
how to get the phone object in separate java file.
if I used the context.
From where i will get this context?
How to check if any system dialog (like the one below or USSD) is displayed in Android ?
Programmatic way or cmd root way?
Any variants.
You can theoretically do this using the AccessibilityService, but it is rather complicated and may or may not work on different devices. Users will need to manually enable accessibility features for your application. You can get callbacks from Android whenever any window is opened and you can then interrogate the window to determine if it has specific text in it or belongs to a specific package, etc. This is a "brute force" approach, but it can be useful in some situations.
A system dialog is an activity. You can detect it by the top activity class name using ActivityManager.
final ActivityManager manager = (ActivityManager) context
.getSystemService(Activity.ACTIVITY_SERVICE);
In devices with API Level less than 23 (M):
final List<ActivityManager.RunningTaskInfo> runningTasks = manager.getRunningTasks(1);
final ComponentName componentName = runningTasks.get(0).topActivity;
final String className = componentName.getClassName();
if (className.equals("YOUR_EXPECTED_ACTIVITY_CLASS_NAME")) {
// do something
}
In newer devices:
final List<ActivityManager.AppTask> appTasks = manager.getAppTasks();
final ComponentName componentName = appTasks.get(0).getTaskInfo().topActivity;
final String className = componentName.getClassName();
if (className.equals("YOUR_EXPECTED_ACTIVITY_CLASS_NAME")) {
// do something
}
Or in this case, you can check if the device is in airplane mode before starting the activity:
private boolean isAirplaneModeOn(final Context context) {
final int airplaneMode = Settings.System.getInt(
context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON,
0
);
return airplaneMode != 0;
}
...
if (!isAirplaneModeOn(this)) {
// do something
}
Your question made me think of a solution in use by the permissions management in Android 6+. Have you ever seen the error message if a Toast or system alert dialog opens up when trying to set permissions?
Android "Screen Overlay Detected" message if user is trying to grant a permission when a notification is showing
The way they did it is by overriding the dispatchTouchEvent method in Activity. This can check if anything is 'in the way' intercepting touch events. You can use your special Activity as a base class for any Activity in your app that you wish to detect any overlays on it.
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
mObscured = (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0;
return super.dispatchTouchEvent(event);
}
Add a public method to check at any given time if your activity is obscured
public boolean isObscured() {
return mObscured;
}
You should be careful - as it's not clear from the question - if a second Activity from a system or privileged app is at the front of the stack then your own activity will no longer be receiving touch events. This is to capture the fragments, toasts, floating widgets and other items that may share the view hierarchy.
I'm implementing a Service (but currently i'm testing the code in an Activity) that detects SIM swap/insertion/removal. When SIM change is detected, i plan to announce the event to other parts of app and store new MSISDN for later use (or clear the stored one if no sim is present).
I used to listen to android.intent.action.SIM_STATE_CHANGED broadcast, but as it's not supported by public SDK API, I've decided to switch to TelehoneManager and PhoneStateListener, listening to service state changes (as described here and here).
Unfortuntely, it seems to be unreliable. Sometimes, after swapping the SIM to a new one, and pulling it out and then inserting back again, IN_SERVICE event is not fired (the phone shows mobile network connection being active, Android Settings show service state as 'In service', but listener does not receive the event).
Also, I've noticed that after swapping to other SIM (without device restart), almost every time when I pull it out and insert back (to fire the events) and listener receives the IN_SERVICE event, SIM state (obtained by TelephonyManager.getSimState()) is not yet SIM_STATE_READY, and I can't obtain the MSISDN (using TelephonyManager.getLine1Number()). A short while after this, I could see MSISDN number in Android Settings, so it's readable, just not yet available when the event comes.
When removing and inserting back the same SIM that was in the phone when the app run for the first time, MSISDN is almost always available when IN_SERVICE event comes.
I've tested this on a few devices (all are Android 5.1) and SIM cards, the behavior is same so it's rather not faulty SIM nor device.
Of course, i have included READ_PHONE_STATE permission in a manifest.
example code:
public static void testListener(Context context) {
TelephonyManager telephonyMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener listener = new PhoneStateListener(){
#Override
public void onServiceStateChanged(ServiceState serviceState) {
super.onServiceStateChanged(serviceState);
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//StorageUtil is a simple helper class to store/load values from SharedPreferences
StorageUtil storageUtil = new StorageUtil(context);
String oldSim = storageUtil.getStringValue(LAST_SIM_STATE_KEY);
String newSim = getMsisdn(context);
String oldImsi = storageUtil.getStringValue(LAST_SIM_IMSI_KEY);
String newImsi = getImsi(context);
Log.d("SIM", MessageFormat.format("{0} === {1} -> {2} [{3} -> {4}] {5}", decodeServiceState(serviceState.getState()), oldSim, newSim, oldImsi, newImsi, tm.getSimState()));
storageUtil.storeValue(LAST_SIM_STATE_KEY, newSim);
storageUtil.storeValue(LAST_SIM_IMSI_KEY, newImsi);
}
};
telephonyMgr.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
}
public static String getImsi(Context context) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getSubscriberId();
}
public static String getMsisdn(Context context) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getLine1Number();
}
static private String decodeServiceState(int state) {
switch(state) {
case 0:
return "IN_SERVICE ";
case 1:
return "OUT_OF_SERVICE";
case 2:
return "EMERGENCY_ONLY";
case 3:
return "POWER_OFF ";
}
return "";
}
example logs (with comments) showing problem occurence:
http://pastebin.com/wUdGH0Hu
Is there a way to fix those issues ? They seem to be pretty random and not easy to reproduce, but they keep happening and ruining the day.
Or maybe I shouldn't use the PhoneStateListener at all ?
How to pair a Bluetooth Low Energy(BLE) device with Android to read encrypted data.
Using the information in the Android BLE page, I am able to discover the device, connect to it, discover services and read un-encrypted characteristics.
When I try to read an encrypted characteristic (one that will cause iOS to show a popup asking to pair and then complete the read) I am getting an error code 5, which corresponds to Insufficient Authentication.
I am not sure how to get the device paired or how to provide the authentication information for the read to complete.
I toyed with BluetoothGattCharacteristics by trying to add descriptors, but that did not work either.
Any help is appreciated!
When you get the GATT_INSUFFICIENT_AUTHENTICATION error, the system starts the bonding process for you. In the example below I'm trying to enable notifications and indications on glucose monitor. First I'm enabling the notifications on Glucose Measurement characteristic which can cause the error to appear.
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementNotificationEnabled();
if (mGlucoseMeasurementContextCharacteristic != null) {
enableGlucoseMeasurementContextNotification(gatt);
} else {
enableRecordAccessControlPointIndication(gatt);
}
}
if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementContextNotificationEnabled();
enableRecordAccessControlPointIndication(gatt);
}
if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onRecordAccessControlPointIndicationsEnabled();
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
// this is where the tricky part comes
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
mCallbacks.onBondingRequired();
// I'm starting the Broadcast Receiver that will listen for bonding process changes
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mContext.registerReceiver(mBondingBroadcastReceiver, filter);
} else {
// this situation happens when you try to connect for the second time to already bonded device
// it should never happen, in my opinion
Logger.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
// I don't know what to do here
// This error was found on Nexus 7 with KRT16S build of Andorid 4.4. It does not appear on Samsung S4 with Andorid 4.3.
}
} else {
mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status);
}
};
Where the mBondingBroadcastReceiver is:
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
Logger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
if (bondState == BluetoothDevice.BOND_BONDED) {
// Continue to do what you've started before
enableGlucoseMeasurementNotification(mBluetoothGatt);
mContext.unregisterReceiver(this);
mCallbacks.onBonded();
}
}
};
Remember to unregister the broadcast receiver when exiting the activity. It may have not been unregistered by the receicver itself.
You might need to check the Kernel smp.c file, which method of paring it invoke for paring. 1) passkey 2)Just work or etc . i guess if it will be able to invoke MIMT and passkey level of security , there will not be any authentication issue. Make sure all flags is set to invoke the SMP passkey methods. track by putting some print in smp.c file.
A solution which works in ICS : with btmgmt tool in android and hooking it in encryption APIs. with passkey or any other methods. it works. You might need to add the passkey APIs in btmgmt from latest bluez code.
i think new android 4.4 provide pairing method. same problem already i am facing so wait for update and hope over problem solved createBond() method .
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#setPairingConfirmation%28boolean%29
i want to set the system preference (by code) for just using 2g networks instead of using 3g. so far i haven't found anything that could have helped me. i suppose i need to set it via the ConnectionManager? can anyone point me in the right direction here?
Unfortunately, you can't do this. The best you can do is take the user to the relevant settings screen (Mobile Network Settings), where they can choose for themselves. There's no API to actually change the setting.
Some ROMs (e.g. CyanogenMod) build this into the system, and there may be options if you are rooted/installed as a system app, but if you want something standard/mass applicable then I'm afraid you're out of luck.
use the following code
public class CheckNetworkType extends Activity
{
private static final String tag = "CheckNetworkType";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
if(tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE )
{
// Network type is 2G
Log.v(tag, "2G or GSM");
}
else
if(tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_CDMA)
{
// Network type is 2G
Log.v(tag, "2G or CDMA");
}
else
if(tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS)
{
// Network type is 3G
Log.v(tag, "3G Network available.");
}
}
}