We are implementing the salesforce live agent chat in our android mobile application. Everything works fine. But we have a corner case.
Initiating the chat -> Opens chat window -> click on close button in window immediately [ within fraction of second ]. App will be crashed. Below is the log obtained from crash.
Log :
java.lang.NullPointerException: Session is not active. Unable to
create LiveAgent Request. at
com.salesforce.android.service.common.utilities.validation.Arguments.checkNotNull(Arguments.java:75)
at
com.salesforce.android.chat.core.internal.liveagent.request.InternalChatRequestFactory.checkSessionIsActive(InternalChatRequestFactory.java:104)
at
com.salesforce.android.chat.core.internal.liveagent.request.InternalChatRequestFactory.createEndRequest(InternalChatRequestFactory.java:95)
at
com.salesforce.android.chat.core.internal.liveagent.handler.EndHandler.onEndingSessionState(EndHandler.java:109)
at
com.salesforce.android.chat.core.internal.liveagent.LiveAgentChatSession.onStateChanged(LiveAgentChatSession.java:177)
at
com.salesforce.android.chat.core.internal.liveagent.LiveAgentChatSession.onStateChanged(LiveAgentChatSession.java:54)
at
com.salesforce.android.service.common.utilities.lifecycle.LifecycleEvaluator.stateChanged(LifecycleEvaluator.java:304)
at
com.salesforce.android.service.common.utilities.lifecycle.LifecycleStateWatcher$1.run(LifecycleStateWatcher.java:73)
at android.os.Handler.handleCallback(Handler.java:751) at
android.os.Handler.dispatchMessage(Handler.java:95) at
android.os.Looper.loop(Looper.java:154) at
android.app.ActivityThread.main(ActivityThread.java:6688) at
java.lang.reflect.Method.invoke(Native Method) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Is there any work around to overcome this issue. Help is appreciated.
This is how I'm doing it on my end. Hope this helps.
WebView wvBody = (WebView) findViewById(R.id.Chat_wvBody);
String url = "http://myweburl.com/chatx.html?m_email=" + accountInfo.getUserEmail() +
"&fname=" + accountInfo.getUserFirstName() +
"&lname=" + accountInfo.getUserLastName();
wvBody.getSettings().setJavaScriptEnabled(true);
wvBody.getSettings().setSaveFormData(false);
wvBody.getSettings().setDomStorageEnabled(true);
wvBody.getSettings().setBuiltInZoomControls(false);
wvBody.getSettings().setSupportZoom(false);
wvBody.getSettings().setLoadWithOverviewMode(true);
wvBody.getSettings().setUseWideViewPort(false);
if (Build.VERSION.SDK_INT >= 21) {
wvBody.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
wvBody.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap facIcon) {
avLoadingIndicatorView.setVisibility(View.VISIBLE);
tvNote.setVisibility(View.VISIBLE);
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
#Override
public void onPageFinished(WebView view, String url) {
avLoadingIndicatorView.setVisibility(View.GONE);
tvNote.setVisibility(View.GONE);
//HIDE LOADING IT HAS FINISHED
webViewLoadingFinished = true;
}
});
if (savedInstanceState != null)
wvBody.restoreState(savedInstanceState);
else
wvBody.loadUrl(url);
wvBody.setBackgroundColor(0x00000000);
Related
I'm making an async request with retrofit, on the middle of request i minimize the app and crash the app...
My log error:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1860)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:650)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:609)
at br.com.ole.oleconsignado.util.ActivityUtils.replaceFragmentToActivityWithBackStack(ActivityUtils.java:109)
at br.com.ole.oleconsignado.ui.fragment.init.LoginFragment.notifyGetProspectSuccess(LoginFragment.java:410)
at br.com.ole.oleconsignado.ui.presenter.LoginPresenter$4.onSuccess(LoginPresenter.java:91)
at br.com.ole.oleconsignado.ui.presenter.LoginPresenter$4.onSuccess(LoginPresenter.java:88)
at br.com.ole.oleconsignado.network.RestCallback.onResponse(RestCallback.java:24)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6165)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)
Here it's the method I call if the request return success:
ActivityUtils.replaceFragmentToActivityWithBackStack(getFragmentManager(), IncompleteStatusFragment.newInstance(mLogin.getCustomerId(), mCustomer, prospect, mLogin), R.id.container_login);
Can someone help me?
That is obvious, if you minimize the app then you won't be able to replace the fragment as your app is not in focus & throw java.lang.IllegalStateException. you should probable maintain a flag & in onResume of your activity if that flag is true then replace the fragment.
like
#Override
public void onPause() {
mIsActivityVisible = false;
}
#Override
public void onResume() {
mIsActivityVisible = true;
if(mShouldReplaceFragmentOnResume) {
mShouldReplaceFragmentOnResume = false;
// replace fragment
}
}
// On Success response
onSuccessOfYourCall() {
if(mIsActivityVisible) {
//replace fragment
} else {
mShouldReplaceFragmentOnResume = true;
}
}
Edit: Strangely works when duplicating the loadUrl() line
I'm working with WebViews to gather data from a webpage. Sometimes, the webview just does nothing. I tried many proposes, but actually, none of them works....
Strange: webview.loadUrl("url...") doesn't work, but as soon as I call it twice, it works...
checkLogin()
void checkLogin(final Context context) {
Log.d("checkLogin()", "Begin of checkLogin()");
WebView webview = returnNewWebView(context, false);
webview.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
Log.d("url", url);
// GOOGLE.COM ACTUALLY WORKS!
if(url.equals("https://www.google.com/"))
return;
Log.d("checkLogin()", "Loading of checkpage finished");
if(url.contains("loginto.php")) {
Log.d("checkLogin()", "User is logged out");
OnLoginCheckListener.onLoginCheckLoggedOut();
} else {
Log.d("checkLogin()", "User is logged in");
OnLoginCheckListener.onLoginCheckLoggedIn();
}
}
});
String id = sharedPref.getString("id", null);
String transid = sharedPref.getString("transid", null);
if(TextUtils.isEmpty("id") || TextUtils.isEmpty("transid")) {
Log.d("checkLogin()", "No login found, starting LoginActivity()");
Intent myIntent = new Intent(context, LoginActivity.class);
context.startActivity(myIntent);
} else {
Log.d("checkLogin()", "Probably logged in, checking by loading startpage");
webview.loadUrl("https://www.google.com");
// google actually works -.-
webview.loadUrl("https://my.login-page.com/index.php?pageid=1&id=" + id + "&transid=" + transid);
}
}
returnNewWebView()
private WebView returnNewWebView(Context context, Boolean JSInterface) {
// Prepare a webview
WebView WebView = new WebView(context);
if(JSInterface) {
WebView.getSettings().setJavaScriptEnabled(true);
WebView.addJavascriptInterface(new JavaScriptInterface(), "AndroidInterface");
}
// We don't need images for data scraping...
WebView.getSettings().setLoadsImagesAutomatically(false);
WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
// Allow cookies
CookieManager.getInstance().acceptCookie();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().acceptThirdPartyCookies(WebView);
}
// Prevent webview not loading
// or try it...
WebView.clearCache(true);
WebView.destroyDrawingCache();
return WebView;
}
As you see, I already tried some stuff in order to prevent it but still, it doesn't work. In that cases, as soon I'm going to put the loadUrl() / postUrl()twice, it works.
What can I do that it works in every single case?
I would appreciate any tip!
Thank you very much in advance
logcat (non-filtered)
I actually see this message then..
03-09 07:36:19.061 4111-24251/? E/ctxmgr: [ProducerActiveIntervalImpl]closeActiveInterval: Error: ongoing, trying to close
and this one:
03-09 07:36:28.864 29862-3249/? E/accs.GcmPush: initializeApp occur error!
java.lang.IllegalStateException: FirebaseApp name [DEFAULT] already exists!
at iv.a(Unknown Source)
at com.google.firebase.FirebaseApp.a(Unknown Source)
at com.google.firebase.FirebaseApp.a(Unknown Source)
at org.android.agoo.gcm.GcmRegister$1.run(GcmRegister.java:32)
and this one too:
E/libEGL: validate_display:99 error 3008 (EGL_BAD_DISPLAY)
But I can't tell you if they are fired by the app....
I have gone through the full code for so long and pointed out this :
You are using this -
webview.loadUrl("https://www.google.com");
// google actually works -.-
webview.loadUrl("https://my.login-page.com/index.php?pageid=1&id=" + id + "&transid=" + transid);
in your checkLogin() method which is simply wrong as because one webview can not display the two urls at same time (as you mentioned it you want to achieve that).
Now according to your code the loading of the first url is overridden by the second url.
In order to achieve the loading of two urls in same webview try to implement this using :
Threads or some sessionTimeout methods.
OR
You can achieve this by using okhttp package.
Hope this helps!
onPageFinished is called when the webpage finished loading, but not after all the javascript on the page finished running. Depending on what the page is doing and what you are trying to achieve, it might be that your code is sometimes being executed before some essential javascript is executed on that page.
It's not a pretty solution but try adding some delay (like a Handler's postDelayed() or SystemClock.sleep() - but never on the UI thread!) to your code to see if that is indeed your problem.
I am currently developing a simple RSS app for Android and one of the app's features is opening url with chrome custom tabs; I have implemented Chrome Custom Tabs based on the samples available on the docs.
While most of the urls were successfully shown by parsing it as Uri, one of the url I passed caused crashes when the custom tab tried to open, which looked something like this format:
tag:github.com,2008:PullRequestReviewCommentEvent/4172209621
I am guessing I should not just parse this String url with Uri.parse() method, but I am kind of stuck, seeking to know what to do here.
I am also guessing this is a similar question with this one:
Chrome custom tabs not opening other apps
The crash seems like there is no available activity that can handle this intent:
FATAL EXCEPTION: main
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=tag:github.com,2008:PullRequestReviewCommentEvent/4172209621 (has extras) }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1798)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1512)
at android.app.Activity.startActivityForResult(Activity.java:3930)
at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:75)
at android.app.Activity.startActivityForResult(Activity.java:3890)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:871)
at android.app.Activity.startActivity(Activity.java:4213)
at android.support.v4.app.ActivityCompatJB.startActivity(ActivityCompatJB.java:27)
at android.support.v4.app.ActivityCompat.startActivity(ActivityCompat.java:134)
at android.support.customtabs.CustomTabsIntent.launchUrl(CustomTabsIntent.java:244)
at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21155)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5422)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Below is the source code that I have written so far regarding opening an URL with Chrome Custom Tabs:
public class ArticleFragment extends Fragment {
#OnClick(R.id.button_see_more) public void onClickSeeMore() {
launchCustomTabs(article.url());
}
private CustomTabsServiceConnection customTabsConnection;
private CustomTabsClient customTabsClient;
private CustomTabsSession customTabsSession;
#Override public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
...
bindCustomTabsService();
}
#Override public void onDestroy() {
unbindCustomTabsService();
super.onDestroy();
}
private void bindCustomTabsService() {
if (customTabsClient != null) {
return;
}
customTabsConnection = new CustomTabsServiceConnection() {
#Override public void onCustomTabsServiceConnected(ComponentName componentName,
CustomTabsClient customTabsClient) {
ArticleSummaryDetailFragment.this.customTabsClient = customTabsClient;
customTabsSession = customTabsClient.newSession(new CustomTabsCallback() {
#Override public void onNavigationEvent(int navigationEvent, Bundle extras) {
Timber.wtf("onNavigationEvent: Code = " + navigationEvent);
}
});
customTabsSession.mayLaunchUrl(Uri.parse(article.originId()), null, null);
customTabsClient.warmup(0L);
}
#Override public void onServiceDisconnected(ComponentName componentName) {
customTabsClient = null;
}
};
CustomTabsClient.bindCustomTabsService(getActivity(), getActivity().getPackageName(),
customTabsConnection);
}
private void unbindCustomTabsService() {
if (customTabsConnection == null) {
return;
}
getActivity().unbindService(customTabsConnection);
customTabsClient = null;
customTabsSession = null;
}
private void launchCustomTabs(String url) {
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder(customTabsSession).build();
customTabsIntent.launchUrl(getActivity(), Uri.parse(url));
}
}
This is a general behavior of android. If the URI you are launching cannot be parsed by any individual app, then you need to handle that error gracefully. There is nothing you can do in this condition as it depends on whether or not the user has an app that can actually interpret that URI.
You need to handle that Exception. It is not a library problem. Also as chrome custom tabs, they are probably expecting a webpage link, not that kind of link. In fact, probably the only app that would probably be able to interpret that URI would be the github app.
Standard android behavior is to crash when you try to launch an intent for an activity that no app can handle.
You may be able to leverage PackageManager APIs to detect whether or not someone can handle that intent.
In my case Google Chrome Application was disabled. After enabling, it starts working.
This code work for me, i also use this for rss feed app
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(MainActivity.activity, Uri.parse(mDataSet.get(getAdapterPosition()).getPostLink()));
A few weeks ago I got the email from Google advising me to upgrade me app to 3.5.1 or risk the app being taken down.
My app is android specific and I'm building it in Android Studio so I've included the updated .jar file and updated the .js and all that stuff.
Everything seems to be fine when navigating around my included html pages but I'm running into trouble when opening an external webpage.
public class MyActivity extends CordovaActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadUrl(getString(R.string.indexURL));
}
#Override
public void init() {
final String os = "Android";
final String version = getVersion();
CordovaWebView webView = new CordovaWebView(this);
init(webView, new CordovaWebViewClient(this, webView) {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
super.onPageFinished(view, url);
boolean redirected = false;
//If the page you're accessing is the root or login page
if (url.endsWith("/Login")) {
//redirect to root page with query string
appView.loadUrl((getString(R.string.mainURL) + "?os=" + os + "&version=" + version));
redirected = true;
}
return redirected;
}
}, new CordovaChromeClient(this, webView));
}
As soon as I upgraded I commented out a few things to do with the Google analytics plugin I'm using and tested and my external urls didn't load.
MyActivity was extending from DroidGap so I updated it to extend from CordovaActivity instead but same issue is applying. I can see it hitting the Url redirecting code ut it doesn't do anything afterwards.
10-14 12:28:46.166 10958-10958/com.example.Example D/CordovaWebView﹕ >>> loadUrl(https://www.MyWebsite.com.au/Login/?os=Android&version=2.0.0)
10-14 12:28:46.166 10958-10958/com.example.Example D/PluginManager﹕ init()
10-14 12:28:46.166 10958-10958/com.example.Example D/CordovaWebView﹕ >>> loadUrlNow()
10-14 12:29:06.166 10958-10958/com.example.Example E/CordovaWebView﹕ CordovaWebView: TIMEOUT ERROR!
Does anything stand out as wrong? Thanks in advance.
Issue was a combination of the config.xml being in the wrong format with <plugin> tags rather than <feature> tags.
also changed
if (url.endsWith("/Login")) {
//redirect to root page with query string
appView.loadUrl((getString(R.string.mainURL) + "?os=" + os + "&version=" + version));
redirected = true;
}
to
if (url.endsWith("/Login")) {
//redirect to root page with query string
loadUrl((getString(R.string.mainURL) + "?os=" + os + "&version=" + version));
redirected = true;
}
I am trying to perform an action on an Android WebView after my webpage finishes loading in it. I setup my WebView to have a WebViewClient to make use of the onPageFinished event callback. However, after some testing, it does't seem to wait until all the JS on the page is done loading before my onPageFinished code fires.
The Google documentation says this:
public void onPageFinished (WebView view, String url)
Added in API level 1
Notify the host application that a page has finished loading. This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet. To get the notification for the new Picture, use onNewPicture(WebView, Picture).
Parameters
view The WebView that is initiating the callback.
url The url of the page.
1) Does onPageFinished only wait for the DOM to load?
2) Is there a way to detect when any JS on the page finishes? If so, what should I use?
I don't see anything in WebViewClient that would be for that purpose. I don't want to add a delay since my users can be on EDGE or on LTE.
You need to implement the callbacks from WebChromeClient. The onPageFinished() is an API that is provided by WebViewClient. There is yet another interface named WebChromeClient that provides the progress information you are seeking:
http://developer.android.com/reference/android/webkit/WebChromeClient.html#onProgressChanged(android.webkit.WebView, int)
Open the link above and look for onProgressChanged(WebView view, int newProgress) - the 'newProgress' variable gives you the percentage of page load that was completed. When it reaches 100 you have a valid page. onPageFinished() cannot be reliably used for this (due to server side redirections etc)
I don't know what you mean by "when JS on the page is finished". Maybe you can clarify what you meant?
From:
https://chromium.googlesource.com/chromium/src.git/+/master/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
#Override
public void didFinishNavigation(final String url, boolean isInMainFrame, boolean isErrorPage,
boolean hasCommitted, boolean isSameDocument, boolean isFragmentNavigation,
Integer pageTransition, int errorCode, String errorDescription, int httpStatusCode) {
...
if (client != null && isFragmentNavigation) {
client.getCallbackHelper().postOnPageFinished(url);
}
}
#Override
public void didFailLoad(
boolean isMainFrame, int errorCode, String description, String failingUrl) {
AwContentsClient client = mAwContentsClient.get();
if (client == null) return;
String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
boolean isErrorUrl =
unreachableWebDataUrl != null && unreachableWebDataUrl.equals(failingUrl);
if (isMainFrame && !isErrorUrl && errorCode == NetError.ERR_ABORTED) {
// Need to call onPageFinished for backwards compatibility with the classic webview.
// See also AwContents.IoThreadClientImpl.onReceivedError.
client.getCallbackHelper().postOnPageFinished(failingUrl);
}
}
#Override
public void didStopLoading(String validatedUrl) {
if (validatedUrl.length() == 0) validatedUrl = ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL;
AwContentsClient client = getClientIfNeedToFireCallback(validatedUrl);
if (client != null && validatedUrl.equals(mLastDidFinishLoadUrl)) {
client.getCallbackHelper().postOnPageFinished(validatedUrl);
mLastDidFinishLoadUrl = null;
}
}
We can easily see that onPageFinished is not pretty much what you're expecting.
To answer your first question: I have found that onProgressChanged will not reach 100, and onPageFinished will not be called until all of the assets (css/js/images) have finished loading for that page.
I can not, however, find any official documentation that states that.