I am trying to access camera through web application. If I create a WebView in XML, it is working fine. But the same doesn't work if I try to create the WebView dynamically. A blank section is coming[ Image attached below]. The Camera Streams are unable to update the view.
This is the WebView Class File
public class PageView extends WebView {
public PageView(Context context) {
super(context);
init();
}
public PageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public PageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init() {
setWebChromeClient(new CustomizedWebChromeClient());
setWebViewClient(new WebViewClient());
//File access
getSettings().setAllowFileAccessFromFileURLs(true);
getSettings().setAllowFileAccess(true);
getSettings().setAllowContentAccess(true);
getSettings().setAllowUniversalAccessFromFileURLs(true);
//Video playbacks
getSettings().setMediaPlaybackRequiresUserGesture(false);
getSettings().setJavaScriptEnabled(true);
getSettings().setDomStorageEnabled(true);
getSettings().setAppCacheEnabled(true);
setupHardwareAcceleration();
setWebContentsDebuggingEnabled(true);
}
class CustomizedWebChromeClient extends android.webkit.WebChromeClient
{
#Override
public void onPermissionRequest(PermissionRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
request.grant(request.getResources());
}
}
}
#TargetApi(11)
private void setupHardwareAcceleration() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (isHardwareAccelerated()) {
setLayerType(View.LAYER_TYPE_NONE, null);
} else {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
}}
This is the MainActivity Class
private WebView webView = null;
private String url = "https://www.onlinemictest.com/webcam-test/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addWebViewToActivity();
}
public void addWebViewToActivity() {
LinearLayout ll = (LinearLayout) findViewById(R.id.linearlayout);
WebView web = new PageView(this);
web.loadUrl("https://www.onlinemictest.com/webcam-test/");
ll.addView(web);
}
This is the result of the above code.
Note: In some websites which tests the webcam, the results of the tests are coming as normal. All the details of my webcam( Android Camera) is also coming as normal. We were even be able to take photos. But the stream from camera to view is not coming. Only as blank. Also, the number in the blank area represents the number of frames.
Found the issue.
I thought that the issue is due to the difference between creating WebView dynamically vs from XML. But the real reason for the issue is, When we create a customized WebView like
public CustomizedWebView extends WebView
and a normal object of Webview like
Webview webview = new Webview(context);
The difference between both of them is the Layer Type. Layer Type is set as "LAYER_TYPE_NONE" for webview. Because of this, I was getting blank screen.
Related
I am trying to keep the WebView media content from stopping when user exits or when screen is locked.
I follow this solutions here but it still stops the media from playing.
WebView media content stops when the screen is locked ( activity's onStop is called)
How can I make WebView keep a video or audio playing in the background?
the main bits of my code is something like this:
public class WebApp extends AppCompatActivity {
WebView webView;
WebSettings webSettings;
String ua = "Mozilla/5.0 (Linux; Android 10; Google Pixel 4 Build/QD1A.190821.014.C2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.108 Mobile Safari/537.36";
public static String url = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Objects.requireNonNull(getSupportActionBar()).hide();
getWindow().setStatusBarColor(getColor(R.color.black));
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_nitter);
webView = findViewById(R.id.webview);
webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.setWebChromeClient(new MyChrome());
webView.setWebViewClient(new MyWebViewClient());
webView.loadUrl(url);
}
public class MyWebView extends WebView {
public MyWebView(Context context) {
super(context);
}
public MyWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onWindowVisibilityChanged(int visibility) {
if (visibility != View.GONE) super.onWindowVisibilityChanged(visibility);
}
}
#Override
public void onBackPressed(){
if(webView.canGoBack())
{
webView.goBack();
}
else
{
webView.clearHistory();
super.onBackPressed();
}
}
would anyone be able to tell me what am I doing wrong even though I think I followed the solution correctly? Thank You.
When I researched the same problem, I was able to solve it as follows. https://stackoverflow.com/a/14055346
On "activity_main.xml" try to:
<org.example.myapp.MyWebView
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
This question already has answers here:
Android set height and width of Custom view programmatically
(10 answers)
Closed 2 years ago.
I am trying to resize a textbox dynamically using Java code. I want the width to not use wrap content but using a static number in dp. I want this to be done in Java code instead of the XML file. I want it like this is because I want to apply it to each item in the recyclerview. It needs to work with multiple screens sizes. It will work like a min Length for a textfield box size. If you know how to do this would be much appericaiated.
this is called auto sizing and it can be done by adding TextChangedListener which is a listener for Edit Tex. this listener watch the changes of editText and it has three different states. also you can create a component(custom view) and extend it from AppCompatTextView name as you want; in its initialization you can add below code:
public class CustomTextView extends AppCompatTextView {
Context ctx;
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
ctx = context;
init();
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
ctx = context;
init();
}
public CustomTextView(Context context) {
super(context);
ctx = context;
init();
}
public void init() {
setOnTouchListener(null);
addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (getText().toString().length() > 10){
setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSmall);
}
else if (getText().toString().length() > 5){
setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeMedium);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
also check these out, there is a tone of documentation for it:
Autosizing TextView Tutorial for Android
Autosizing TextViews
I have created a custom View that will display a circle (the idea is that the user will be able to interact with this "ball" in various ways)
From my main activity class, I want to adjust some of the "ball's" properties, in this case change its color.
My problem is that nothing happens (no errors either, the app runs but doesn't do what I want) when I try to call the various methods from my MainActivity class, but if I do it from CircleView class, it works (for example changing the color upon touch)
Here is my custom View class (CircleView.java):
public class CircleView extends View {
private int circleColor = Color.GREEN;
private Paint paint;
public CircleView(Context context) {
super(context);
init(context, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL:
this.circleColor = setRandomColor();
invalidate();
break;
case MotionEvent.ACTION_DOWN:
this.circleColor = setRandomColor();
invalidate();
break;
}
return super.onTouchEvent(event);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
paint = new Paint();
paint.setAntiAlias(true);
}
public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
invalidate();
}
public int setRandomColor() {
Random random = new Random();
int randomColor = Color.argb(255, random.nextInt(), random.nextInt(), random.nextInt());
return randomColor;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//...
//someXvalue, someYvalue, someRadius are being set here
//...
paint.setColor(circleColor);
canvas.drawCircle(someXvalue, someYvalue, someRadius, paint);
}
}
And here is my MainActivity.java class:
public class MainActivity extends Activity implements
GestureDetector.OnGestureListener {
private GestureDetectorCompat mDetector;
CircleView circle;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDetector = new GestureDetectorCompat(this, this);
circle = new CircleView(this);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
this.mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
public boolean onDown(MotionEvent event) {
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
circle.setCircleColor(circle.setRandomColor(0));
circle.invalidate();
return true;
}
}
I am new to Android development, and Java as well. I realize it could be something with the Context, which is something I have not fully understood yet. Could also be something with the TouchEvents. I am sure that someone out there can see my mistake. Any help is appreciated.
your circle view is not a part of activity's layout , it's just a object in memory which has no link to your activity screen so solutions
1.) Either set circle as Activity's view
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDetector = new GestureDetectorCompat(this, this);
circle = new CircleView(this);
setContentView(circle);
}
2.) you can create your <yourpackagename.CircleView ...attributes .../> tag in your activity_main.xml and then use findViewById to initialize it in your activity.
1)If all you want to do with gestures is on tap, just implement an onClickListener on your View instead.
2)You aren't actually using the GestureDetector anywhere. The way it works is you set an onTouchListener for the view you want to get gestures on, and send the events to the gesture detector. You aren't ever sending data for any view to the detector, so it will never do anything.
3)Not a bug just an oddness- why circle.setColor(circle.setRandomColor())? I would expect a function named setXXX to actually set XXX, rather than having to do it yourself later. Not following that convention will work, but make debugging and maintenance hard.
Edit: Also what #Pavneet_Singh said- your circle isn't in your layout anywhere, so it won't be on screen.
As title says CordovaWebView and onBackPressed in android in combination are giving weird results.
I have hybrid app. My main activity has DrawerLayout and CordovaWebView.
My onBackPressed:
#Override
public void onBackPressed(){
if(drawerIsOpen){
//close drawer
}else if(webviewIsIn){
//hide webview
}else{
super.onBackPressed();
}
}
When I use android's WebView the overridden method is called as expected. And when I change to CordovaWebView the method wouldn't even get called, instead native onBackPressed would be called instead.
I have tried overriding onKeyDown and onKeyUp but it gives me the same result, the methods are just not being called.
I'm using Cordova 2.9.0 and testing device is Galaxy Note 2, Android jellybean 4.2.2
DrawerLayout has the close on back pressed functionality I've just disabled it.
I hope you guys can understand the problem.
I encountered the same issue. My solution was to derive from CordovaWebView and override public boolean onKeyUp(int keyCode, KeyEvent event) with something like this (for Cordova 3.4.0, the code is a part of the CordovaWebView.onKeyUp(int, KeyEvent)):
public class CustomCordovaWebView extends CordovaWebView {
protected View mCustomView;
protected boolean bound;
public CustomCordovaWebView(final Context context) {
super(context);
}
public CustomCordovaWebView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public CustomCordovaWebView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
#TargetApi(11)
public CustomCordovaWebView(final Context context, final AttributeSet attrs, final int defStyle, final boolean privateBrowsing) {
super(context, attrs, defStyle, privateBrowsing);
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// If back key
if (keyCode == KeyEvent.KEYCODE_BACK) {
// A custom view is currently displayed (e.g. playing a video)
if (mCustomView!=null){
this.hideCustomView();
}else{
// The webview is currently displayed
// If back key is bound, then send event to JavaScript
if (this.bound) {
this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
return true;
} else {
// If not bound
// Go to previous page in webview if it is possible to go back
if (this.backHistory()) {
return true;
}
// If not, then invoke default behavior
else {
//this.activityState = ACTIVITY_EXITING;
//return false;
// If they hit back button when app is initializing, app should exit instead of hang until initialization (CB2-458)
// this.cordova.getActivity().finish();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this thing is closing your activity in CordovaWebView
}
}
}
} else {
return super.onKeyUp(keyCode, event);
}
return false;
}
#Override
public void hideCustomView() {
mCustomView = null;
super.hideCustomView();
}
#Override
public void showCustomView(final View view, final WebChromeClient.CustomViewCallback callback) {
mCustomView = view;
super.showCustomView(view, callback);
}
#Override
public void bindButton(final boolean override) {
bound = override;
super.bindButton(override);
}
}
If there is a better solution, I would be interested in it.
I'm coding a simple class to use SVG resource:
public class SvgImageView extends ImageView {
private int svgResourceId = 0;
public SvgImageView(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context.obtainStyledAttributes(attrs, R.styleable.SvgImageView));
}
private void parseAttributes(TypedArray a) {
this.svgResourceId = a.getResourceId(R.styleable.SvgImageView_svg, 0);
a.recycle();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
// set correct layer type
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
// set drawable
if (svgResourceId != 0)
setImageDrawable(SvgCache.getSvgPictureDrawable(getContext().getResources(), svgResourceId));
}
}
in the activity XML simply I use it:
<myapp.framework.widget.SvgImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:svg="#raw/lighting" />
Everything works fine in runtime but in editor mode, when opening the Graphical Layout panel, when parsing attributes:
this.svgResourceId = a.getResourceId(R.styleable.SvgImageView_svg, 0);
this.svgResourceId is 0, so I think it can't obtain the resource id. Why?
It may be the same situation as I had recently. To sum it up, it's because the IDE (Eclipse) processes the code with a different output method, resulting in the different display.
Here's a link to the question I had asked, hope it helps. Clearing Screen in C++/XCode