Android 5.1 now has official support for Dual Sim phones, however there's not much currently available in the officially documented APIs. Does anybody know how, with a rooted phone, an app can switch either SIM1 or SIM 2 On and Off?
From the offical documentation mentioned the class SubscriptionManager,I just found something that could be switched:
DefaultVoice:
/** #hide */
public void setDefaultVoiceSubId(int subId) {
if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
iSub.setDefaultVoiceSubId(subId);
}
} catch (RemoteException ex) {
// ignore it
}
}
DefaultSms:
/** #hide */
public void setDefaultSmsSubId(int subId) {
if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
iSub.setDefaultSmsSubId(subId);
}
} catch (RemoteException ex) {
// ignore it
}
}
DefaultData:
/** #hide */
public void setDefaultDataSubId(int subId) {
if (VDBG) logd("setDataSubscription sub id = " + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
iSub.setDefaultDataSubId(subId);
}
} catch (RemoteException ex) {
// ignore it
}
}
But as you see,most of the methods of the class is #hide,that means it's not suitable to be public in the current version(Android 5.1.1/API Level 22).But you can also call them:
https://devmaze.wordpress.com/2011/01/19/using-com-android-internal-part-5-summary-and-example/
And also some information for you from this:
Android dual SIM card API
Related
I want to control wifi hotspot dynamically in my Android app project. I have tired Reflection (which will not work in Android Oreo and later versions), startLocalOnyNetwork (but I want specific SSID and PASSWORD, which is not possible to configure it).
Then I rooted my phone, Is it possible if the device is rooted ?
Expecting an api to turn on/off wifi hotspot with specific SSID and PASSWORD or use the previous one.
Any possibilities or workarounds ?
Thanks in advance.
To turn on Wifi Hotspot, need some permissions
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
and the permission should be dynamically granted by user
In apps advanced settings -> Modify system settings
/**
* This enables tethering using the ssid/password defined in Settings App>Hotspot & tethering
* Does not require app to have system/privileged access
* Credit: Vishal Sharma - https://stackoverflow.com/a/52219887
*/
public boolean startTethering() {
File outputDir = mContext.getCodeCacheDir();
Object proxy;
try {
proxy = ProxyBuilder.forClass(OnStartTetheringCallbackClass())
.dexCache(outputDir).handler(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}).build();
} catch (Exception e) {
Log.e(TAG, "Error in enableTethering ProxyBuilder");
e.printStackTrace();
return false;
}
Method method = null;
try {
method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class);
if (method == null) {
Log.e(TAG, "startTetheringMethod is null");
} else {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null);
Log.d(TAG, "startTethering invoked");
}
return true;
} catch (Exception e) {
Log.e(TAG, "Error in enableTethering");
e.printStackTrace();
}
return false;
}
public void stopTethering() {
try {
Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class);
if (method == null) {
Log.e(TAG, "stopTetheringMethod is null");
} else {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE);
Log.d(TAG, "stopTethering invoked");
}
} catch (Exception e) {
Log.e(TAG, "stopTethering error: " + e.toString());
e.printStackTrace();
}
}
Use above methods to turn on/off Wifi Hotspot with SSID and password defined in the settings.
private int AP_STATE_DISABLED = 11;
private int AP_STATE_ENABLING = 12;
private int AP_STATE_ENABLED = 13;
private int AP_STATE_ERROR = 14;
/**
* #return status hot spot enabled or not
*/
public boolean isHotSpotEnabled(Context context) {
Method method = null;
int actualState = 0;
try {
WifiManager mWifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
method = mWifiManager.getClass().getDeclaredMethod("getWifiApState");
method.setAccessible(true);
actualState = (Integer) method.invoke(mWifiManager, (Object[]) null);
if (actualState == AP_STATE_ENABLING ||actualState == AP_STATE_ENABLED) {
return true;
}
} catch (IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Above method can be used to get the current state of hotspot
I know how to turn on/off wifi hot spot using reflection in android using below method.
private static boolean changeWifiHotspotState(Context context,boolean enable) {
try {
WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Method method = manager.getClass().getDeclaredMethod("setWifiApEnabled", WifiConfiguration.class,
Boolean.TYPE);
method.setAccessible(true);
WifiConfiguration configuration = enable ? getWifiApConfiguration(manager) : null;
boolean isSuccess = (Boolean) method.invoke(manager, configuration, enable);
return isSuccess;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
But the above method is not working Android 8.0(Oreo).
When I execute above method in Android 8.0, I am getting below statement in logcat.
com.gck.dummy W/WifiManager: com.gck.dummy attempted call to setWifiApEnabled: enabled = true
Is there any other way to on/off hotspot on android 8.0
I thought the LocalOnlyHotspot route was the way to, but as #edsappfactory.com said in the comments - it only gives closed network, no internet access.
In Oreo hot-spotting/tethering moved to ConnectionManager, and its annotated #SystemApi, so (nominally) inaccessible.
As part of something else I was doing, I made an app and put it on github here. It uses reflection to get at the function and DexMaker to generate a subclass of ConnectionManager.OnStartTetheringCallback (which is also inaccessible).
Think it all works okay - bit rough around the edges, so please feel free to make better!
Relevant bits of code are in:
MyOreoWifiManager and;
CallbackMaker
I lost patience trying to get my DexMaker-generated callback to fire the MyOnStartTetheringCallback so all that code is in disarray and commented out.
Finally I got the solution.
Android 8.0, they provided public api to turn on/off hotspot. WifiManager
Below is the code to turn on hotspot
private WifiManager.LocalOnlyHotspotReservation mReservation;
#RequiresApi(api = Build.VERSION_CODES.O)
private void turnOnHotspot() {
WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
#Override
public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
super.onStarted(reservation);
Log.d(TAG, "Wifi Hotspot is on now");
mReservation = reservation;
}
#Override
public void onStopped() {
super.onStopped();
Log.d(TAG, "onStopped: ");
}
#Override
public void onFailed(int reason) {
super.onFailed(reason);
Log.d(TAG, "onFailed: ");
}
}, new Handler());
}
private void turnOffHotspot() {
if (mReservation != null) {
mReservation.close();
}
}
onStarted(WifiManager.LocalOnlyHotspotReservation reservation) method will be called if hotspot is turned on.. Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot.
Note:
To turn on hotspot, the Location(GPS) should be enabled in the device. Otherwise, it will throw SecurityException
As per Jon suggestion, I got another way to enable WifiHotSpot in Android Oreo and above.
public boolean enableTetheringNew(MyTetheringCallback callback) {
File outputDir = mContext.getCodeCacheDir();
try {
proxy = ProxyBuilder.forClass(classOnStartTetheringCallback())
.dexCache(outputDir).handler(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "onTetheringStarted":
callback.onTetheringStarted();
break;
case "onTetheringFailed":
callback.onTetheringFailed();
break;
default:
ProxyBuilder.callSuper(proxy, method, args);
}
return null;
}
}).build();
} catch (IOException e) {
e.printStackTrace();
}
ConnectivityManager manager = (ConnectivityManager) mContext.getApplicationContext().getSystemService(ConnectivityManager.class);
Method method = null;
try {
method = manager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, classOnStartTetheringCallback(), Handler.class);
if (method == null) {
Log.e(TAG, "startTetheringMethod is null");
} else {
method.invoke(manager, TETHERING_WIFI, false, proxy, null);
}
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
private Class classOnStartTetheringCallback() {
try {
return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
I am able to pair a bluetooth keyboard but not able to connect so as to make it an input device.
I went through the documentation provided at developer site - http://developer.android.com/guide/topics/connectivity/bluetooth.html#Profiles
It says that the Android Bluetooth API provides implementations for the following Bluetooth profiles but you can implement the interface BluetoothProfile to write your own classes to support a particular Bluetooth profile.
Headset
A2DP
Health Device
There is no documentation how to implement BluetoothProfile for HID bluetooth device(Keyboard)
Android has itself implemented bluetooth connection for HID devices but those API's are hidden. I tried reflection to use them too. I do not get any error but keyboard does not get connected as input device. This is what i have done -
private void connect(final BluetoothDevice bluetoothDevice) {
if(bluetoothDevice.getBluetoothClass().getDeviceClass() == 1344){
final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
#Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
Log.i("btclass", profile + "");
if (profile == getInputDeviceHiddenConstant()) {
Class instance = null;
try {
//instance = Class.forName("android.bluetooth.IBluetoothInputDevice");
instance = Class.forName("android.bluetooth.BluetoothInputDevice");
Method connect = instance.getDeclaredMethod("connect", BluetoothDevice.class);
Object value = connect.invoke(proxy, bluetoothDevice);
Log.e("btclass", value.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
#Override
public void onServiceDisconnected(int profile) {
}
};
mBluetoothAdapter.getProfileProxy(this, mProfileListener,getInputDeviceHiddenConstant());
}
}
public static int getInputDeviceHiddenConstant() {
Class<BluetoothProfile> clazz = BluetoothProfile.class;
for (Field f : clazz.getFields()) {
int mod = f.getModifiers();
if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
try {
if (f.getName().equals("INPUT_DEVICE")) {
return f.getInt(null);
}
} catch (Exception e) {
Log.e("", e.toString(), e);
}
}
}
return -1;
}
Due to security reasons, it is not possible for third party applications to connect to a bluetooth keyboard as the application can be a keylogger. So it can be only done manually by the user.
Here is the code I used on Android Marshmallow (6.0).. To get an L2CAP connection started (Needed for HID)
public static BluetoothSocket createL2CAPBluetoothSocket(String address, int psm){
return createBluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false,false, address, psm);
}
// method for creating a bluetooth client socket
private static BluetoothSocket createBluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, int port){
Log.e(TAG, "Creating socket with " + address + ":" + port);
try {
Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
int.class, int.class,boolean.class,boolean.class,String.class, int.class);
constructor.setAccessible(true);
BluetoothSocket clientSocket = (BluetoothSocket) constructor.newInstance(type,fd,auth,encrypt,address,port);
return clientSocket;
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Boolean connect(View v) {
try {
// TODO: Check bluetooth enabled
mDevice = getController();
if (mDevice != null) {
Log.e(TAG, "Controller is paired");
// Create socket
mSocket = createL2CAPBluetoothSocket(mDevice.getAddress(), 0x1124);
if (mSocket != null) {
if (!mSocket.isConnected()) {
mSocket.connect();
}
Log.e(TAG, "Socket successfully created");
ConnectedThread mConnectedThread = new ConnectedThread(mSocket);
mConnectedThread.run();
}
} else {
showToast("Controller is not connected");
}
return true;
} catch (Exception e) {
e.printStackTrace();
if (e instanceof IOException){
// handle this exception type
} else {
// We didn't expect this one. What could it be? Let's log it, and let it bubble up the hierarchy.
}
return false;
}
}
private BluetoothDevice getController() {
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
if (device.getName().equals("Wireless Controller")) // Change to match DS4 - node name
{
Log.d(TAG, "Found device named: " + device.getName());
return device;
}
}
}
return null;
}
It can still have problems creating the Service, and you need to set the correct L2CAP PSAM for the device, but hope it can help..
How can I detect if 'High Contrast' setting (available on Android 5.0+) is enabled in Accessibility settings?
In the AccessibilityManager class (see source here) you have a public method called isHighTextContrastEnabled that you can use to get your information:
/**
* Returns if the high text contrast in the system is enabled.
* <p>
* <strong>Note:</strong> You need to query this only if you application is
* doing its own rendering and does not rely on the platform rendering pipeline.
* </p>
*
* #return True if high text contrast is enabled, false otherwise.
*
* #hide
*/
public boolean isHighTextContrastEnabled() {
synchronized (mLock) {
IAccessibilityManager service = getServiceLocked();
if (service == null) {
return false;
}
return mIsHighTextContrastEnabled;
}
}
So in your code, you can access this method by doing so (if you're in an Activity):
AccessibilityManager am = (AccessibilityManager) this.getSystemService(Context.ACCESSIBILITY_SERVICE);
boolean isHighTextContrastEnabled = am.isHighTextContrastEnabled();
#alxscms' answer may be right but it does not help me So I found an alternative way to check High contrast text is Enabled or not in android.
Below function will return true if HighContrastText is enabled in user phone and otherwise return false.
Below function is checked in all android phones and it's working.
public static boolean isHighContrastTextEnabled(Context context) {
if (context != null) {
AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
Method m = null;
if (am != null) {
try {
m = am.getClass().getMethod("isHighTextContrastEnabled", null);
} catch (NoSuchMethodException e) {
Log.i("FAIL", "isHighTextContrastEnabled not found in AccessibilityManager");
}
}
Object result;
if (m != null) {
try {
result = m.invoke(am, null);
if (result instanceof Boolean) {
return (Boolean) result;
}
} catch (Exception e) {
Log.i("fail", "isHighTextContrastEnabled invoked with an exception" + e.getMessage());
}
}
}
return false;
}
I hope this can help many more others.
we can check highContrast fonts like this
public boolean isHighTextContrastEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(), "high_text_contrast_enabled", 0) == 1;
}
I want to pair the device and connect it ,but I have a problem ,I just can pair device but I am not able to connect them. I want to know how to solve this problem. I'm afraid, I have not explained my problem very well, I can not connect means, connect your phone to a Bluetooth headset and I can only pair, here is the code
if (btAdapt.isEnabled()) {
tbtnSwitch.setChecked(false);
} else {
tbtnSwitch.setChecked(true);
}
// ============================================================
IntentFilter intent = new IntentFilter();
intent.addAction(BluetoothDevice.ACTION_FOUND);
intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(searchDevices, intent);
}
private BroadcastReceiver searchDevices = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Bundle b = intent.getExtras();
Object[] lstName = b.keySet().toArray();
for (int i = 0; i < lstName.length; i++) {
String keyName = lstName[i].toString();
Log.e(keyName, String.valueOf(b.get(keyName)));
}
BluetoothDevice device = null;
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
String str = "no pair|" + device.getName() + "|"
+ device.getAddress();
if (lstDevices.indexOf(str) == -1)
lstDevices.add(str);
adtDevices.notifyDataSetChanged();
}
}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (device.getBondState()) {
case BluetoothDevice.BOND_BONDING:
Log.d("BlueToothTestActivity", "it is pairing");
break;
case BluetoothDevice.BOND_BONDED:
Log.d("BlueToothTestActivity", "finish");
connect(device);
break;
case BluetoothDevice.BOND_NONE:
Log.d("BlueToothTestActivity", "cancel");
default:
break;
}
}
}
};
#Override
protected void onDestroy() {
this.unregisterReceiver(searchDevices);
super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
}
class ItemClickEvent implements AdapterView.OnItemClickListener {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
if(btAdapt.isDiscovering())btAdapt.cancelDiscovery();
String str = lstDevices.get(arg2);
String[] values = str.split("\\|");
String address = values[2];
Log.e("address", values[2]);
BluetoothDevice btDev = btAdapt.getRemoteDevice(address);
try {
Boolean returnValue = false;
if (btDev.getBondState() == BluetoothDevice.BOND_NONE) {
BluetoothDevice.createBond(BluetoothDevice remoteDevice);
Method createBondMethod = BluetoothDevice.class
.getMethod("createBond");
Log.d("BlueToothTestActivity", "start");
returnValue = (Boolean) createBondMethod.invoke(btDev);
}else if(btDev.getBondState() == BluetoothDevice.BOND_BONDED){
connect(btDev);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void connect(BluetoothDevice btDev) {
UUID uuid = UUID.fromString(SPP_UUID);
try {
btSocket = btDev.createInsecureRfcommSocketToServiceRecord(uuid);
Log.d("BlueToothTestActivity", "connecting...");
btSocket.connect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class ClickEvent implements View.OnClickListener {
public void onClick(View v) {
if (v == btnSearch)
{
if (btAdapt.getState() == BluetoothAdapter.STATE_OFF) {
Toast.makeText(BlueToothTestActivity.this, "please open", 1000)
.show();
return;
}
if (btAdapt.isDiscovering())
btAdapt.cancelDiscovery();
lstDevices.clear();
Object[] lstDevice = btAdapt.getBondedDevices().toArray();
for (int i = 0; i < lstDevice.length; i++) {
BluetoothDevice device = (BluetoothDevice) lstDevice[i];
String str = "pair|" + device.getName() + "|"
+ device.getAddress();
lstDevices.add(str);
adtDevices.notifyDataSetChanged();
}
setTitle("address:" + btAdapt.getAddress());
btAdapt.startDiscovery();
} else if (v == tbtnSwitch) {
if (tbtnSwitch.isChecked() == false)
btAdapt.enable();
else if (tbtnSwitch.isChecked() == true)
btAdapt.disable();
} else if (v == btnDis)
{
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
} else if (v == btnExit) {
try {
if (btSocket != null)
btSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
BlueToothTestActivity.this.finish();
}
}
}
}
You have not specified, but I assume your problem is in the socket creation part rather than the actual connect() call. This is where things usually go wrong.
How to fix?
Your code assumes the headset supports insecure BT communications. In many cases this is true, but not in all. Try calling createRfcommSocketToServiceRecord() instead
Your code uses the default SPP UUID for the RFCOMM channel lookup. For API versions >= 15 this is the wrong thing to do. Instead try calling device.getUuids() and use the first returned UUID as the creation parameter.
From my own experience, even for pre-15 API versions you can still call getUuids() and get good results, but you will need to do it by reflection. Only if the above fails should you attempt socket creation with the default SPP UUID
If the above fails, you may try, as a last resort, to activate the "createRfcommSocket" hidden API . That had worked for me several occasions, and on multiple Android versions. Use java reflection to activate this call and, since inherently not safe, protect it with try catch.
Remember to place your logic in an AsyncTask or something. You do not want the UI thread to block on such tasks!
Finally feel free to use https://github.com/giladHaimov/BTWiz for a much simpler handling of the Bluetooth connect and for simple async IO interface.
Quoting your code:
btSocket = btDev.createInsecureRfcommSocketToServiceRecord(uuid);
Log.d("BlueToothTestActivity", "connecting...");
btSocket.connect();
You can find the code on the official Android documentation on connecting as a client, here.
I can see 4 things that might cause problems:
You should connect in a separate thread! .connect() is a blocking call - see link above
Not all devices accept insecure connections
For Android devices below 2.3.3 this method does not work. You have to call a private method via reflection - see this. Also I think you will find it on SO.
Surround .create.... with a try/catch and post errors on Logcat.
Can you post your Logcat logs?