I'm trying to use custom WebChromeClient, but for some URL's in android marshmallow and nougat it show's me below error in logcat and don't load URL, but it's working fine for pre marshmallow.
The error:
W/cr_AwContentsClient: Denied starting an intent without a user
gesture
What is the meaning the error? How should I handle it?
The webview:
#SuppressLint("SetJavaScriptEnabled")
public class MyWebView extends BaseWebView {
public BrowserWebView(Context context, AttributeSet attrs) {
super(context, attrs);
getSettings().setJavaScriptEnabled(true);
setWebChromeClient(new WebChromeClient());
}
}
The activity :
public class MyActivity extends Activity {
private MyWebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_browser);
webView = (MyWebView) findViewById(R.id.my_web_view);
webView.loadUrl("https://.../");
}
#Override
public void onBackPressed() {
// Check if the key event was the Back button and if there's history
if (webView != null && webView.canGoBack()) {
webView.goBack();
return;
}
super.onBackPressed();
}
}
Activity layout XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.activity.MyActivity">
<com.test.MyWebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/my_web_view"/>
</RelativeLayout>
Related
I have activity and when it is created it sends some requests, so it takes time to load this activity.
Is it possible to show "loading layout" while requests are proceeding?
I tried something like this, but it doesn't work:
setContentView(R.layout.loading);
sendRequests();
setContentView(R.layout.main);
To accomplish this, you could add a "loading layout" to your main layout.
Something like this:
<FrameLayout
android:id="#+id/loading_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Loading stuff" />
</FrameLayout>
Then when it is time to show your loading layout you can do:
FrameLayout loadingLayout = findViewById(R.id.loading_layout);
loadingLayout.setVisibility(View.VISIBLE);
When you want to hide it simply:
loadingLayout.setVisibility(View.GONE);
You will want to make sure that you do network requests off of the main thread, and return to the main thread whenever it is time to update the UI (i.e. show/hide the loading layout).
You can add a progress bar in activity or fragment.
If you are using Retrofit or etc., use this approach:
Set the progressbar visible before request
and invisible it when onResponse or onFailure called
binding.progressBar.setVisibility(View.VISIBLE);
// request
call.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Response<MovieResponse> response) {
Log.d(TAG, "onResponse is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
if (!response.isSuccess()) {
Log.d(TAG, "No Success");
}
mMovieList = response.body().getMovies(); // <- response is null here
mMovieAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(Throwable t) {
Log.i(TAG, "onFailure is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(getActivity(), "Failed !", Toast.LENGTH_LONG).show();
}
});
You can create common class for custom progress dialog,
public class CustomProgressDialog extends Dialog {
public CustomProgressDialog(#NonNull Context context) {
super(context);
init(context);
}
public CustomProgressDialog(#NonNull Context context, int themeResId) {
super(context, themeResId);
init(context);
}
protected CustomProgressDialog(#NonNull Context context, boolean cancelable, #Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
init(context);
}
void init(Context context) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().getRootView().setBackgroundResource(android.R.color.transparent);
getWindow().setDimAmount(0.1f);
getWindow().getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
insets.consumeSystemWindowInsets();
return insets;
});
View view = LayoutInflater.from(context).inflate(
R.layout.dialog_custom, null
);
setContentView(view);
setCancelable(false);
setCanceledOnTouchOutside(false);
}
}
dialog_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:indeterminateTint="#color/colorPrimary" />
</RelativeLayout>
Declare this class in your activity or parent activity to use in every child classes,
public class BaseFragment extends Fragment {
protected CustomProgressDialog mDialog;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialog = new CustomProgressDialog(requireActivity());
}
}
To show dialog before your api call
mDialog.show();
To dismiss dialog in response or error
mDialog.dismiss();
navigation openI build android app that open different website in web view but when i am open Walmart website i face problem on website navigation bar when i scroll down my website navigation bar not going on top it's perfrom swipe to refresh.
Scroll for going on top of navigation top but not scroll going swipe to refresh
my xml file is:--
`<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeContainer"
android:layout_width="match_parent"
android:layout_below="#+id/progressBar"
android:layout_height= "match_parent">
<WebView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webView1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>`
My java code is :--
public class MainActivity extends AppCompatActivity {
private WebView myWebView;
Context context;
Toolbar toolbar;
ProgressBar progressBar;
SwipeRefreshLayout mySwipeRefreshLayout;
WebSettings settings;
RelativeLayout relativeLayout;
#SuppressLint("SetJavaScriptEnabled")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.webView1);
myWebView.setWebViewClient(new WebViewClientDemo());
myWebView.setWebChromeClient(new WebChromeClientDemo());
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.loadUrl("https://www.walmart.com/");
myWebView.getSettings().setDomStorageEnabled(true);
mySwipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.swipeContainer);
mySwipeRefreshLayout.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
myWebView.reload();
}
}
);
mySwipeRefreshLayout.setNestedScrollingEnabled(false);
sorry for bad English
thank you in advance.
Step 1: You have to see the scroll position, if it is completely swiped down, ie when y position is zero do refresh.
Step 2: You can do it by using canChileScrollUp() method
This is a custom refreshlayout which has a function "canChildScrollUp" detects weather to refresh or not, if it returns false it will not refresh.
"canSwipeRefreshChildScrollUp" is place where u will write your logic in activity. in ur case use custom webview and detect the scroll position and if the scroll is completely done then only return true
public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {
private CanChildScrollUpCallback mCanChildScrollUpCallback;
public interface CanChildScrollUpCallback {
boolean canSwipeRefreshChildScrollUp();
}
public void setCanChildScrollUpCallback(CanChildScrollUpCallback canChildScrollUpCallback) {
mCanChildScrollUpCallback = canChildScrollUpCallback;
}
#Override
public boolean canChildScrollUp() {
if (mCanChildScrollUpCallback != null) {
return mCanChildScrollUpCallback.canSwipeRefreshChildScrollUp();
}
return super.canChildScrollUp();
}
}
In your Activity
public class YourActivity implements CustomSwipeRefreshLayout.CanChildScrollUpCallback {
private CustomSwipeRefreshLayout mRefreshLayout;
private WebView mWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
// after initialization
mRefreshLayout.setCanChildScrollUpCallback(this);
}
#Override
public boolean canSwipeRefreshChildScrollUp() {
return mWebview.getScrollY() > 0;
}
}
TO detect nested scroll you can use this
public class MyWebView extends WebView{
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
if(clampedX || clampedY){
//Content is not scrolling
//TODO Enable SwipeRefreshLayout
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getActionMasked()==MotionEvent.ACTION_UP){
//TODO Disable SwipeRefreshLayout
}
}
}
I found this link that states how I could make the glow effect on my ImageButton. So whenever the user press the ImageButton the onTouchEvent() function is called and there I call the setImageBitmap() function. The problem is this function (setImageBitmap()) seems to have no effect at all.
What works:
1) So far I extended the ImageButton as below
// Pen.java
public class Pen extends ImageButton {
public Pen(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("Now I am setting Pen");
return true;
}
}
Then inside Activity I create Pen (custom ImageButton) instance, define setGlow() and call setImageBitmap() from instance of Pen.
//MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Pen myImgbutton;
myImgbutton = (Pen) findViewById(R.id.pen);
myImgbutton.setImageBitmap(setGlow(R.drawable.pen));
}
}
public Bitmap setGlow(int resourceId) {
......
}
What doesn't work:
1) All same as above ( extending a ImageButton in android ), but this time I am calling the
setImageBitmap function from inside onTouchEvent(). For this case I have define setGlow function in inside Pen.java
// Pen.java
public class Pen extends ImageButton {
public Pen(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("Now I am setting Pen");
// Here I say to apply the glow effect to the image
setImageBitmap(setGlow(R.drawable.pen));
return true;
}
public Bitmap setGlow(int resourceId) {
....
}
}
Then in xml file I do :
.....
<com.example.testsetimagebmp.Pen
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/pen"
android:background="#drawable/pen" />
....
Finally in MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// ....
}
I think this might be the classic out of memory issue. You can try to use the bitmap of the launcher icon if you want to check whether this is true:
public class Pen extends ImageButton {
public Pen(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("Now I am setting Pen");
// Here I say to apply the glow effect to the image
setImageBitmap(setGlow(R.mipmap.ic_launcher));
return true;
}
public Bitmap setGlow(int resourceId) {
....
}
}
If this is the problem check this link.
You can't do that because you will out of memory if you put setImageBitmap(setGlow(R.drawable.pen)) in onTouchEvent.
onTouchEvent will be triggered serval times per second.And you will create serval bitmaps in memory per second.It will out of memory before you setImageBitmap successfully.
I built the project as you post, but it works fine. It sets the Bitmap correctly. So maybe the getGlow() method doesn't work well. Make some Logs as below
public Bitmap setGlow(int resourceId) {
Bitmap bm = BitmapFactory.decodeResource(getResources(),resourceId);
Log.e("tag", "Size: " + bm.getByteCount());
return bm;
}
then check whether the return is right.
When I declare and try to get a reference to my button, which I declare in XML, the app won't open and I don't know why. PLEASE try to explain to me why not -- don't just give a link.
Here's the code:
public class MainActivity extends AppCompatActivity {
final String stream="<iframe width=\"300\" height=\"193\" src=\"http://cdn.livestream.com/embed/sl48?layout=4&color=0xffad4b&autoPlay=true&mute=false&iconColorOver=0xe17b00&iconColor=0xb96500&allowchat=true&height=193&width=300\" style=\"border:0;outline:0\" frameborder=\"0\" scrolling=\"no\"></iframe>";
// Button button = (Button) findViewById(R.id.home);
//final Button button1 = (Button) findViewById(R.id.stream);
//final Button button2 = (Button) findViewById(R.id.contatti);
WebView custumWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
custumWebView = (WebView) findViewById(R.id.webView);
custumWebView.loadData(stream, "text/html", null);
custumWebView.getSettings().setJavaScriptEnabled(true);
custumWebView.getSettings().setLoadsImagesAutomatically(true);
custumWebView.clearHistory();
custumWebView.clearCache(true);
custumWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
public class CustomWebView extends WebView {
public CustomWebView (Context context) {
super( context );
init();
}
public CustomWebView (Context context, AttributeSet attrs) {
super( context, attrs );
init();
}
public CustomWebView (Context context, AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
init();
}
public CustomWebView (Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
super( context, attrs, defStyle, privateBrowsing );
init();
}
protected void init () {
getSettings().setJavaScriptEnabled( true );
setWebViewClient( new CustomWebViewClient() );
setDownloadListener( new CustomDownloadListener() );
}
protected boolean overrideUrlLoading (WebView view, String url) {
// ANY CUSTOM LOGIC GOES HERE
view.loadUrl(url);
return true;
}
protected void pageFinished (WebView view, String url) {
}
protected void downloadStarted(String url, String mimetype) {
try {
//Start new activity to load the specific url
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimetype);
getContext().startActivity(intent);
//custumWebView.loadData(stream, "text/html", null);
} catch (Exception exception) {
exception.printStackTrace();
}
}
/**
* Default webview client.
*/
protected class CustomWebViewClient extends WebViewClient {
/**
* Constructor, default.
*/
public CustomWebViewClient () {
}
#Override
public boolean shouldOverrideUrlLoading (WebView view, String url) {
return overrideUrlLoading( view, url );
}
#Override
public void onPageFinished (WebView view, String url) {
pageFinished(view, url);
}
}
protected class CustomDownloadListener implements DownloadListener {
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
downloadStarted(url, mimetype);
}
}
}
and here the xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<WebView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/webView"
android:layout_below="#+id/stream"
android:layout_alignRight="#+id/stream"
android:layout_alignEnd="#+id/stream"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="#+id/imageView" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home"
android:id="#+id/home"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="stream"
android:id="#+id/stream"
android:layout_alignTop="#+id/home"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Contatti"
android:id="#+id/contatti"
android:layout_above="#+id/webView"
android:layout_centerHorizontal="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:minHeight="50dp"
android:minWidth="400dp" />
</RelativeLayout>
The CustomWebView class is so I don't get errors with loadData for the streaming site. I don't know why this class is working but it is. I copied it from the livestream support site, I'm only a newbie and I'm trying to learn.
If you're referring to these two lines of code at the top of your class:
// Button button = (Button) findViewById(R.id.home);
//final Button //final Button button2 = (Button) findViewById(R.id.contatti);
That will not work in that location. Those buttons are created in your XML layout. You cannot get a reference to a button declared in an XML layout before you first call setContentView() in your onCreate() method. You must do this.
This is what you need to do:
public class MainActivity extends AppCompatActivity {
private Button mButton;
private Button mButton1;
private Button mButton2;
// declare any other fields you require
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.home);
mButton1 = (Button) findViewById(R.id.stream);
mButton2 = (Button) findViewById(R.id.contatti);
// Your other initialization code
}
Please note that you cannot declare those Buttons as final fields, as they are not instantiated in a constructor (onCreate() is not a constructor).
I am developing an application in which I would like to create different webViews in some conditions. Despite having more than one webView, the idea is to show only one of them.
I have seen that the best way is create a new class which extends Activity.
This is the main class
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = new Intent(this, WebScreen.class);
startActivity(intent);
}
This is the second class I have done to create new Webviews
public class WebScreen extends Activity {
private WebView myWebView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_PROGRESS);
}
public void onClick(View arg0) {
return;
}
#Override
protected void onPause() {
myWebView = null;
super.onPause();
}
#Override
protected void onStart(){
}
#Override
protected void onResume() {
super.onResume();
myWebView = new WebView(this);
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.loadUrl("myURL");
setContentView(myWebView);
}
#Override
public void onBackPressed() {
super.onBackPressed();
myWebView = null;
}
In the same way you have used a layout on your first activity setContentView(R.layout.main);. You have to set another layout on the WebScreen.onCreate. p.e.
myweblayout.xml
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
Set it at onCreate
setContentView(R.layout.myweblayout)
And get the tag from the activity using
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
I suggest you to read Building Web Apps in WebView
You can create two webviews in the same activity and same xml file,just keep the visibility of one of the views as gone and one as visible .You can always switch between the views by changing the visibilities.