I am having trouble attaching onTouch/onClick events for a RelativeLayout. I have searched a lot on internet, and could find the possible solution as using dispatchTouchEvent(MotionEvent). But I don't want to use this way, as I am having some trouble implementing that as well. Code is attached below.
public class ConnectMeDigit extends RelativeLayout implements AddressAware {
public ConnectMeDigit(Context context, AttributeSet attrs) {
super(context, attrs);
View view = LayoutInflater.from(context).inflate(R.layout.numpad_digit, this);
Typeface face=Typeface.createFromAsset(context.getAssets(), "helveticathin.ttf");//"helveticaultralight.ttf");
String xmlProvidedSize = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "tag");
TextView keypadnumber = (TextView) view.findViewById(R.id.keypadnumber);
TextView keypadalphabets = (TextView) view.findViewById(R.id.keypadalphabets);
TextView keypadplussubscript = (TextView) view.findViewById(R.id.keypadplussubscript);
keypadnumber.setTypeface(face);
keypadalphabets.setTypeface(face);
keypadplussubscript.setTypeface(face);
keypadplussubscript.setVisibility(View.GONE);
keypadnumber.setText(xmlProvidedSize);
if(xmlProvidedSize.equals("1")) {
keypadalphabets.setVisibility(View.GONE);
}
else if(xmlProvidedSize.equals("2")) {
keypadalphabets.setText("ABC");
}
else if(xmlProvidedSize.equals("3")) {
keypadalphabets.setText("DEF");
}
else if(xmlProvidedSize.equals("4")) {
keypadalphabets.setText("GHI");
}
else if(xmlProvidedSize.equals("5")) {
keypadalphabets.setText("JKL");
}
else if(xmlProvidedSize.equals("6")) {
keypadalphabets.setText("MNO");
}
else if(xmlProvidedSize.equals("7")) {
keypadalphabets.setText("PQRS");
}
else if(xmlProvidedSize.equals("8")) {
keypadalphabets.setText("TUV");
}
else if(xmlProvidedSize.equals("9")) {
keypadalphabets.setText("WXYZ");
}
else if(xmlProvidedSize.equals("0")) {
keypadplussubscript.setVisibility(View.VISIBLE);
keypadalphabets.setVisibility(View.GONE);
}
else if(xmlProvidedSize.equals("*")) {
keypadalphabets.setVisibility(View.GONE);
}
else if(xmlProvidedSize.equals("#")) {
keypadalphabets.setVisibility(View.GONE);
}
System.out.println("ConnectMeDigit.this.getTag(): " + ConnectMeDigit.this.getTag());
System.out.println("xmlProvidedSize: " + xmlProvidedSize);
setEnabled(true);
setFocusable(true);
setFocusableInTouchMode(true);//setFocusable(true);
setClickable(true);
setLongClickable(true);
DialKeyListener lListener = new DialKeyListener(xmlProvidedSize);
setOnClickListener(lListener);
setOnTouchListener(lListener);
if (xmlProvidedSize.equals("0")) {//("0+".equals(text)) {
setOnLongClickListener(lListener);
}
}
private AddressText mAddress;
public void setAddressWidget(AddressText address) {
mAddress = address;
}
private boolean mPlayDtmf;
public void setPlayDtmf(boolean play) {
mPlayDtmf = play;
}
private class DialKeyListener implements OnClickListener, OnTouchListener, OnLongClickListener {
final char mKeyCode;
boolean mIsDtmfStarted;
/*DialKeyListener() {
mKeyCode = ConnectMeDigit.this.getText().subSequence(0, 1).charAt(0);
}*/
DialKeyListener(String character) {
mKeyCode = character.charAt(0); //ConnectMeDigit.this.getText().subSequence(0, 1).charAt(0);
System.out.println("mKeyCode: " + mKeyCode);
}
private boolean linphoneServiceReady() {
if (!LinphoneService.isReady()) {
Log.w("Service is not ready while pressing digit");
Toast.makeText(getContext(), getContext().getString(R.string.skipable_error_service_not_ready), Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
public void onClick(View v) {
if (mPlayDtmf) {
if (!linphoneServiceReady()) return;
LinphoneCore lc = LinphoneManager.getLc();
lc.stopDtmf();
mIsDtmfStarted =false;
if (lc.isIncall()) {
lc.sendDtmf(mKeyCode);
}
}
if (mAddress != null) {
int lBegin = mAddress.getSelectionStart();
if (lBegin == -1) {
lBegin = mAddress.length();
}
if (lBegin >= 0) {
mAddress.getEditableText().insert(lBegin,String.valueOf(mKeyCode));
}
}
}
public boolean onTouch(View v, MotionEvent event) {
if (!mPlayDtmf) return false;
if (!linphoneServiceReady()) return true;
if (InCallActivity.isInstanciated()) {
InCallActivity.instance().resetControlsHidingCallBack();
}
LinphoneCore lc = LinphoneManager.getLc();
if (event.getAction() == MotionEvent.ACTION_DOWN && !mIsDtmfStarted) {
LinphoneManager.getInstance().playDtmf(getContext().getContentResolver(), mKeyCode);
mIsDtmfStarted = true;
} else {
if (event.getAction() == MotionEvent.ACTION_UP) {
lc.stopDtmf();
mIsDtmfStarted = false;
}
}
return false;
}
public boolean onLongClick(View v) {
if (mPlayDtmf) {
if (!linphoneServiceReady()) return true;
// Called if "0+" dtmf
LinphoneCore lc = LinphoneManager.getLc();
lc.stopDtmf();
}
if (mAddress == null) return true;
int lBegin = mAddress.getSelectionStart();
if (lBegin == -1) {
lBegin = mAddress.getEditableText().length();
}
if (lBegin >= 0) {
mAddress.getEditableText().insert(lBegin,"+");
}
return true;
}
};
}
I have tried setEnabled(true) setFocusable(true) setFocusableInTouchMode(true) setClickable(true) setLongClickable(true) and none of them seems to work.
Try using
view.setOnClickListener(lListener);
view.setOnTouchListener(lListener);
instead of
setOnClickListener(lListener);
setOnTouchListener(lListener);
Related
I have this code in my MainActivity
recyclerView.setAdapter(customAdapter);
customAdapter.submitList(path_list);
selectionTracker = new SelectionTracker.Builder<>(
"my-selection-id",
recyclerView,
new ScrollKeyProvider(1, path_list),
new ScrollItemDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()
)
.withOnItemActivatedListener(new OnItemActivatedListener<Long>() {
#Override
public boolean onItemActivated(#NonNull ItemDetailsLookup.ItemDetails<Long> item, #NonNull MotionEvent e) {
Log.d("TAG", "Selected ItemId: " + item.toString());
return true;
}
})
.withOnDragInitiatedListener(new OnDragInitiatedListener() {
#Override
public boolean onDragInitiated(#NonNull MotionEvent e) {
Log.d("TAG", "onDragInitiated");
return true;
}
}).build();
customAdapter.setSelectionTracker(selectionTracker);
selectionTracker.addObserver(new SelectionTracker.SelectionObserver() {
#Override
public void onItemStateChanged(#NonNull Object key, boolean selected) {
super.onItemStateChanged(key, selected);
}
#Override
public void onSelectionRefresh() {
super.onSelectionRefresh();
}
#Override
public void onSelectionChanged() {
super.onSelectionChanged();
if (selectionTracker.hasSelection() && actionMode == null) {
actionMode = startSupportActionMode(new ActionModeController(ScrollActivity.this, selectionTracker));
actionMode.getMenu().findItem(R.id.action_item_count).setTitle("" + selectionTracker.getSelection().size());
} else if (!selectionTracker.hasSelection() && actionMode != null) {
actionMode.finish();
actionMode = null;
} else {
actionMode.getMenu().findItem(R.id.action_item_count).setTitle("" + selectionTracker.getSelection().size());
}
Iterator<String> itemIterable = selectionTracker.getSelection().iterator();
while (itemIterable.hasNext()) {
Log.i("TAG", itemIterable.next());
}
}
#Override
public void onSelectionRestored() {
super.onSelectionRestored();
}
});
This is my ActionMode callback code
public class ActionModeController implements ActionMode.Callback {
private final Context context;
private final SelectionTracker selectionTracker;
public ActionModeController(Context context, SelectionTracker selectionTracker) {
this.context = context;
this.selectionTracker = selectionTracker;
}
#Override
public boolean onCreateActionMode(androidx.appcompat.view.ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.action_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(androidx.appcompat.view.ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(androidx.appcompat.view.ActionMode mode, MenuItem item) {
if(item.getItemId()==R.id.action_clear){
if (selectionTracker.hasSelection()){
selectionTracker.clearSelection();
}
}
else if(item.getItemId()==R.id.action_select_all){
// **THIS IS PLACE WHERE I NEED HELP TO ENTER CODE FOR SELECT ALL FUNCTIONALITY**
}
return false;
}
#Override
public void onDestroyActionMode(androidx.appcompat.view.ActionMode mode) {
selectionTracker.clearSelection();
}
}
What should I do in select all section in onActionItemClicked for selecting all items in Recyclerview using SelectionTracker?
You can see for the clear option in onActionItemClicked, I have used functions of selectionTracker to clear all the selected items. I am expecting similar solution for select all option too.
Kotlin version using PagingDataAdapter - can be reworked replacing the snapshot to items in your implementation.
var itemsArray = arrayListOf<Long>()
adapter?.snapshot()?.items?.forEach {
if (!selectionTracker.isSelected(it.id.toLong()))
itemsArray.add(it.id.toLong())
}
selectionTracker?.setItemsSelected(itemsArray.asIterable(), true)
I have the task to make video play in recyclerview use exoplayer
and use this reference :
I am follow tutorial by Droid wafe :
and code works very well in my application. but. there is a slight problem. the problem is when I call the notifyItemChange (position) function to update an item on videoViewHolder. the video paused, but the audio still runs in the background.
I think the problem is when notifyItemChange is called, video view holder in re-create and make the video pause (default) but audio keep running cause not calling setplaywhenready(false)
import android.content.Context;
import android.graphics.Point;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestManager;
import com.google.android.exoplayer2.*;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.*;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
import es.hyrax.zonapets.R;
import es.hyrax.zonapets.data.network.model.post.Post;
import es.hyrax.zonapets.ui.user_private.home.dashboard_my_zona.viewholder_myzona.ViewHolderImages;
import es.hyrax.zonapets.ui.user_private.home.dashboard_my_zona.viewholder_myzona.ViewHolderMultipleImages;
import es.hyrax.zonapets.ui.user_private.home.dashboard_my_zona.viewholder_myzona.ViewHolderVideos;
import es.hyrax.zonapets.utils.listener.OnDoubleClickListener;
import java.util.ArrayList;
import java.util.Objects;
public class ExoPlayerRecyclerViewMyZona extends RecyclerView {
private static final String TAG = "ExoPlayerRecyclerView";
private static final String AppName = "ZonaPets";
/**
* PlayerViewHolder UI component
* Watch PlayerViewHolder class
*/
private ImageView mediaCoverImage, volumeControl;
private FrameLayout container_volume;
private ProgressBar progressBar;
private View viewHolderParent;
private AspectRatioFrameLayout mediaContainer;
private PlayerView videoSurfaceView;
private SimpleExoPlayer videoPlayer;
/**
* variable declaration
*/
// Media List
private ArrayList<Post> mediaObjects = new ArrayList<>();
private int videoSurfaceDefaultHeight = 0;
private int screenDefaultHeight = 0;
private Context context;
private int playPosition = -1;
private boolean isVideoViewAdded;
private RequestManager requestManager;
// controlling volume state
private VolumeState volumeState;
private int targetPosition;
private OnEventClickVideoViewHolder onEventClick;
public ExoPlayerRecyclerViewMyZona(#NonNull Context context) {
super(context);
init(context);
}
public ExoPlayerRecyclerViewMyZona(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
this.context = context.getApplicationContext();
Display display = ((WindowManager) Objects.requireNonNull(
getContext().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay();
Point point = new Point();
display.getSize(point);
videoSurfaceDefaultHeight = point.x;
screenDefaultHeight = point.y;
videoSurfaceView = new PlayerView(this.context);
videoSurfaceView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM);
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
//Create the player using ExoPlayerFactory
videoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
// Disable Player Control
videoSurfaceView.setUseController(false);
// Bind the player to the containerView.
videoSurfaceView.setPlayer(videoPlayer);
// Turn on Volume
setVolumeControl(VolumeState.ON);
addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (mediaCoverImage != null) {
// show the old thumbnail
mediaCoverImage.setVisibility(VISIBLE);
}
// There's a special case when the end of the list has been reached.
// Need to handle that with this bit of logic
if (!recyclerView.canScrollVertically(1)) {
playVideo(true);
} else {
playVideo(false);
}
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
addOnChildAttachStateChangeListener(new OnChildAttachStateChangeListener() {
#Override
public void onChildViewAttachedToWindow(#NonNull View view) {
}
#Override
public void onChildViewDetachedFromWindow(#NonNull View view) {
if (viewHolderParent != null && viewHolderParent.equals(view)) {
resetVideoView();
}
}
});
videoPlayer.addListener(new Player.EventListener() {
#Override
public void onTimelineChanged(Timeline timeline, #Nullable Object manifest, int reason) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups,
TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case Player.STATE_BUFFERING:
Log.e(TAG, "onPlayerStateChanged: Buffering video.");
if (progressBar != null) {
progressBar.setVisibility(VISIBLE);
}
if (volumeControl != null){
volumeControl.setAlpha(1f);
}
break;
case Player.STATE_ENDED:
Log.d(TAG, "onPlayerStateChanged: Video ended.");
videoPlayer.seekTo(0);
break;
case Player.STATE_IDLE:
break;
case Player.STATE_READY:
Log.e(TAG, "onPlayerStateChanged: Ready to play.");
if (progressBar != null) {
progressBar.setVisibility(GONE);
}
if (volumeControl != null){
volumeControl.setAlpha(1f);
}
if (!isVideoViewAdded) {
addVideoView();
}
break;
default:
break;
}
}
#Override
public void onRepeatModeChanged(int repeatMode) {
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
#Override
public void onPositionDiscontinuity(int reason) {
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
#Override
public void onSeekProcessed() {
}
});
}
public void playVideo(boolean isEndOfList) {
int targetPosition;
if (!isEndOfList) {
int startPosition = ((LinearLayoutManager) Objects.requireNonNull(
getLayoutManager())).findFirstVisibleItemPosition();
int endPosition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();
// if there is more than 2 list-items on the screen, set the difference to be 1
if (endPosition - startPosition > 1) {
endPosition = startPosition + 1;
}
// something is wrong. return.
if (startPosition < 0 || endPosition < 0) {
return;
}
// if there is more than 1 list-item on the screen
if (startPosition != endPosition) {
int startPositionVideoHeight = getVisibleVideoSurfaceHeight(startPosition);
int endPositionVideoHeight = getVisibleVideoSurfaceHeight(endPosition);
targetPosition =
startPositionVideoHeight > endPositionVideoHeight ? startPosition : endPosition;
} else {
targetPosition = startPosition;
}
} else {
targetPosition = mediaObjects.size() - 1;
}
Log.d(TAG, "playVideo: target position: " + targetPosition);
// video is already playing so return
if (targetPosition == playPosition) {
return;
}
// set the position of the list-item that is to be played
playPosition = targetPosition;
if (videoSurfaceView == null) {
return;
}
// remove any old surface views from previously playing videos
videoSurfaceView.setVisibility(INVISIBLE);
removeVideoView(videoSurfaceView);
//set get target position to this target position
this.targetPosition = targetPosition;
int currentPosition =
targetPosition - ((LinearLayoutManager) Objects.requireNonNull(
getLayoutManager())).findFirstVisibleItemPosition();
View child = getChildAt(currentPosition);
if (child == null) {
return;
}
if (child.getTag() instanceof ViewHolderVideos) {
ViewHolderVideos holder = (ViewHolderVideos) child.getTag();
if (holder == null) {
playPosition = -1;
return;
}
mediaCoverImage = holder.img_post;
progressBar = holder.progressBar;
volumeControl = holder.volumeControl;
viewHolderParent = holder.itemView;
container_volume = holder.container_volume;
requestManager = holder.requestManager;
mediaContainer = holder.mediaContainer;
videoSurfaceView.setPlayer(videoPlayer);
mediaContainer.setOnClickListener(new OnDoubleClickListener() {
#Override
public void onDoubleClick(View v) {
onEventClick.onDoubleClickListener(targetPosition);
}
#Override
public void onSingleClick(View v) {
onEventClick.onSingleClickListener(targetPosition);
}
});
container_volume.setOnClickListener(new OnDoubleClickListener() {
#Override
public void onDoubleClick(View v) {
}
#Override
public void onSingleClick(View v) {
toggleVolume();
}
});
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(
context, Util.getUserAgent(context, AppName));
String mediaUrl = mediaObjects.get(targetPosition).getImagepost().get(0).getVideo();/*"https://androidwave.com/media/androidwave-video-1.mp4";*/
if (mediaUrl != null) {
MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(mediaUrl));
videoPlayer.prepare(videoSource);
videoPlayer.setPlayWhenReady(true);
}
}else {
videoPlayer.setPlayWhenReady(false);
}
}
/**
* Returns the visible region of the video surface on the screen.
* if some is cut off, it will return less than the #videoSurfaceDefaultHeight
*/
private int getVisibleVideoSurfaceHeight(int playPosition) {
int at = playPosition - ((LinearLayoutManager) Objects.requireNonNull(
getLayoutManager())).findFirstVisibleItemPosition();
Log.d(TAG, "getVisibleVideoSurfaceHeight: at: " + at);
View child = getChildAt(at);
if (child == null) {
return 0;
}
int[] location = new int[2];
child.getLocationInWindow(location);
if (location[1] < 0) {
return location[1] + videoSurfaceDefaultHeight;
} else {
return screenDefaultHeight - location[1];
}
}
// Remove the old player
private void removeVideoView(PlayerView videoView) {
ViewGroup parent = (ViewGroup) videoView.getParent();
if (parent == null) {
return;
}
int index = parent.indexOfChild(videoView);
if (index >= 0) {
parent.removeViewAt(index);
isVideoViewAdded = false;
//viewHolderParent.setOnClickListener(null);
}
}
private void addVideoView() {
mediaContainer.addView(videoSurfaceView);
isVideoViewAdded = true;
videoSurfaceView.requestFocus();
videoSurfaceView.setVisibility(VISIBLE);
videoSurfaceView.setAlpha(1);
mediaCoverImage.setVisibility(GONE);
volumeControl.setVisibility(VISIBLE);
}
private void resetVideoView() {
if (isVideoViewAdded) {
removeVideoView(videoSurfaceView);
playPosition = -1;
videoSurfaceView.setVisibility(INVISIBLE);
mediaCoverImage.setVisibility(VISIBLE);
volumeControl.setVisibility(VISIBLE);
}
}
private Boolean currentPositionIsVideoType(){
int currentPosition =
targetPosition - ((LinearLayoutManager) Objects.requireNonNull(
getLayoutManager())).findFirstVisibleItemPosition();
View child = getChildAt(currentPosition);
if (child == null) {
return false;
}
if (child.getTag() instanceof ViewHolderVideos) {
return true;
}else {
return false;
}
}
public void releasePlayer() {
if (currentPositionIsVideoType()) {
if (videoPlayer != null) {
videoPlayer.release();
videoPlayer = null;
}
viewHolderParent = null;
}
}
public void onPausePlayer() {
if (currentPositionIsVideoType()){
if (videoPlayer != null) {
//videoPlayer.stop(true);
videoPlayer.setPlayWhenReady(false);
videoPlayer.getPlaybackState();
}
}
}
public void resumePlayer() {
if (currentPositionIsVideoType()){
if (videoPlayer != null) {
videoPlayer.setPlayWhenReady(true);
videoPlayer.getPlaybackState();
}
}
}
private void toggleVolume() {
if (videoPlayer != null) {
if (volumeState == VolumeState.OFF) {
Log.d(TAG, "togglePlaybackState: enabling volume.");
setVolumeControl(VolumeState.ON);
} else if (volumeState == VolumeState.ON) {
Log.d(TAG, "togglePlaybackState: disabling volume.");
setVolumeControl(VolumeState.OFF);
}
}
}
//public void onRestartPlayer() {
// if (videoPlayer != null) {
// playVideo(true);
// }
//}
private void setVolumeControl(VolumeState state) {
volumeState = state;
if (state == VolumeState.OFF) {
videoPlayer.setVolume(0f);
animateVolumeControl();
} else if (state == VolumeState.ON) {
videoPlayer.setVolume(1f);
animateVolumeControl();
}
}
private void animateVolumeControl() {
if (volumeControl != null) {
volumeControl.bringToFront();
if (volumeState == VolumeState.OFF) {
requestManager.load(R.drawable.ic_volume_off)
.into(volumeControl);
} else if (volumeState == VolumeState.ON) {
requestManager.load(R.drawable.ic_volume_on)
.into(volumeControl);
}
//volumeControl.animate().cancel();
volumeControl.setAlpha(1f);
volumeControl.animate()
.alpha(1f)
.setDuration(600).setStartDelay(1000);
}
}
public void setMediaObjects(ArrayList<Post> mediaObjects) {
this.mediaObjects = mediaObjects;
}
public void setVideoViewHolderClickListener(OnEventClickVideoViewHolder onEventClick){
this.onEventClick = onEventClick;
}
/**
* Volume ENUM
*/
private enum VolumeState {
ON, OFF
}
public interface OnEventClickVideoViewHolder {
void onSingleClickListener(int position);
void onDoubleClickListener(int position);
}
}
and log cat not show any error!!
please take a look my comment in issue report for help understand
There is a WebViewPool,when Activity/Fragment is destoryed,webview will be reset and add to the WebViewPool.
The following is the code of WebViewPool:
public class WebViewPool {
private static volatile WebViewPool sINSTANCE;
private int mMaxSize;
private List<WebView> mAvailableList;
private List<WebView> mInUsedList;
private IWebViewPoolFactory mFactory;
private WebViewPool() {
}
public static WebViewPool getInstance() {
if (sINSTANCE == null) {
synchronized (WebViewPool.class) {
if (sINSTANCE == null) {
sINSTANCE = new WebViewPool();
}
}
}
return sINSTANCE;
}
public void init(IWebViewPoolFactory factory,boolean lazy) {
init(2, factory,lazy);
}
public void init(int maxSize, IWebViewPoolFactory factory,boolean lazy) {
mMaxSize = maxSize;
mFactory = factory;
mAvailableList = new ArrayList<>(maxSize);
mInUsedList = new ArrayList<>(maxSize);
if (!lazy) {
create();
}
}
private synchronized void create() {
if (mFactory == null) {
return;
}
for (int i = 0; i < mMaxSize; i++) {
WebView webView = mFactory.create(new MutableContextWrapper(APP.getApplicationContext()));
mAvailableList.add(webView);
}
}
/**
* get webview form pool
* #param context
* #return
*/
public synchronized WebView getWebView(Context context) {
if(!(context instanceof Activity)){
throw new IllegalStateException("Context must be Activity");
}
WebView webView = null;
if (mAvailableList.size() > 0) {
webView = mAvailableList.remove(0);
} else {
if (mFactory != null) {
webView = mFactory.create(new MutableContextWrapper(APP.getApplicationContext()));
}
}
if (webView != null) {
((MutableContextWrapper) webView.getContext()).setBaseContext(context);
mInUsedList.add(webView);
}
return webView;
}
/**
* reset/destroy webview when activity/fragemnt is destroyed
* #param webView
*/
public synchronized void restWebView(WebView webView) {
if (webView == null || mFactory == null) {
return;
}
mFactory.reset(webView);
((MutableContextWrapper) webView.getContext()).setBaseContext(APP.getApplicationContext());
if (mInUsedList.contains(webView)) {
mInUsedList.remove(webView);
if (mAvailableList.size() < mMaxSize) {
mAvailableList.add(webView);
} else {
mFactory.destroy(webView);
}
} else {
mFactory.destroy(webView);
}
}
}
the following is some code of reset function:
public void reset(WebView webView) {
if(webView==null){
return;
}
ViewParent viewParent = webView.getParent();
if (viewParent!=null) {
((ViewGroup)viewParent).removeView(webView);
}
webView.stopLoading();
webView.clearCache(false);
webView.loadUrl("about:blank");
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
webView.clearHistory();
}
}, 1000);
}
But when reuse the webview,last html page show first before new url sometimes.It doesn't happened everytime. I searched in Google, but not work.Does anyone know the reason? Thank you!
This problem is solved finally! The reason is that add the reseted WebView to available list while about:blank is not loaded so that clearHistory() doesn't work.
So, reset the webview but do not add to available list when activity/fragment is destroyed, call clearHistory() at onPageFinished() when url is about:blank:
#Override
public void onPageFinish(String url, boolean success) {
if("about:blank".equals(url)){
webView.clearHistory();
//then add the webview to available list;
}
}
I have the problem with idling resources while testing using Espresso.
It doesn't work. It is called only twice and that's all, even if return false.
public class MyIdlingResource implements IdlingResource {
private boolean mIdle;
private ResourceCallback mResourceCallback;
public MyIdlingResource () {
this.mIdle = false;
this.mResourceCallback = null;
}
#Override
public final String getName() {
return MyIdlingResource .class.getSimpleName();
}
#Override
public final boolean isIdleNow() {
ArrayList<View> views = doStuff();
mIdle = views != null && !views.isEmpty();
if (mIdle) {
if (mResourceCallback != null) {
mResourceCallback.onTransitionToIdle();
}
}
return false;
}
#Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
mResourceCallback = resourceCallback;
}
}
So in this case I return false all the time, but it doesn't work either.
What is wrong ?
You missed return true; in below peace of code:
if (mIdle) {
if (mResourceCallback != null) {
mResourceCallback.onTransitionToIdle();
return true; // this one is missed
}
}
I want to make glass application with offline voice recognition with no ok glass
what I want to know is changing ok glass to other words ( something like "start").
I saw the source decompiled GlassHome.apk and GlassVoice.apk.
I knew that setting to ok glass is related with VoiceInputHelper, voice_label_ok_glass in String.xml
so I tried to change all of string "ok glass" to "nice"(temp guard phrase) in String.xml
but when I said any word (like "hahaha" or "kakaka") , all of word I said is recognized to my guard phrase ("nice") by VoiceService.
what should I do for changing "ok glass" to my guard phrase and working it right ???????
(P.S sorry my bad english. I hope you understand what question means)
here is my code ( I tried to set VoiceConfig to "nice")
public class MainActivity extends GlassActivity implements VoiceListener {
public static final String TEST_SERVICE_EXTRAS_KEY = "serviceExtras";
private ImageView gradientView;
private GuardHintAnimator guardHintAnimator;
private TextView guardPhraseView;
private boolean isRunning = false;
private final FormattingLogger logger = FormattingLoggers.getLogger(this);
private VoiceConfig onWindowFocusChangedRecoverConfig;
private VoiceConfig voiceConfig;
#VisibleForTesting
VoiceInputHelper voiceInputHelper;
private IVoiceMenuDialog voiceMenuDialog;
public FormattingLogger getLogger()
{
return this.logger;
}
public boolean isRunning()
{
return this.isRunning;
}
#Override
protected void onCreateInternal(Bundle bundle) {
super.onCreateInternal(bundle);
this.voiceInputHelper = new VoiceInputHelper(this, new DelegatingVoiceListener(this)
{
public VoiceConfig onVoiceCommand(VoiceCommand paramAnonymousVoiceCommand)
{
if ((!MainActivity.this.hasWindowFocus()) && (!MainActivity.this.isMessageShowing()))
{
MainActivity.this.logger.d("Ignoring voice command because we don't have window focus.", new Object[0]);
return null;
}
Log.d("listener",paramAnonymousVoiceCommand.toString());
//return super.onVoiceCommand(paramAnonymousVoiceCommand);
return null;
}
}, getVoiceServiceExtras());
}
protected void onPauseInternal()
{
this.isRunning = false;
super.onPauseInternal();
closeVoiceMenu();
this.voiceInputHelper.setVoiceConfig(VoiceConfig.OFF);
this.voiceInputHelper.unregisterGrammarLoaders();
}
public void closeVoiceMenu()
{
if (this.voiceMenuDialog != null)
{
this.voiceMenuDialog.dismiss(false);
this.voiceMenuDialog = null;
}
}
public void onPrepareVoiceMenu(VoiceMenuDialog paramVoiceMenuDialog) {}
public boolean onResampledAudioData(byte[] paramArrayOfByte, int paramInt1, int paramInt2)
{
return false;
}
protected void onResumeInternal()
{
this.isRunning = true;
super.onResumeInternal();
this.voiceInputHelper.registerGrammarLoaders();
this.voiceInputHelper.setWantAudioData(shouldProvideAudioData());
NetworkUtil.checkNetwork();
VoiceConfig localVoiceConfig = new VoiceConfig();
String[] arrayOfString = new String[1];
arrayOfString[0] = "nice";
localVoiceConfig = localVoiceConfig.setCustomPhrases(arrayOfString).setShouldSaveAudio(true);
voiceInputHelper.setVoiceConfig(localVoiceConfig);
}
public boolean isVoiceMenuShowing()
{
return (this.voiceMenuDialog != null) && (this.voiceMenuDialog.isShowing());
}
public VoiceConfig onVoiceCommand(VoiceCommand paramVoiceCommand)
{
Log.d("hhh",paramVoiceCommand.toString());
this.logger.w("Unrecognized voice command: %s", new Object[] { paramVoiceCommand });
return null;
}
protected Bundle getVoiceServiceExtras()
{
Bundle localBundle = new Bundle();
/* if (getIntent().hasExtra("serviceExtras"))
{
localBundle.putAll(getIntent().getBundleExtra("serviceExtras"));
}*/
return localBundle;
}
public void setVoiceConfig(VoiceConfig paramVoiceConfig)
{
this.voiceConfig = paramVoiceConfig;
if (paramVoiceConfig != null) {
this.voiceInputHelper.setVoiceConfig(this.voiceConfig);
}
}
public boolean shouldProvideAudioData()
{
return false;
}
public void onVoiceConfigChanged(VoiceConfig paramVoiceConfig, boolean paramBoolean) {}
}
DelegatingVoiceListener :
class DelegatingVoiceListener implements VoiceListener
{
private final VoiceListener delegate;
DelegatingVoiceListener(VoiceListener paramVoiceListener)
{
this.delegate = paramVoiceListener;
}
public FormattingLogger getLogger()
{
return this.delegate.getLogger();
}
public boolean isRunning()
{
return this.delegate.isRunning();
}
public boolean onResampledAudioData(byte[] paramArrayOfByte, int paramInt1, int paramInt2)
{
return this.delegate.onResampledAudioData(paramArrayOfByte, paramInt1, paramInt2);
}
public VoiceConfig onVoiceCommand(VoiceCommand paramVoiceCommand)
{
return this.delegate.onVoiceCommand(paramVoiceCommand);
}
public void onVoiceConfigChanged(VoiceConfig paramVoiceConfig, boolean paramBoolean)
{
this.delegate.onVoiceConfigChanged(paramVoiceConfig, paramBoolean);
}
}
You need to request special permissions in your manifest to implement unlisted voice commands. Go here. However, I doubt you can change the 'ok glass' voice command. You can still try if you really want to.