I am creating an application which requires a webview.
I want to enable text selection in webview. (I found a few solutions but none of them worked)
Once the webview is selected, it should not be directly copied. I should be able to expand the selection range with handles (It is possible in version 2.3 and later. But I want this on versions lower than 2.3. HTC's browser gives us this option)
Any idea?
recently i solved that
put this function on create or on load in activity
private void emulateShiftHeld(WebView view)
{
try
{
KeyEvent shiftPressEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0);
shiftPressEvent.dispatch(view);
}
catch (Exception e)
{
Log.e("dd", "Exception in emulateShiftHeld()", e);
}
}
it will done...
Related
I've been developing hybrid apps for many companies with mobile websites.
And as a matter of fact, there are some websites made with using jsp.
I already had the knowledge that iframes and javascripts xhr requests will not fire webViewClient's shouldOverrideUrlLoading override function. I'm fine with that.
But today I learned that SOME actions such as:
JSP Page Redirects
Link Clicks within a JSP page
JSP/JS induced URL Loads
will not ALWAYS fire this function.
Hence, shouldOverrideUrlLoading() does not fire, when the webView is asked to load a page that it cannot load(i.e. "intent://...",) it shows an error page.
Has anyone encountered this kind of behaviour and is there any solution to work around it ?
Below is the code I'm using to invoke activities, where urls with 'intent:' protocol (which will fail because this function never gets called when above actions are performed)
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// ... omitted ...
if ( url.startsWith("intent:") ) {
Intent intent = null;
try {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
// The following flags launch the app outside the current app
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
try {
getActivity().startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
return true;
}
}
ps. please notice that every other websites' page loads will perfectly call shouldOverrideUrlLoading().
I couldn't find any JSP related bugs on android webViews so I'm asking one.
ps. I am happily willing to provide sample websites that some gracious readers will try on.. but the website's written in Korean so I doubt it will help.
Thank you!
Your problem might not related to JSP, the real problem may be shouldOverrideUrlLoading() itself. In this case, using shouldOverrideUrlLoading() may not be a good idea, so why not try another perspective?
I've encountered many problems when using
shouldOverrideUrlLoading() loading XmlHttpRequest. At the end, I
came up with the idea using onProgressChanged() and it solved all
my problems. I've written a similar answer here.
I tried adding your code into my own webview project and tested it with some JSP sites, and looks like it always work. I also added loadUrl() after other activities are invoked, so after pressing the back button, the loading error page will not be displayed again. So try this one :
First declare a global variable to store last URL.
String strLastUrl = null;
Then override onProgressChanged(WebView view, int progress)
mWebView.setWebChromeClient(new MyWebChromeClient(){
#Override
public void onProgressChanged(WebView view, int progress) {
if (progress == 100) {
//A fully loaded url will come here
String StrNewUrl = view.getUrl();
if(TextUtils.equals(StrNewUrl,strLastUrl)){
//same page was reloaded, not doing anything
}else{
String strOldUrl = null;
//save old url to variable strOldUrl before overwriting it
strOldURL = strLastUrl;
//a new page was loaded,overwrite this new url to variable
strLastUrl = StrNewUrl;
if ( strLastUrl.startsWith("intent:") ) {
Log.d("TAG", "intent triggered");
Intent intent = null;
try {
intent = Intent.parseUri(strLastUrl, Intent.URI_INTENT_SCHEME);
// The following flags launch the app outside the current app
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
//reload the page before invoking other activities
view.loadUrl(strOldURL);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
}
super.onProgressChanged(view, progress);
}
});
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'm new here.
I have a problem, i try to shutdown a 4.2.2 android device (not root).
I know that ACTION_SHUTDOWN not works with unroot device.
So i want to open the existing shutdown/reboot/airplane dialog, the same we get when we maintain the on/off button. Then the user just have to click shutdown button.
I try to create by this way, without result...
Intent intent = new Intent(Settings.ACTION_DISPLAY_SETTINGS); // or others settings
startActivity(intent);
Thanks,
The is no public sdk access to open the power button menu programatically.
This link has all the approches Here.Simulating power button press to display switch off dialog box
InputManager.getInstance().injectInputEvent(new InputEvent(KeyEvent.KEYCODE_POWER, keyCode), sync);
'sync' becomes either of these:
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT
and you need
import android.hardware.input.InputManager;
This is untested, but puts you in the right direction, also bare in mind, functionality like this is NOT recommend.
failing that:
public static void simulateKey(final int KeyCode) {
new Thread() {
#Override
public void run() {
try {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyCode);
} catch (Exception e) {
Log.e("Exception when sendKeyDownUpSync", e.toString());
}
}
}.start();
}
and simply call it like
simulateKey(KeyEvent.KEYCODE_POWER);
my goal is to target with a keyevent a specific application running either in foreground or background from a background service.
I tried many solutions, but have not yet managed to do it.
The few solutions tried (all from a background running service):
With a broadcast, I tried to target the first application (for example the phone app) that would manage the key event
KeyEvent lKey1Up = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_ENDCALL);
KeyEvent lKey1Dwn = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_ENDCALL);
Intent lKey1UpIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
Intent lKey1DwnIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
lKey1UpIntent.putExtra(Intent.EXTRA_KEY_EVENT, lKey1Up);
lKey1DwnIntent.putExtra(Intent.EXTRA_KEY_EVENT, lKey1Dwn );
sendOrderedBroadcast(lKey1UpIntent, null);
sendOrderedBroadcast(lKey1DwnIntent, null);
=> Nothing happens with my foreground phone app when the broadcast is performed while I am in a phone call state (OFFHOOK). Indeed, I was nearly sure this would not work since I have no way to specificely target the phone app.
With Instrumentation, I tried to target the application that has the focus :
Instrumentation lInst = new Instrumentation();
KeyEvent lKey1Up = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_1);
KeyEvent lKey1Dwn = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_1);
lInst.sendKeySync(lKey1Up);
lInst.sendKeySync(lKey1Dwn);
also tried with a single call to :
lInst.sendKeyDownUpSync(KeyEvent.KEYCODE_1)
=> Application crashes (also during phone call)
looks like I cannot use Instrumentation out of a testing purpose
Eventually, I thought about using
superDispatchKeyEvent(KeyEvent)
but since I don't know how to target a specific window from the targeted running application (and I have none in my service, indeed), I don't know how to use it at all.
And before anyone asks, I added the
android.permission.INJECT_EVENTS
android.permission.MODIY_PHONE_STATE
in my manifest in order to be sure all I do is "allowed".
Then... thanks first for reading until here, and now :
some of you know how I can manage to
do target a specific application with a
keystroke event from a service?
some of you know how to do the same with the phone application specificely?
Thanks in advance for your help.
my goal is to target with a keyevent a specific application running either in foreground or background from a background service.
This is not possible, because it is a security hole. Allowing application A to inject key events into application B raises all sorts of ugly malware possibilities.
You can use something like this, but need rooted device:
public static void inputKeyEvent(String keyCodeString) {
try {
int keyCode = Integer.parseInt(keyCodeString);
try {
Instrumentation m_Instrumentation = new Instrumentation();
m_Instrumentation.sendKeyDownUpSync(keyCode);
} catch (SecurityException e) {
try {
Process processKeyEvent = Runtime.getRuntime().exec("/system/xbin/su");
DataOutputStream os = new DataOutputStream(processKeyEvent.getOutputStream());
os.writeBytes("input keyevent " + keyCode + "\n");
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
The browser does this by calling public void emulateShiftHeld() method on the WebView which is hidden in the SDK.
Any other options?
From the class that extends WebView:
public void selectAndCopyText() {
try {
Method m = WebView.class.getMethod("emulateShiftHeld", null);
m.invoke(this, null);
} catch (Exception e) {
e.printStackTrace();
// fallback
KeyEvent shiftPressEvent = new KeyEvent(0,0,
KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT,0,0);
shiftPressEvent.dispatch(this);
}
}
And then you have to use ClipboardManager to watch for new text.
Works on Android 1.5 - 2.3. emulateShiftHeld() made public since 2.2.
This chunk of code does the exact same thing as emulateshiftheld(). It allows the user to select text. Then automatically copies it to the clipboard.
KeyEvent shiftPressEvent = new KeyEvent(0,0,
KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT,0,0);
shiftPressEvent.dispatch(portal);