I have a webview in my activity. Now when I use WebView.findAll() method to search text in webview it is not highlighting the matching words.
It works fine in Android 1.6 but is not working in 2.2.
There is an issue in Android issue tracker about this: http://code.google.com/p/android/issues/detail?id=9018
I placed this code right after WebView.findAll(), and it made highlighting working:
try
{
Method m = WebView.class.getMethod("setFindIsUp", Boolean.TYPE);
m.invoke(webView, true);
}
catch (Throwable ignored){}
In android 4.0.3, seems the setFindIsUp is a private method. So above code won't work. As getMethod() method won't return the private methods. Following is a work-around to call the private method which works for 4.0.3:
try{
//Can't use getMethod() as it's a private method
for(Method m : WebView.class.getDeclaredMethods()){
if(m.getName().equals("setFindIsUp")){
m.setAccessible(true);
m.invoke(view, true);
break;
}
}
}catch(Exception ignored){}
Related
I'm looking for a way to identify the input device that is external.
I notice the Android API for [InputDevice] class have a function called [isExternal]. But when I tried to use it, it tells me that it cannot resolve method. I check the online API reference and notice that the function does not exist. So I wonder why is the function in the API but not in the online reference.
Reference:
https://developer.android.com/reference/android/view/InputDevice.html
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/InputDevice.java
isExternal is a hidden method that is not accessible through the SDK. However, you can still invoke it using java reflection.
public boolean isExternal(InputDevice inputDevice) {
try {
Method m = InputDevice.class.getMethod("isExternal");
return (Boolean) m.invoke(inputDevice);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
}
source: What does #hide mean in the Android source code?
I am facing a rendering issue when running animation to simple View. My setup has ViewPager and the first Fragment contains a WebView and the second Fragment has custom progress indicator which I animate.
Following image shows the problem, somehow there is relation with the WebView although the indicator is fully in it's own Fragment. My guess is that the platform uses the same GPU renderer and when having a WebView there it gets broken.
Anyone had same issue/found a workaround?
Thanks.
My guess was somewhat correct. I found a hack to fix this issue.
Extend WebView and override all constructors
Set layer type to software for the custom WebView
API level >= 11
setLayerType(LAYER_TYPE_SOFTWARE, null);
API level < 11
try {
Method setLayerType = getClass().getMethod("setLayerType",
new Class[] { int.class, Paint.class });
if (setLayerType != null)
setLayerType.invoke(this, new Object[] { 1, null });
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
NOTE: This implementation dramatically affects performance of WebView.
Have a look at this,
https://developer.android.com/guide/webapps/migrating.html
In KitKat everything has pretty much changed.
Why don't you try and set the target SDK to 18. If you do this then the webview works in compatibility mode.
I am trying to use ITelephony.aidl in my application. Using this i want to answer the incoming call. I managed to use endcall() and it works perfectly. But when i try to use answerringingcall() it throws error and says that MODIFY_PHONE_STATE is needed, but cant be used since its only available for system apps.
So is there any way of making this work on android 2.3 and above?or is there any other way for answering calls ?
thanks in advance:)
here's my code.
`
public void callAnswer(){
try {
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
telephonyService.answerRingingCall();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}`
and this is my ITelephony.aidl file
package com.android.internal.telephony;
interface ITelephony {
boolean endCall();
void answerRingingCall();
}
must add permission uses-permission android:name="android.permission.MODIFY_PHONE_STATE"
May be #pra16 you have found a way to accept a call. If not check out this link.The headset keyevent hack worked fine for me . I tested it on android 4.3
I have some code to automatically pair with a bluetooth device by calling createBond(), registering a broadcast receiver for android.bluetooth.device.action.PAIRING_REQUEST and then manually entering the PIN code to pair.
This has worked great with all devices tested so far up to Andoid 4.0 but today I tried this on my Nexus 7 with Android 4.2.1 and got the following error:
java.lang.noSuchMethodException: android.bluetooth.IBluetooth.createBond
Did they actually remove this function from the library?
UPDATE
What's actually happening is the IBluetooth interface object that I am using to call createBond is not being initialized. In the following code the line that tries to get the IBinder named BTBinder returns null when this process fails causing BTInterface to be set to null at the end. So, my question now is why on my Nexus 7 with Android 4.2.1 does the call to get the binder return null but works correctly on 5 other devices I've tested?
public static IBluetooth getBluetoothInterface()
{
//Gets a bluetooth interface from private Android system API
IBluetooth BTInterface = null;
try
{
Class<?> ServiceManager = Class.forName("android.os.ServiceManager");
Method getService = ServiceManager.getDeclaredMethod("getService", String.class);
IBinder BTBinder = (IBinder) getService.invoke(null, "bluetooth");
Class<?> IBluetooth = Class.forName("android.bluetooth.IBluetooth");
Class<?>[] IBluetoothClasses = IBluetooth.getDeclaredClasses();
Class<?> IBluetoothClass0 = IBluetoothClasses[0];
Method asInterface = IBluetoothClass0.getDeclaredMethod("asInterface",IBinder.class);
asInterface.setAccessible(true);
BTInterface = (IBluetooth) asInterface.invoke(null, BTBinder);
}
catch (Exception e)
{
return null;
}
return BTInterface;
}
In Android 4.2 they changed the bluetooth stack implementation.
"Android 4.2 introduces a new Bluetooth stack optimized for use with Android devices. The new Bluetooth stack developed in collaboration between Google and Broadcom replaces the stack based on BlueZ and provides improved compatibility and reliability."
There are a lot of bt related things not working even with the public api on Nexus 7.
public boolean createBond(BluetoothDevice btDevice)
throws Exception
{
Class class1 = Class.forName("android.bluetooth.BluetoothDevice");
Method createBondMethod = class1.getMethod("createBond");
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
return returnValue.booleanValue();
}
This worked on 4.2.1 Galaxy Nexus. Haven't tried on Nexus 7, but I had the same issue of MethodNotFoundException when I use IBluetooth method. So it might also fix for Nexus 7 too.
Is there a way to retrieve Browser's user-agent without having a WebView in activity?
I know it is possible to get it via WebView:
WebView view = (WebView) findViewById(R.id.someview);
String ua = view.getSettings().getUserAgentString() ;
But in my case I don't have/need a webview object and I don't want to create it just for retrieving user-agent string.
If you don't have one you can try taking it like this
String ua=new WebView(this).getSettings().getUserAgentString();
Edit-
The doc for getUserAgentString() says
Return the WebView's user-agent string.
So i don't think you can get it unless you declare one. Some one correct me if i am wrong
There is a much simpler way if you are on Android 2.1 or above. Granted this isn't the exact same User Agent string that a webview would return, but might serve you well enough for your purposes.
As an additional advantage to pulling from web view, you can use this from any thread (not just the UI thread).
There is a system property called http.agent, which can be used to retrieve the User-Agent string.
String userAgent = System.getProperty("http.agent");
See Programmatically get User-Agent String for more details.
I used to use solution proposed by DeRagan. But it turned out that creating a single WebView instance starts a thread "WebViewCoreThread" which stays on the background until application is terminated by the system. Maybe it doesn't consume too much resources but I don't like it anyway. So I use slightly different method now, which tries to avoid WebViewCoreThread creation:
// You may uncomment next line if using Android Annotations library, otherwise just be sure to run it in on the UI thread
// #UiThread
public static String getDefaultUserAgentString(Context context) {
if (Build.VERSION.SDK_INT >= 17) {
return NewApiWrapper.getDefaultUserAgent(context);
}
try {
Constructor<WebSettings> constructor = WebSettings.class.getDeclaredConstructor(Context.class, WebView.class);
constructor.setAccessible(true);
try {
WebSettings settings = constructor.newInstance(context, null);
return settings.getUserAgentString();
} finally {
constructor.setAccessible(false);
}
} catch (Exception e) {
return new WebView(context).getSettings().getUserAgentString();
}
}
#TargetApi(17)
static class NewApiWrapper {
static String getDefaultUserAgent(Context context) {
return WebSettings.getDefaultUserAgent(context);
}
}
It creates WebSettings instance directly using package-visible constructor and if that is not available for some reason (e.g. due to API changes in future Android versions) - silently falls back to "WebView-like" solution.
UPDATE
As pointed by #Skywalker5446, starting from Android 4.2/API 17, there is a public static method to get default user agent value. I've updated my code to use that method on the supported platforms.
Since Android 2.1 you should use System.getProperty("http.agent");
You also dont need to create a WebView first AND , thats the advantage,
you can use it inside a non-uithread.
greetings steve
This is an updated solution based on previous answers that works when you compile for KitKat. Now the WebSettings class is abstract and the WebSettingsClassic class has been removed.
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static String getUserAgent(final Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return WebSettings.getDefaultUserAgent(context);
}
else {
try {
final Class<?> webSettingsClassicClass = Class.forName("android.webkit.WebSettingsClassic");
final Constructor<?> constructor = webSettingsClassicClass.getDeclaredConstructor(Context.class, Class.forName("android.webkit.WebViewClassic"));
constructor.setAccessible(true);
final Method method = webSettingsClassicClass.getMethod("getUserAgentString");
return (String) method.invoke(constructor.newInstance(context, null));
}
catch (final Exception e) {
return new WebView(context).getSettings()
.getUserAgentString();
}
}
}
Thanks to Idolon's answer my app could process this in the background.
But somehow on HTC Inspire 4G from AT&T that runs 2.3.3, it goes to the catch statement and it can be no longer run on the background thread.
My solution for this is the following:
public static String getUserAgent(Context context) {
try {
Constructor<WebSettings> constructor = WebSettings.class.getDeclaredConstructor(Context.class, WebView.class);
constructor.setAccessible(true);
try {
WebSettings settings = constructor.newInstance(context, null);
return settings.getUserAgentString();
} finally {
constructor.setAccessible(false);
}
} catch (Exception e) {
String ua;
if(Thread.currentThread().getName().equalsIgnoreCase("main")){
WebView m_webview = new WebView(context);
ua = m_webview.getSettings().getUserAgentString();
}else{
mContext = context;
((Activity) mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
WebView webview = new WebView(mContext);
mUserAgent = webview.getSettings().getUserAgentString();
}
});
return mUserAgent;
}
return ua;
}
}
(suppose you have mContext and mUserAgent in the field)