I'm try send DTMF codes in icoming CALL. For this i'n try use Java reflection:
public void initialize(){
ClassLoader classLoader = Dtmf.class.getClassLoader();
final Class<?> classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
Method methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
objectCallManager = methodGetInstance.invoke(null);
methodGetState = classCallManager.getDeclaredMethod(SEND_DTMF, char.class);
}
public boolean sendDtmf(char ch) {
boolean result = false;
if ( methodGetState != null) {
try {
Object res = methodGetState.invoke(objectCallManager,
new Object[]{Character.valueOf(ch)});
if (res instanceof Boolean) {
result = ((Boolean) res).booleanValue();
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return result;
}
Link for source code of class CallManager : Call Manager source code
But i'm always get "false" in method sendDtmf(). In debug, code is go into next:
Object res = methodGetState.invoke(objectCallManager,
new Object[]{Character.valueOf(ch)});
What wrong?
The method is likely throwing an InvocationTargetException if your application isn't signed with the platform certificate as conventional apps cannot execute these methods (and will not be granted the required platform permissions to do so).
In short: the method is returning false because you're catching (and ignoring) the exception.
There's an open issue (#1428) on the Android issue tracker for sending DTMF tones as it presently isn't possible.
Related
I'm working on an SDK for Android. As part of this SDK, I need to set my own WebViewClient to a WebView of an application where the WebView and the SDK are integrated (meaning not part of my SDK).
For this reason, this WebView might have already been set with a WebViewClient and in this case, I need to get the instance of this WebViewClient from the WebView set my own WebViewClient to it and forward the callback methods of my WebViewCleint to the originally configured one that was set by the developer of the app.
I noticed that from API V26 there is a getWebViewClient method for the WebView class. but obviously, I'm looking for a way to do this on previous versions as well. Maybe there is some kind of way to do this using the support libs?
Does someone know how can I get the instance of the set WebViewClient in the WebView in older versions? using Reflection or any other method?
I managed to get the instance of the WebViewClient using reflection like so:
Object providerInstance = getProviderInstance();
Object contentsClientAdapter = getContentsClientAdapter(providerInstance);
Object webViewClient = getWebViewClientFromClientAdapter(contentsClientAdapter);
if (webViewClient instanceof WebViewClient) {
mPreviousWebViewClient = (WebViewClient) webViewClient;
}
And those are the three methods to drill down the WebView object to get the WebViewClient object:
public Object getProviderInstance() {
Object returnValue = null;
try {
Class<? extends WebView> mWebViewClass = mWebView.getClass();
Field providerField = mWebViewClass.getDeclaredField("mProvider");
providerField.setAccessible(true);
Object mProvider = providerField.get(mWebView);
returnValue = mProvider;
} catch (NoSuchFieldException aE) {
aE.printStackTrace();
} catch (IllegalAccessException aE) {
aE.printStackTrace();
}
return returnValue;
}
private Object getContentsClientAdapter(Object aProviderInstance) {
Object returnValue = null;
try {
Class<?> aClass = aProviderInstance.getClass();
Field contentsClientAdapterField = aClass.getDeclaredField("mContentsClientAdapter");
contentsClientAdapterField.setAccessible(true);
Object mContentsClientAdapter = contentsClientAdapterField.get(aProviderInstance);
returnValue = mContentsClientAdapter;
} catch (NoSuchFieldException aE) {
aE.printStackTrace();
} catch (IllegalAccessException aE) {
aE.printStackTrace();
}
return returnValue;
}
private Object getWebViewClientFromClientAdapter(Object aContentsClientAdapter) {
Object returnValue = null;
try {
Class<?> aClass = aContentsClientAdapter.getClass();
Field WebViewClientField = aClass.getDeclaredField("mWebViewClient");
WebViewClientField.setAccessible(true);
Object mWebViewClient = WebViewClientField.get(aContentsClientAdapter);
returnValue = mWebViewClient;
} catch (NoSuchFieldException aE) {
aE.printStackTrace();
} catch (IllegalAccessException aE) {
aE.printStackTrace();
}
return returnValue;
}
But I'm really hoping to find some kind of another way to do the same. Something that will be less prone to breakage.
I am developing an application which needs to send sms in pdu mode.
I am using this code but it gives NoSuchElementException on first line.
try {
Method m2 = sms.getClass().getDeclaredMethod("sendRawPdu", pdu.getClass(), pdu.getClass(), piSent.getClass(), piDelivered.getClass());
m2.setAccessible(true);
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(null, "", "Test", false);
Object[] arrayOfObject2 = new Object[5];
arrayOfObject2[0] = pdus.encodedScAddress;
arrayOfObject2[1] = pdus.encodedMessage;
arrayOfObject2[2] = piSent;
arrayOfObject2[3] = piDelivered;
arrayOfObject2[4] = null;
try {
m2.invoke(sms, arrayOfObject2);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Any help will be appreciated.
I tried it on Lollipop, but there is no method related to sendRawPdu
Do a little more thing just print the list of methods available to check if there is any method related to sendRawPdu
Method[] methods = sms.getClass().getDeclaredMethods();
boolean methodAvailable = false;
for(Method m : methods) {
Log.d("SmsManager", m.toString());
if(m.toString().contains("sendRawPdu")) {
methodAvailable = true;
}
}
now you have methodAvailable, if it is true you can send Raw PDU, if not then you can't. sendRawPdu was available before JellyBeans. Try to run this on Pre JellyBeans devices.
I am trying to read WIFI proxy settings
Proxy host
Proxy port
Proxy user (authentication)
Proxy password (authentication)
from devices in android versions 2.X.X – 4.X.X without any success.
Calling:
String proxy = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.HTTP_PROXY);
Always returns null.
I've also added to my android manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
still it returns null.
Also tried:
android.net.Proxy. getHost(Context ctx) – which is deprecated – returns the IP
android.net.Proxy. getPortt(Context ctx) – which is deprecated – returns always -1.
Java calls:
System.getProperty("http.proxyHost");
System.getProperty("http.proxyCall");
Also returns null.
Is there a working code which retrieves all these settings or at least partially from devices in all android versions?
I found this project: Android Proxy Library
Which provides backward compatible ways of querying Proxy settings as well as setting them for WebViews on older versions of Android.
// Grab Proxy settings in a backwards compatible manner
ProxyConfiguration proxyConfig = ProxySettings.getCurrentHttpProxyConfiguration( context );
// Set Proxy for WebViews on older versions of Android
ProxyUtils.setWebViewProxy( getActivity().getApplicationContext() );
However, there is something you need to understand about Proxy Settings set on a WiFi AP. Since WiFi specific Proxy Settings were not implemented in Android proper until 3.1, all pre-3.1 devices that expose that functionality are using some sort of custom hack. They don't work in any sort of standard way. So libraries like this won't be able to grab any proxy set from one of those hacks.
There is however a System Wide Proxy in pre-3.1 that this sort of library WILL grab. Of course Android saw fit not to provide any official way to modify this setting. But there are apps on the Play Store that will allow you to do it, this is the one I'm using: Proxy Settings and it works well, setting the System Proxy and allowing you to grab it either via this library, or even simpler methods like querying the JVM proxy settings.
I ended up not using the APL and instead went with a much simpler implementation:
private static final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
...
String proxyAddress;
int proxyPort;
if( IS_ICS_OR_LATER )
{
proxyAddress = System.getProperty( "http.proxyHost" );
String portStr = System.getProperty( "http.proxyPort" );
proxyPort = Integer.parseInt( ( portStr != null ? portStr : "-1" ) );
}
else
{
proxyAddress = android.net.Proxy.getHost( context );
proxyPort = android.net.Proxy.getPort( context );
}
This is what I'm using:
public static String[] getUserProxy(Context context)
{
Method method = null;
try
{
method = ConnectivityManager.class.getMethod("getProxy");
}
catch (NoSuchMethodException e)
{
// Normal situation for pre-ICS devices
return null;
}
catch (Exception e)
{
return null;
}
try
{
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Object pp = method.invoke(connectivityManager);
if (pp == null)
return null;
return getUserProxy(pp);
}
catch (Exception e)
{
return null;
}
}
private static String[] getUserProxy(Object pp) throws Exception
{
String[] userProxy = new String[3];
String className = "android.net.ProxyProperties";
Class<?> c = Class.forName(className);
Method method;
method = c.getMethod("getHost");
userProxy[0] = (String) method.invoke(pp);
method = c.getMethod("getPort");
userProxy[1] = String.valueOf((Integer) method.invoke(pp));
method = c.getMethod("getExclusionList");
userProxy[2] = (String) method.invoke(pp);
if (userProxy[0] != null)
return userProxy;
else
return null;
}
Following is code snippet to retrieve proxy details
public static String getProxyDetails(Context context) {
String proxyAddress = new String();
try {
if (IsPreIcs()) {
proxyAddress = android.net.Proxy.getHost(context);
if (proxyAddress == null || proxyAddress.equals("")) {
return proxyAddress;
}
proxyAddress += ":" + android.net.Proxy.getPort(context);
} else {
proxyAddress = System.getProperty("http.proxyHost");
proxyAddress += ":" + System.getProperty("http.proxyPort");
}
} catch (Exception ex) {
//ignore
}
return proxyAddress;
}
It'll return enmpty if some exception or no proxy detected;
private fun getUserProxy(context: Context): Data {
return try {
val declaredField = WifiConfiguration::class.java.getDeclaredField("mIpConfiguration")
declaredField.isAccessible = true
val data =
(context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager)
?.configuredNetworks
?.asSequence()
?.mapNotNull {
try {
declaredField.get(it)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
?.mapNotNull {
try {
(it.javaClass.getDeclaredField("httpProxy").get(it) as? ProxyInfo)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
?.find { !it.host.isNullOrEmpty() }
?.let { Data(it.host ?: "", it.port.toString()) }
?: Data()
declaredField.isAccessible = false
return data
} catch (e: Exception) {
e.printStackTrace()
Data()
}
}
data class Data(
val host: String = "",
val port: String = ""
)
I'm using aidl to answer call automagically, code as following:
ITelephony.Stub.asInterface(ServiceManager.getService("phone"))
.answerRingingCall();
I import ServiceManager.class
import android.os.ServiceManager;
but there's a problem:The import android.os.ServiceManager cannot be resolved
How can I make it work? Thanks
android.os.ServiceManager is a hidden class (i.e., #hide) and hidden classes (even if they are public in the Java sense) are removed from android.jar, hence you get the error when you try to import ServiceManager. Hidden classes are those that Google does not want to be part of the documented public API.
Applications using non-public API cannot be compiled easily, there will be different platform versions of this class.
Though it is old one, but no one has answered it yet. Any hidden classes can be used using reflection APIs. Here is an example to acquire a service using Service Manager via reflection APIs:
if(mService == null) {
Method method = null;
try {
method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null, "My_SERVICE_NAME");
if(binder != null) {
mService = IMyService.Stub.asInterface(binder);
}
if(mService != null)
mIsAcquired = true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "Service is already acquired");
}
As said above these methods work only on System apps or framework apps from Android N on words.
Still we can code for System app for ServiceManager usage as below using reflection of Android Code
#SuppressLint("PrivateApi")
public IMyAudioService getService(Context mContext) {
IMyAudioService mService = null;
Method method = null;
try {
method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null, "YOUR_METHOD_NAME");
if (binder != null) {
mService = IMyAudioService .Stub.asInterface(binder);
}
} catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return mService;
}
I need to cancel the missed calls notification for a certain number. I've seen the NotificationMgr class on com.android.phone but i'm unable to call it trough reflection. Is there any other way?
The code below will cancel the missed call notification.
To get the method work correctly, you must gain MODIFY_PHONE_STATE permission in AndroidManifest.xml like
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"></uses-permission>
in your AndroidManifest.xml
String Log_Tag = "log";
try
{
Class serviceManagerClass = Class.forName("android.os.ServiceManager");
Method getServiceMethod = serviceManagerClass.getMethod("getService", String.class);
Object phoneService = getServiceMethod.invoke(null, "phone");
Class ITelephonyClass = Class.forName("com.android.internal.telephony.ITelephony");
Class ITelephonyStubClass = null;
for(Class clazz : ITelephonyClass.getDeclaredClasses())
{
if (clazz.getSimpleName().equals("Stub"))
{
ITelephonyStubClass = clazz;
break;
}
}
if (ITelephonyStubClass != null)
{
Class IBinderClass = Class.forName("android.os.IBinder");
Method asInterfaceMethod = ITelephonyStubClass.getDeclaredMethod("asInterface",
IBinderClass);
Object iTelephony = asInterfaceMethod.invoke(null, phoneService);
if (iTelephony != null)
{
Method cancelMissedCallsNotificationMethod = iTelephony.getClass().getMethod(
"cancelMissedCallsNotification");
cancelMissedCallsNotificationMethod.invoke(iTelephony);
}
else
{
Log.w(LOG_TAG, "Telephony service is null, can't call "
+ "cancelMissedCallsNotification");
}
}
else
{
Log.d(LOG_TAG, "Unable to locate ITelephony.Stub class!");
}
} catch (ClassNotFoundException ex)
{
Log.e(LOG_TAG,
"Failed to clear missed calls notification due to ClassNotFoundException!", ex);
} catch (InvocationTargetException ex)
{
Log.e(LOG_TAG,
"Failed to clear missed calls notification due to InvocationTargetException!",
ex);
} catch (NoSuchMethodException ex)
{
Log.e(LOG_TAG,
"Failed to clear missed calls notification due to NoSuchMethodException!", ex);
} catch (Throwable ex)
{
Log.e(LOG_TAG, "Failed to clear missed calls notification due to Throwable!", ex);
}
The original link is
http://sites.google.com/site/t2k269group/development-diary/reset-missed-calls-notification
If some know how to use the reflection to access class in com.android.phone, please tell me.
You cannot affect anyone other application's Notifications, let alone one for missed calls.