Transition gives flicker when splash screen calls "finish()" after startActivity(intent, options.toBundle()); - android-5.0-lollipop

I am creating an android app (lollipop version). App shows large logo in middle of splash screen. Login screen contains a small sized logo at top. I use ActivityOptions.makeSceneTransitionAnimation() to set animation from large logo of splash screen to small logo of login screen.
Splash screen launches to launch app. After delay of few milisec , splash screen creates intent for login screen. Also set transition. Then it starts login activity. It begins transition animation of logo. And shows login screen successfully. Everything is working well and animation is smooth up to this point.
Then I added "finish();" in splash screen so that back button on login screen do not loads splash screen. Now transition was giving flicker.
I tried following approach but still flicker is there.
used "finishAfterTransition();" instead of "finish();"
added FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_NEW_TASK flags to intent (this leads to even wired behavior)
Override onBackPressed() in login screen. and added
finish();
android.os.Process.killProcess(android.os.Process.myPid()); - This terminates app but restarts it again.
Here, I'm pasting the code of splashScreen. This code is working but gives flicker while transition. gotoLoginScreen() method at the end of class is the place which loads login activity. The login screen is basic activity template from android studio. Using com.android.support:appcompat-v7:21.0.2 library to support lower devices.
public class SplashActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_splash, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
ImageView imageView_logo;
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_splash, container, false);
imageView_logo = (ImageView) rootView.findViewById(R.id.imageview_logo);
imageView_logo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startTimer();
}
});
startTimer();
return rootView;
}
private void startTimer() {
new CountDownTimer(1000, 1000) {
#Override
public void onTick(long l) {
}
public void onFinish() {
launchNextActivity();
}
}.start();
}
/**
* base on session continuity the next activity will be decided and
* launches next activity
*/
private void launchNextActivity() {
if (isSessionContinue()) {
goToHomeScreen();
} else {
goToLoginScreen();
}
}
/**
* checks current user ID, null indicate terminated session
*
* #return true if session is continued and false of session is terminated
*/
private boolean isSessionContinue() {
return false;
}
/**
* directly leads to home screen
*/
private void goToHomeScreen() {
//code to start home screen by skipping login
}
/**
* leads to login screen.
*/
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
**private void goToLoginScreen() {
Intent loginIntent = new Intent(getActivity(), LoginActivity.class);
if (android.os.Build.VERSION.SDK_INT >= 21) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(getActivity(), imageView_logo, getString(R.string.transition_logo));
getActivity().startActivity(loginIntent, options.toBundle());
getActivity().finishAfterTransition();
} else {
startActivity(loginIntent);
getActivity().finish();
}
}**
}
}
Is there any way to avoid flicker? It is a stain on beauty.

add this to your activity:
private boolean shouldFinish = false;
#Override
public void onStop() {
super.onStop();
if (shouldFinish) {
getActivity().finish();
}
}
and change this:
private void goToLoginScreen() {
shouldFinish = true;
Intent loginIntent = new Intent(getActivity(), LoginActivity.class);
if (android.os.Build.VERSION.SDK_INT >= 21) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(getActivity(), imageView_logo, getString(R.string.transition_logo));
getActivity().startActivity(loginIntent, options.toBundle());
} else {
startActivity(loginIntent);
}
}

Related

How to expand the view while zooming an image into ViewPager2

I was trying, with ViewPager2, to get default gallery-like experience of common Android SmartPhone, where you can zoom an image with pan and pinch controls along with the ability to navigate to another photo by swipe gestures.
I faced a problem in which when the zoomed image is swiped expecting it to get panned, instead of that, the ViewPager2 switched to another page.
ViewPager2 responds to the swipe event and causes page change and it doesn’t let zoomable view to respond to that event.
How do I solve the problem? Thanks.
The only solution I found is to use the old ViewPager with which it is possible to intercept events and if the photo is enlarged, it is possible to disable the page change and allow the management of the zoom.
First I defined a field, in a static class, to keep track of the state the photo is in:
public class Utilities {
....
static boolean isZoomed;
private Utilities () { }
static public void setIsZoomed (boolean z) {
isZoomed = z;
}
static public boolean getIsZoomed () {
return isZoomed;
}
....
}
Then in the custom class for managing the zoom I detect the status of the photo:
public class TouchImageView extends ImageView {
...
Utilities.setIsZoomed(normalizedScale != 1);
...
}
Finally, in the ViewPager custom class I disable or allow pagination based on the state of the photo:
public class CustomViewPager extends ViewPager {
public CustomViewPager (Context context) {
super(context);
}
public CustomViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent (MotionEvent ev) {
try {
if (Utilities.getIsZoomed())
return false;
else
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
return false;
}
}
}

how to do a button click in Xamarin Forms Android custom info window

In my Xamarin Forms Android project I am showing a Map using CustomMapRenderer. I am popping up a Info Window in Map screen and this info window has button name called "Call". I need to do a "OnCLick" button click operation for this button. I have googled it, but unfortunately I didn't come across any solutions. at last I have started to work on converting the Android Native code -Java into Xamarin Forms Android - c#, for this conversion I have been using this answers Google Maps Android API v2 - Interactive InfoWindow (like in original android google maps) . This converted code shows A field initializer cannot reference the non static field, method or property OnInfoWindowElemTouchListener.onClickConfirmed(view, marker) this Error inside Java.Lang.Runnable please help me to resolve the problem.
OnInfoWindowElemTouchListener.cs
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Gms.Maps.Model;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Views;
using Android.Views.Accessibility;
using Java.Lang;
namespace Hotel.Droid
{
public abstract class OnInfoWindowElemTouchListener : Java.Lang.Object
, View.IOnTouchListener
{
private View view;
private Drawable bgDrawableNormal;
private Drawable bgDrawablePressed;
private Handler handler = new Handler();
private Marker marker;
private static bool endPressStatus = false;
private bool pressed = false;
public OnInfoWindowElemTouchListener(View view, Drawable bgDrawableNormal, Drawable bgDrawablePressed)
{
this.view = this.view;
this.bgDrawableNormal = this.bgDrawableNormal;
this.bgDrawablePressed = this.bgDrawablePressed;
}
public OnInfoWindowElemTouchListener()
{
}
public void setMarker(Marker marker)
{
this.marker = this.marker;
}
public bool OnTouch(View vv, MotionEvent e)
{
if (0 <= e.GetX() && e.GetX() <= vv.Width && 0 <= e.GetY() && e.GetY() <= vv.Height)
{
switch (e.ActionMasked)
{
case MotionEventActions.Down:
startPress();
break;
// We need to delay releasing of the view a little so it shows the
// pressed state on the screen
case MotionEventActions.Up:
//handler.PostDelayed(ConfirmClickRunnable, 150);
Task.Factory.StartNew(() => onClickConfirmed(view, marker));
Task.Delay(150);
break;
case MotionEventActions.Cancel:
endPress();
break;
default:
break;
}
}
else {
// If the touch goes outside of the view's area
// (like when moving finger out of the pressed button)
// just release the press
endPress();
}
return false;
}
private void startPress()
{
if (!pressed)
{
pressed = true;
//handler.RemoveCallbacks(ConfirmClickRunnable);
view.SetBackgroundDrawable(bgDrawablePressed);
if ((marker != null))
{
marker.ShowInfoWindow();
}
}
}
public bool endPress()
{
if (pressed)
{
this.pressed = false;
handler.RemoveCallbacks(ConfirmClickRunnable);
view.SetBackgroundDrawable(bgDrawableNormal);
if ((marker != null))
{
marker.ShowInfoWindow();
}
endPressStatus = true;
return true;
}
else {
endPressStatus = false;
return false;
}
}
private Runnable ConfirmClickRunnable = new Java.Lang.Runnable(() =>
{
if (endPressStatus)
{
onClickConfirmed(view, marker);
}
});
/*private class RunnableAnonymousInnerClassHelper : Java.Lang.Object, Java.Lang.IRunnable
{
private readonly Context outerInstance;
public RunnableAnonymousInnerClassHelper(Context outerInstance)
{
this.outerInstance = outerInstance;
}
public void Run()
{
if (endPressStatus)
{
onClickConfirmed();
}
}
}*/
protected abstract void onClickConfirmed(View v, Marker marker);
}
}
Updated
I have implemented the Task.Factory.StartNew instead of Android Runnableand now I am stucking on the below lines. I am struggling on converting this below Java codes into C#since it is written by Anonymous class concept.
Java
this.infoButtonListener = new OnInfoWindowElemTouchListener(infoButton,
getResources().getDrawable(R.drawable.btn_default_normal_holo_light),
getResources().getDrawable(R.drawable.btn_default_pressed_holo_light))
{
#Override
protected void onClickConfirmed(View v, Marker marker) {
// Here we can perform some action triggered after clicking the button
Toast.makeText(MainActivity.this, marker.getTitle() + "'s button clicked!", Toast.LENGTH_SHORT).show();
}
};
this.infoButton.setOnTouchListener(infoButtonListener);
infoButton in code is Call button
C# - Please help me to resolve the problem by converting/using(How to use) the above java code
The solution is too complicated for this window. Please see chat room for step by step solution.
https://chat.stackoverflow.com/rooms/128847/discussion-between-jamal-and-yuri-s

Vaadin Drag Drop Component

We are creating a web application using Vaadin. Our application contains alot of drag and drop features.
We have an object which is drag-able.
We can click on it to open its menu as well.
Sometimes that when we click that item it behaves as if it is dragged.
When this happens we are unable to open its menu because the component is in dragmode.
All components with the same functionality behave the same however in development environment, when we restart the tomcat the problem disappeared?
I noticed that when the components start showing me this behavior the webpage in FireFox the behavior is fine there?
A simple solution to this could be to introduce a drag mode/edit button which would allow the user to switch the drag mode on and off.
This would mean the user could interact with the components and then enter this "drag mode" when they wished to drag them. Hence reducing the frustration of trying to interact with the component and it starting to "drag" instead.
I've create a simple example program to try out below.
public class DemoUI extends UI {
HorizontalSplitPanel splitPanel;
DragAndDropWrapper wrapperA;
DragAndDropWrapper wrapperB;
DragAndDropWrapper splitPaneWrapper;
Button buttonA;
Button buttonB;
private boolean isDragMode = false;
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = DemoUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
Button buttonA = new Button("Button A");
Button buttonB = new Button("Button B");
final DragAndDropWrapper wrapperA = new DragAndDropWrapper(buttonA);
final DragAndDropWrapper wrapperB = new DragAndDropWrapper(buttonB);
final VerticalLayout leftPanel = new VerticalLayout();
final VerticalLayout rightPanel = new VerticalLayout();
DragAndDropWrapper leftPanelWrapper = new DragAndDropWrapper(leftPanel);
DragAndDropWrapper rightPanelWrapper = new DragAndDropWrapper(rightPanel);
buttonA.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Notification.show("Button A was clicked");
}
});
buttonB.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Notification.show("Button B was clicked");
}
});
leftPanelWrapper.setDropHandler(new DropHandler() {
#Override
public void drop(DragAndDropEvent event) {
leftPanel.addComponent(event.getTransferable().getSourceComponent());
}
#Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
});
rightPanelWrapper.setDropHandler(new DropHandler() {
#Override
public void drop(DragAndDropEvent event) {
rightPanel.addComponent(event.getTransferable().getSourceComponent());
}
#Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
});
final Button dragMode = new Button("Drag Mode On");
dragMode.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
isDragMode = !isDragMode;
if (isDragMode) {
dragMode.setCaption("Drag Mode Off");
wrapperA.setDragStartMode(DragStartMode.WRAPPER);
wrapperB.setDragStartMode(DragStartMode.WRAPPER);
} else {
dragMode.setCaption("Drag Mode On");
wrapperA.setDragStartMode(DragStartMode.NONE);
wrapperB.setDragStartMode(DragStartMode.NONE);
}
}
});
leftPanel.setSizeFull();
rightPanel.setSizeFull();
leftPanelWrapper.setSizeFull();
rightPanelWrapper.setSizeFull();
leftPanel.addComponent(wrapperA);
rightPanel.addComponent(wrapperB);
splitPanel.setFirstComponent(leftPanelWrapper);
splitPanel.setSecondComponent(rightPanelWrapper);
splitPanel.setSizeFull();
VerticalLayout layout = new VerticalLayout();
layout.addComponent(dragMode);
layout.addComponent(splitPanel);
layout.setSizeFull();
this.setContent(layout);
this.setSizeFull();
}
.
All the best.

Android HTML5 video fullscreen and rotation

i read the article
Android WebView: handling orientation changes
and follow the tip i build a project
MainActivity
package com.example.testvideo1;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.WebView;
import android.os.Build;
#SuppressLint("NewApi")
public class MainActivity extends ActionBarActivity {
private VideoEnabledWebView webView;
private VideoEnabledWebChromeClient webChromeClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set layout
setContentView(R.layout.activity_main);
// Save the web view
webView = (VideoEnabledWebView) findViewById(R.id.webView);
// Initialize the VideoEnabledWebChromeClient and set event handlers
View nonVideoLayout = findViewById(R.id.nonVideoLayout);
// Your own view,
//Your own view,
ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout);
View loadingView = null; // Your own view, read class comments
webChromeClient = new VideoEnabledWebChromeClient(nonVideoLayout,
videoLayout, loadingView, webView) // See all available
// constructors...
{
// Subscribe to standard events, such as onProgressChanged()...
#Override
public void onProgressChanged(WebView view, int progress) {
// Your code...
}
};
webChromeClient
.setOnToggledFullscreen(new VideoEnabledWebChromeClient.ToggledFullscreenCallback() {
#Override
public void toggledFullscreen(boolean fullscreen) {
// Your code to handle the full-screen change, for
// example showing and hiding the title bar. Example:
if (fullscreen) {
WindowManager.LayoutParams attrs = getWindow()
.getAttributes();
attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
getWindow().setAttributes(attrs);
if (android.os.Build.VERSION.SDK_INT >= 14) {
getWindow()
.getDecorView()
.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
} else {
WindowManager.LayoutParams attrs = getWindow()
.getAttributes();
attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
getWindow().setAttributes(attrs);
if (android.os.Build.VERSION.SDK_INT >= 14) {
getWindow().getDecorView()
.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_VISIBLE);
}
}
}
});
webView.setWebChromeClient(webChromeClient);
// Navigate everywhere you want, this classes have only been tested on
// YouTube's mobile site
webView.loadUrl("http://app.vlooks.cn/webchat/html5/2300/home");
}
#Override
public void onBackPressed() {
// Notify the VideoEnabledWebChromeClient, and handle it ourselves if it
// doesn't handle it
if (!webChromeClient.onBackPressed()) {
if (webView.canGoBack()) {
webView.goBack();
} else {
// Close app (presumably)
super.onBackPressed();
}
}
}
}
follow is VideoEnabledWebChromeClient.java
package com.example.testvideo1;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebChromeClient;
import android.widget.FrameLayout;
/**
* This class serves as a WebChromeClient to be set to a WebView, allowing it to
* play video. Video will play differently depending on target API level
* (in-line, fullscreen, or both).
*
* It has been tested with the following video classes: -
* android.widget.VideoView (typically API level <11) -
* android.webkit.HTML5VideoFullScreen$VideoSurfaceView/VideoTextureView
* (typically API level 11-18) -
* com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView
* (typically API level 19+)
*
* Important notes: - For API level 11+, android:hardwareAccelerated="true" must
* be set in the application manifest. - The invoking activity must call
* VideoEnabledWebChromeClient's onBackPressed() inside of its own
* onBackPressed(). - Tested in Android API levels 8-19. Only tested on
* http://m.youtube.com.
*
* #author Cristian Perez (http://cpr.name)
*
*/
public class VideoEnabledWebChromeClient extends WebChromeClient implements
OnPreparedListener, OnCompletionListener, OnErrorListener {
public interface ToggledFullscreenCallback {
public void toggledFullscreen(boolean fullscreen);
}
private View activityNonVideoView;
private ViewGroup activityVideoView;
private View loadingView;
private VideoEnabledWebView webView;
private boolean isVideoFullscreen; // Indicates if the video is being
// displayed using a custom view
// (typically full-screen)
private FrameLayout videoViewContainer;
private CustomViewCallback videoViewCallback;
private ToggledFullscreenCallback toggledFullscreenCallback;
/**
* Never use this constructor alone. This constructor allows this class to
* be defined as an inline inner class in which the user can override
* methods
*/
#SuppressWarnings("unused")
public VideoEnabledWebChromeClient() {
}
/**
* Builds a video enabled WebChromeClient.
*
* #param activityNonVideoView
* A View in the activity's layout that contains every other view
* that should be hidden when the video goes full-screen.
* #param activityVideoView
* A ViewGroup in the activity's layout that will display the
* video. Typically you would like this to fill the whole layout.
*/
#SuppressWarnings("unused")
public VideoEnabledWebChromeClient(View activityNonVideoView,
ViewGroup activityVideoView) {
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = null;
this.webView = null;
this.isVideoFullscreen = false;
}
/**
* Builds a video enabled WebChromeClient.
*
* #param activityNonVideoView
* A View in the activity's layout that contains every other view
* that should be hidden when the video goes full-screen.
* #param activityVideoView
* A ViewGroup in the activity's layout that will display the
* video. Typically you would like this to fill the whole layout.
* #param loadingView
* A View to be shown while the video is loading (typically only
* used in API level <11). Must be already inflated and without a
* parent view.
*/
#SuppressWarnings("unused")
public VideoEnabledWebChromeClient(View activityNonVideoView,
ViewGroup activityVideoView, View loadingView) {
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = loadingView;
this.webView = null;
this.isVideoFullscreen = false;
}
/**
* Builds a video enabled WebChromeClient.
*
* #param activityNonVideoView
* A View in the activity's layout that contains every other view
* that should be hidden when the video goes full-screen.
* #param activityVideoView
* A ViewGroup in the activity's layout that will display the
* video. Typically you would like this to fill the whole layout.
* #param loadingView
* A View to be shown while the video is loading (typically only
* used in API level <11). Must be already inflated and without a
* parent view.
* #param webView
* The owner VideoEnabledWebView. Passing it will enable the
* VideoEnabledWebChromeClient to detect the HTML5 video ended
* event and exit full-screen. Note: The web page must only
* contain one video tag in order for the HTML5 video ended event
* to work. This could be improved if needed (see Javascript
* code).
*/
public VideoEnabledWebChromeClient(View activityNonVideoView,
ViewGroup activityVideoView, View loadingView,
VideoEnabledWebView webView) {
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = loadingView;
this.webView = webView;
this.isVideoFullscreen = false;
}
/**
* Indicates if the video is being displayed using a custom view (typically
* full-screen)
*
* #return true it the video is being displayed using a custom view
* (typically full-screen)
*/
public boolean isVideoFullscreen() {
return isVideoFullscreen;
}
/**
* Set a callback that will be fired when the video starts or finishes
* displaying using a custom view (typically full-screen)
*
* #param callback
* A VideoEnabledWebChromeClient.ToggledFullscreenCallback
* callback
*/
public void setOnToggledFullscreen(ToggledFullscreenCallback callback) {
this.toggledFullscreenCallback = callback;
}
#Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if (view instanceof FrameLayout) {
// A video wants to be shown
FrameLayout frameLayout = (FrameLayout) view;
View focusedChild = frameLayout.getFocusedChild();
// Save video related variables
this.isVideoFullscreen = true;
this.videoViewContainer = frameLayout;
this.videoViewCallback = callback;
// Hide the non-video view, add the video view, and show it
activityNonVideoView.setVisibility(View.INVISIBLE);
activityVideoView.addView(videoViewContainer, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
activityVideoView.setVisibility(View.VISIBLE);
if (focusedChild instanceof android.widget.VideoView) {
// android.widget.VideoView (typically API level <11)
android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;
// Handle all the required events
videoView.setOnPreparedListener(this);
videoView.setOnCompletionListener(this);
videoView.setOnErrorListener(this);
} else {
// Other classes, including:
// - android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which
// inherits from android.view.SurfaceView (typically API level
// 11-18)
// - android.webkit.HTML5VideoFullScreen$VideoTextureView, which
// inherits from android.view.TextureView (typically API level
// 11-18)
// -
// com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView,
// which inherits from android.view.SurfaceView (typically API
// level 19+)
// Handle HTML5 video ended event only if the class is a
// SurfaceView
// Test case: TextureView of Sony Xperia T API level 16 doesn't
// work fullscreen when loading the javascript below
if (webView != null
&& webView.getSettings().getJavaScriptEnabled()
&& focusedChild instanceof SurfaceView) {
// Run javascript code that detects the video end and
// notifies the Javascript interface
String js = "javascript:";
js += "var _ytrp_html5_video_last;";
js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
js += "if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) {";
{
js += "_ytrp_html5_video_last = _ytrp_html5_video;";
js += "function _ytrp_html5_video_ended() {";
{
js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must
// match
// Javascript
// interface
// name
// and
// method
// of
// VideoEnableWebView
}
js += "}";
js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
}
js += "}";
webView.loadUrl(js);
}
}
// Notify full-screen change
if (toggledFullscreenCallback != null) {
toggledFullscreenCallback.toggledFullscreen(true);
}
}
}
#Override
#SuppressWarnings("deprecation")
public void onShowCustomView(View view, int requestedOrientation,
CustomViewCallback callback) // Available in API level 14+,
// deprecated in API level 18+
{
onShowCustomView(view, callback);
}
#Override
public void onHideCustomView() {
// This method should be manually called on video end in all cases
// because it's not always called automatically.
// This method must be manually called on back key press (from this
// class' onBackPressed() method).
if (isVideoFullscreen) {
// Hide the video view, remove it, and show the non-video view
activityVideoView.setVisibility(View.INVISIBLE);
activityVideoView.removeView(videoViewContainer);
activityNonVideoView.setVisibility(View.VISIBLE);
// Call back (only in API level <19, because in API level 19+ with
// chromium webview it crashes)
if (videoViewCallback != null
&& !videoViewCallback.getClass().getName()
.contains(".chromium.")) {
videoViewCallback.onCustomViewHidden();
}
// Reset video related variables
isVideoFullscreen = false;
videoViewContainer = null;
videoViewCallback = null;
// Notify full-screen change
if (toggledFullscreenCallback != null) {
toggledFullscreenCallback.toggledFullscreen(false);
}
}
}
#Override
public View getVideoLoadingProgressView() // Video will start loading, only
// called in the case of
// VideoView (typically API
// level 10-)
{
if (loadingView == null) {
return super.getVideoLoadingProgressView();
} else {
loadingView.setVisibility(View.VISIBLE);
return loadingView;
}
}
#Override
public void onPrepared(MediaPlayer mp) // Video will start playing, only
// called in the case of
// android.widget.VideoView
// (typically API level <11)
{
if (loadingView != null) {
loadingView.setVisibility(View.GONE);
}
}
#Override
public void onCompletion(MediaPlayer mp) // Video finished playing, only
// called in the case of
// android.widget.VideoView
// (typically API level <11)
{
onHideCustomView();
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) // Error while
// playing
// video, only
// called in the
// case of
// android.widget.VideoView
// (typically
// API level
// <11)
{
return false; // By returning false, onCompletion() will be called
}
/**
* Notifies the class that the back key has been pressed by the user. This
* must be called from the Activity's onBackPressed(), and if it returns
* false, the activity itself should handle it. Otherwise don't do anything.
*
* #return Returns true if the event was handled, and false if was not
* (video view is not visible)
*/
public boolean onBackPressed() {
if (isVideoFullscreen) {
onHideCustomView();
return true;
} else {
return false;
}
}
}
and VideoEnabledWebView.java
package com.example.testvideo1;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import java.util.Map;
/**
* This class serves as a WebView to be used in conjunction with a
* VideoEnabledWebChromeClient. It makes possible: - To detect the HTML5 video
* ended event so that the VideoEnabledWebChromeClient can exit full-screen.
*
* Important notes: - Javascript is enabled by default and must not be disabled
* with getSettings().setJavaScriptEnabled(false). - setWebChromeClient() must
* be called before any loadData(), loadDataWithBaseURL() or loadUrl() method.
*
* #author Cristian Perez (http://cpr.name)
*
*/
public class VideoEnabledWebView extends WebView {
public class JavascriptInterface {
#android.webkit.JavascriptInterface
public void notifyVideoEnd() // Must match Javascript interface method
// of VideoEnabledWebChromeClient
{
// This code is not executed in the UI thread, so we must force that
// to happen
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
if (videoEnabledWebChromeClient != null) {
videoEnabledWebChromeClient.onHideCustomView();
}
}
});
}
}
private VideoEnabledWebChromeClient videoEnabledWebChromeClient;
private boolean addedJavascriptInterface;
public VideoEnabledWebView(Context context) {
super(context);
addedJavascriptInterface = false;
}
#SuppressWarnings("unused")
public VideoEnabledWebView(Context context, AttributeSet attrs) {
super(context, attrs);
addedJavascriptInterface = false;
}
#SuppressWarnings("unused")
public VideoEnabledWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
addedJavascriptInterface = false;
}
/**
* Indicates if the video is being displayed using a custom view (typically
* full-screen)
*
* #return true it the video is being displayed using a custom view
* (typically full-screen)
*/
public boolean isVideoFullscreen() {
return videoEnabledWebChromeClient != null
&& videoEnabledWebChromeClient.isVideoFullscreen();
}
/**
* Pass only a VideoEnabledWebChromeClient instance.
*/
#Override
#SuppressLint("SetJavaScriptEnabled")
public void setWebChromeClient(WebChromeClient client) {
getSettings().setJavaScriptEnabled(true);
if (client instanceof VideoEnabledWebChromeClient) {
this.videoEnabledWebChromeClient = (VideoEnabledWebChromeClient) client;
}
super.setWebChromeClient(client);
}
#Override
public void loadData(String data, String mimeType, String encoding) {
addJavascriptInterface();
super.loadData(data, mimeType, encoding);
}
#Override
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String historyUrl) {
addJavascriptInterface();
super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
#Override
public void loadUrl(String url) {
addJavascriptInterface();
super.loadUrl(url);
}
#Override
public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
addJavascriptInterface();
super.loadUrl(url, additionalHttpHeaders);
}
private void addJavascriptInterface() {
if (!addedJavascriptInterface) {
// Add javascript interface to be called when the video ends (must
// be done before page load)
addJavascriptInterface(new JavascriptInterface(),
"_VideoEnabledWebView"); // Must match Javascript interface
// name of
// VideoEnabledWebChromeClient
addedJavascriptInterface = true;
}
}
}
and the layout file
<!-- View that will be hidden when video goes fullscreen -->
<RelativeLayout
android:id="#+id/nonVideoLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.VideoEnabledWebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<!-- View where the video will be shown when video goes fullscreen -->
<RelativeLayout
android:id="#+id/videoLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- View that will be shown while the fullscreen video loads (maybe include a spinner and a "Loading..." message) -->
<View
android:id="#+id/videoLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="invisible" />
</RelativeLayout>
the project can't work, and i want when fullscreen , let the program go LandScape mode.
but i failed.
thanks.......
I've been facing the same issue.
Although this question is quite old, I have come to a simple solution which I could not find on stack overflow.
Just enforce Landscape when going full screen:
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
And revert this, when going back.
In context:
public class BaseWebChromeClient extends WebChromeClient
{
#Override
public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback)
{
[...]
act.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
[...]
#Override
public void onHideCustomView(View view, WebChromeClient.CustomViewCallback callback)
{
[...]
act.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// use SCREEN_ORIENTATION_SENSOR, if you don't to enforce portrait mode.
[...]
}
}

What is the best way to trigger a combo-box cell editor by typing in a JTable cell?

In other words, I want JTable to drop-down a combo-box whenever user types in a cell that has a JComboBox (or any other JComboBox-based cell-editor) editor associated to it.
Basically, you have to install an appropriate listener on the combo and open the popup explicitly. First candidate for "appropriate" is an AncestorListener, which invokes showing the popup in its ancestorAdded method.
Unfortunately that doesn't seem to be the whole story: works if the table's surrenderFocus property is false. If it is true works only for not-editable combos. After some digging, the reason for the not-working part turns out to be an internal focustransfer (from the combo to the textfield) after the popup is opened by the ancestorListener. In that case, we need a second listener which opens the popup once the editor's editingComponent got the focus permanently.
Multiple listeners routinely step onto each other's feet, so best to not install both permanently but do it on each call to getEditorComp, and let them uninstall themselves once they showed the popup. Below is a working example of how-to do it, just beware: it's not formally tested!
public static class DefaultCellEditorX extends DefaultCellEditor {
private AncestorListener ancestorListener;
private PropertyChangeListener focusPropertyListener;
public DefaultCellEditorX(JComboBox comboBox) {
super(comboBox);
}
/**
* Overridden to install an appriate listener which opens the
* popup when actually starting an edit.
*
* #inherited <p>
*/
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
super.getTableCellEditorComponent(table, value, isSelected, row, column);
installListener(table);
return getComponent();
}
/**
* Shows popup.
*/
protected void showPopup() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
getComponent().setPopupVisible(true);
}
});
}
/**
* Dynamically install self-uninstalling listener, depending on JComboBox
* and JTable state.
* #param table
*/
private void installListener(JTable table) {
if (getComponent().isEditable() && table.getSurrendersFocusOnKeystroke()) {
installKeyboardFocusListener();
} else {
installAncestorListener();
}
}
private void installAncestorListener() {
if (ancestorListener == null) {
ancestorListener = new AncestorListener() {
#Override
public void ancestorAdded(AncestorEvent event) {
getComponent().removeAncestorListener(ancestorListener);
showPopup();
}
#Override
public void ancestorRemoved(AncestorEvent event) {
}
#Override
public void ancestorMoved(AncestorEvent event) {
}
};
}
getComponent().addAncestorListener(ancestorListener);
}
private void installKeyboardFocusListener() {
if (focusPropertyListener == null) {
focusPropertyListener = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
LOG.info("property: " + evt.getPropertyName());
if (focusManager().getPermanentFocusOwner() !=
getComponent().getEditor().getEditorComponent()) return;
focusManager()
.removePropertyChangeListener("permanentFocusOwner", focusPropertyListener);
showPopup();
}
};
}
focusManager().addPropertyChangeListener("permanentFocusOwner", focusPropertyListener);
}
/**
* Convience for less typing.
* #return
*/
protected KeyboardFocusManager focusManager() {
return KeyboardFocusManager.getCurrentKeyboardFocusManager();
}
/**
* Convenience for type cast.
* #inherited <p>
*/
#Override
public JComboBox getComponent() {
return (JComboBox) super.getComponent();
}
}
JTable table = new JTable(data, columns);
table.putClientProperty("terminateEditOnFocusLost", true);
JScrollPane scrollPane = new JScrollPane(table);
final JXComboBox editorComboBox = new JXComboBox(array);
editorComboBox.addAncestorListener(new AncestorListener() {
public void ancestorAdded(AncestorEvent event) {
//make sure combobox handles key events
editorComboBox.requestFocusInWindow();
}
public void ancestorMoved(AncestorEvent event) {}
public void ancestorRemoved(AncestorEvent event) {}
});
AutoCompleteDecorator.decorate(editorComboBox);
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellEditor(new ComboBoxCellEditor(editorComboBox));