I have a problem in my code. I want to autoplay first video from recyclerview in ExoPlayer, The player is working good on scroll but the first video does not play automatically
public class VideoPlayerRecyclerView extends RecyclerView {
private static final String TAG = "VideoPlayerRecyclerView";
private enum VolumeState {ON, OFF};
// ui
private ImageView thumbnail, volumeControl;
private ProgressBar progressBar;
private View viewHolderParent;
private FrameLayout frameLayout;
private PlayerView videoSurfaceView;
private SimpleExoPlayer videoPlayer;
// vars
private ArrayList<Status_Bakend> 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 playback state
private VolumeState volumeState;
public VideoPlayerRecyclerView(#NonNull Context context) {
super(context);
init(context);
}
public VideoPlayerRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(final Context context){
this.context = context.getApplicationContext();
Display display = ((WindowManager) 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);
// 2. Create the player
videoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
// Bind the player to the view.
videoSurfaceView.setUseController(false);
videoSurfaceView.setPlayer(videoPlayer);
setVolumeControl(VolumeState.ON);
playVideo(true);
videoPlayer.setPlayWhenReady(true);
addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
Log.d(TAG, "onScrollStateChanged: called.");
if(thumbnail != null){ // show the old thumbnail
thumbnail.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(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
addOnChildAttachStateChangeListener(new OnChildAttachStateChangeListener() {
#Override
public void onChildViewAttachedToWindow(View view) {
}
#Override
public void onChildViewDetachedFromWindow(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);
}
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(!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) 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;
}
Toast.makeText(context, "playVideo: target position: " + targetPosition, Toast.LENGTH_SHORT).show();
// 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);
int currentPosition = targetPosition - ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
View child = getChildAt(currentPosition);
if (child == null) {
return;
}
VideoPlayerViewHolder holder = (VideoPlayerViewHolder) child.getTag();
if (holder == null) {
playPosition = -1;
return;
}
thumbnail = holder.thumbnail;
progressBar = holder.progressBar;
volumeControl = holder.volumeControl;
viewHolderParent = holder.itemView;
requestManager = holder.requestManager;
frameLayout = holder.itemView.findViewById(R.id.media_container);
videoSurfaceView.setPlayer(videoPlayer);
videoPlayer.addVideoListener(new VideoListener() {
#Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
frameLayout.getLayoutParams().height = (height * 2);
}
#Override
public void onRenderedFirstFrame() {
}
});
viewHolderParent.setOnClickListener(videoViewClickListener);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(
context, Util.getUserAgent(context, "RecyclerView VideoPlayer"));
String mediaUrl = mediaObjects.get(targetPosition).getStatus_link();
if (mediaUrl != null) {
MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(mediaUrl));
videoPlayer.prepare(videoSource);
videoPlayer.setPlayWhenReady(true);
}
}
private OnClickListener videoViewClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
toggleVolume();
}
};
/**
* Returns the visible region of the video surface on the screen.
* if some are cut off, it will return less than the #videoSurfaceDefaultHeight
* #param playPosition
* #return
*/
private int getVisibleVideoSurfaceHeight(int playPosition) {
int at = playPosition - ((LinearLayoutManager) 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(){
frameLayout.addView(videoSurfaceView);
isVideoViewAdded = true;
videoSurfaceView.requestFocus();
videoSurfaceView.setVisibility(VISIBLE);
videoSurfaceView.setAlpha(1);
}
private void resetVideoView(){
if(isVideoViewAdded){
removeVideoView(videoSurfaceView);
playPosition = -1;
videoSurfaceView.setVisibility(INVISIBLE);
}
}
public void releasePlayer() {
if (videoPlayer != null) {
videoPlayer.release();
videoPlayer = null;
}
viewHolderParent = null;
}
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);
}
}
}
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_favorite_border_black_24dp)
.into(volumeControl);
}
else if(volumeState == VolumeState.ON){
requestManager.load(R.drawable.ic_favorite_border_black_24dp)
.into(volumeControl);
}
volumeControl.animate().cancel();
volumeControl.setAlpha(1f);
volumeControl.animate()
.alpha(0f)
.setDuration(600).setStartDelay(1000);
}
}
public void setMediaObjects(ArrayList<Status_Bakend> mediaObjects){
this.mediaObjects = mediaObjects;
}
}
This is my code on recyclerview scroll working fine on scroll but I want to autoplay my first video in recyclerview without scrolling.
Just add this line after setAdapter to the recycler view.
recyclerView.smoothScrollBy(0, -1);
OR
recyclerView.smoothScrollBy(0, 1);
This will solve your problem.
You only need to make the first video play using postDelayed().
I think the reason is that the views of the RecyclerView items are all drawn on the layout and the video play process are duplicated.
Related
So I've been trying to fix this issue for so many hours but can't find the cause behind it.
Issue: My app shows data from my API into recyclerView, a standard feature. The issue comes when I use the search function. When I search for something, my search adapter shows the query data but going back to my Main fragment again, the view loader shows content fine but when I click on it, search items are actually being loaded instead.
Check my app to find out what I'm talking about: https://play.google.com/store/apps/details?id=envision.apps.newsextra
To reproduce, search for something, click on any article from search results, then go back and click any article from main feed, search items are actually being loaded instead.
Here's my main fragment:
public class FeedsFragment extends Fragment implements ArticleListener, LocalMessageCallback {
private PullRefreshLayout pullRefreshLayout;
private RecyclerView recyclerView;
private FeedsAdapter adapter;
private View layout;
private ArrayList<Object> data = new ArrayList<>();
private List<Favorites> favorites = new ArrayList<>();
private List<Articles> articles = new ArrayList<>();
private boolean init = true;
private DataViewModel dataViewModel;
private NativeAdsManager mNativeAdsManager;
private String sort_date = SharedPrefernces.getFeedSortDate();
public static FeedsFragment newInstance() {
return new FeedsFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
layout = inflater.inflate(R.layout.feeds_fragment_layout, container, false);
init_views();
setRecyclerView();
initNativeAds();
dataViewModel = ViewModelProviders.of(this).get(DataViewModel.class);
dataViewModel.getFavorites().observe(this, favorites -> {
if(favorites!=null){
this.favorites = favorites;
}
});
dataViewModel.getArticles().observe(this, articles -> {
this.articles = articles;
if(init) {
if (articles!= null && articles.size() > 0) {
//this.articles = articles;
data = new ArrayList<>();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(getString(R.string.all_stories))){
data.add(new Info("Showing stories based on all your interests"));
}else{
data.add(new Info("Showing stories on "+SharedPrefernces.getActiveInterest()));
}
data.addAll(articles);
adapter.setData(data);
}
init = false;
}
});
new Handler().postDelayed(() -> {
//we first check if time set to fetch feeds again has elapsed
pullRefreshLayout.setRefreshing(true);
fetchFeeds();
SharedPrefernces.setReloadArticles(false);
}, 1000);
return layout;
}
//init view layouts
private void init_views(){
pullRefreshLayout = layout.findViewById(R.id.pullRefreshLayout);
int[] colorScheme = getResources().getIntArray(R.array.refresh_color_scheme);
pullRefreshLayout.setColorSchemeColors(colorScheme);
pullRefreshLayout.setOnRefreshListener(this::fetchFeeds);
}
//init recyclerview
private void setRecyclerView() {
recyclerView = (RecyclerView) layout.findViewById(R.id.recyclerView);
GridLayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 1);
recyclerView.setLayoutManager(mLayoutManager);
adapter = new FeedsAdapter(getActivity(),recyclerView,this);
//int index = movies.size() - 1;
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(data.size()>0 && data.get(1) instanceof Articles){
adapter.setLoader();
loadMoreFeeds();
}
}));
recyclerView.setAdapter(adapter);
}
private void initNativeAds(){
mNativeAdsManager = new NativeAdsManager(getActivity(), getResources().getString(R.string.FACEBOOK_FEED_NATIVE_AD), 10);
mNativeAdsManager.loadAds();
mNativeAdsManager.setListener(new NativeAdsManager.Listener() {
#Override
public void onAdsLoaded() {
}
#Override
public void onAdError(AdError adError) {
}
});
}
private void fetchFeeds(){
if(!NetworkUtil.hasConnection(getActivity())) {
setNetworkError();
return;
}
NetworkService service = StringApiClient.createServiceWithToken(NetworkService.class);
try {
JSONObject jsonData = new JSONObject();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(getString(R.string.all_stories))) {
jsonData.put("interests", new JSONArray(SharedPrefernces.getUserInterests()));
}else{
ArrayList<String> interest = new ArrayList<>();
interest.add(SharedPrefernces.getActiveInterest());
jsonData.put("interests", new JSONArray(interest));
}
if(SharedPrefernces.getUserUnfollowedFeedSources()!=null && SharedPrefernces.getUserUnfollowedFeedSources().size()>0) {
jsonData.put("sources", new JSONArray(SharedPrefernces.getUserUnfollowedFeedSources()));
}
jsonData.put("location", Misc.getCurrentCountryCode());
String requestBody = jsonData.toString();
Log.e("final requestbody",requestBody);
Call<String> callAsync = service.getArticles(requestBody);
callAsync.enqueue(new Callback<String>() {
#Override
public void onResponse(#NonNull Call<String> call, #NonNull Response<String> response) {
Log.e("response",String.valueOf(response.body()));
pullRefreshLayout.setRefreshing(false);
if(response.body()==null){
setNetworkError();
return;
}
try {
JSONObject res = new JSONObject(response.body());
// Add Your Logic
if(res.getString("status").equalsIgnoreCase("ok")){
//create a new object
data = new ArrayList<>();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(getString(R.string.all_stories))){
data.add(new Info("Showing stories based on all your interests"));
}else{
data.add(new Info("Showing Stories on "+SharedPrefernces.getActiveInterest()));
}
sort_date = res.getString("date");
SharedPrefernces.setFeedSortDate(sort_date);
ArrayList<Articles> articles = JsonParser.getArticles(res.getJSONArray("feeds"));
//delete all previously store articles, and add new items to database
dataViewModel.deleteAllArticles();
dataViewModel.insertAllArticles(articles);
//append interests to our object list
data.addAll(articles);
//set data to adapter
adapter.setData(data);
//set last fetched time to sharedpreferences
if(articles.size()>0)SharedPrefernces.setArticleLastRefreshTime(System.currentTimeMillis());
}
}catch (Exception e){
e.printStackTrace();
Log.e("error",e.getMessage());
}
}
#Override
public void onFailure(#NonNull Call<String> call, #NonNull Throwable throwable) {
Log.e("error",String.valueOf(throwable.getMessage()));
setNetworkError();
pullRefreshLayout.setRefreshing(false);
}
});
} catch (JSONException e) {
Log.e("parse error",e.getMessage());
e.printStackTrace();
}
}
private void loadMoreFeeds(){
// ToDo
}
private void setNetworkError(){
dataViewModel.deleteAllArticles();
dataViewModel.insertAllArticles(articles);
pullRefreshLayout.setRefreshing(false);
data = new ArrayList<>();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(App.getContext().getString(R.string.all_stories))){
data.add(new Info("Showing stories based on all your interests"));
}else{
data.add(new Info("Showing stories on "+SharedPrefernces.getActiveInterest()));
}
data.add(new Error(""));
adapter.setData(data);
}
#Override
public void OnItemClick(Articles article) {
//List<Integer> contestWinners = data.subList(0, 5);
int position = 0;
for (Articles arts: this.articles) {
if(arts.getId() == article.getId()){
position = this.articles.indexOf(arts);
}
}
Gson gson = new Gson();
String json = gson.toJson(article);
Intent intent = new Intent(getActivity(), FeedViewerActivity.class);
intent.putExtra("position", position);
intent.putExtra("article",json);
intent.putExtra(FeedViewerActivity.VIEW_TYPE, Constants.ARTICLE_VIEW);
intent.putExtra(FeedViewerActivity.VIEW_SIZE, get_feeds_view_size(this.articles,position));
startActivity(intent);
Objects.requireNonNull(getActivity()).overridePendingTransition(R.anim.slide_left_in, R.anim.still);
}
#Override
public void OnPinClick(Articles articles,String action) {
if(articles==null)return;
if(action.equalsIgnoreCase(getResources().getString(R.string.add_pin))){
dataViewModel.insertFavorites(ObjectMapper.mapFavorites(articles));
}else {
dataViewModel.deleteFavorite(ObjectMapper.mapFavorites(articles).getId());
}
}
#Override
public void OnShareClick(Articles articles) {
Intent share = new Intent(android.content.Intent.ACTION_SEND);
share.setType("text/plain");
share.putExtra(Intent.EXTRA_SUBJECT, articles.getTitle());
share.putExtra(Intent.EXTRA_TEXT, articles.getLink());
startActivity(Intent.createChooser(share, "Share Article"));
}
#Override
public boolean IsPinned(Articles articles) {
for (Favorites fav: favorites) {
if(fav.getId() == articles.getId()){
return true;
}
}
return false;
}
#Override
public void requestAds(int position) {
NativeAd ad = mNativeAdsManager.nextNativeAd();
if(ad!=null){
adapter.setAd(ad,position);
}
}
#Override
public void loadSingleFeedsActivity(Articles articles) {
Gson gson = new Gson();
String myJson = gson.toJson(articles);
Intent intent = new Intent(getActivity(), FeedSourceActivity.class);
intent.putExtra("article", myJson);
startActivity(intent);
}
#Override
public boolean isSingleFeedsActivity() {
return false;
}
#Override
public void onDestroy() {
LocalMessageManager.getInstance().send(R.id.remove_listener);
LocalMessageManager.getInstance().removeListener(this);
super.onDestroy();
}
#Override
public void onStart() {
super.onStart();
LocalMessageManager.getInstance().addListener(this);
}
#Override
public void handleMessage(#NonNull LocalMessage localMessage) {
if(localMessage.getId() == R.id.reload_feeds){
pullRefreshLayout.setRefreshing(true);
fetchFeeds();
SharedPrefernces.setReloadArticles(false);
}
if(localMessage.getId() == R.id.scroll_feeds_to_top){
recyclerView.smoothScrollToPosition(0);
}
}
}
Adapter:
public class FeedsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {
private ArrayList<Object> data = new ArrayList<>();
private Context context;
private int lastItemPosition = -1;
private final int VIEW_TYPE_HEADER = 1;
private final int VIEW_TYPE_LIST = 2;
private final int VIEW_TYPE_LOADER = 3;
private final int VIEW_TYPE_NETWORK_ERROR = 4;
private final int VIEW_TYPE_INFO = 5;
private final int VIEW_TYPE_AD = 6;
private boolean isLoading = false;
private LoadMoreListener loadMoreListener;
private int visibleThreshold = 2;//visible items before loading next feeds
private int firstVisibleItem,lastVisibleItem, totalItemCount;
private ArticleListener articleListener;
public FeedsAdapter(Context context, RecyclerView mRecyclerView, ArticleListener articleListener) {
this.context=context;
this.articleListener = articleListener;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LocalMessageManager.getInstance().send(R.id.recyclerview_scroll);
firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if ((firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD) % Constants.ADS.LOAD_ADS_AT_POSITION == 0){
//
int pos = firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD;
if(pos > lastItemPosition && data.size()>pos && data.get(pos - 1) != null/*dont load ad if we r currently making a request*/) {
if (!(data.get(pos) instanceof NativeAd)) {
articleListener.requestAds(pos);
}
}
}
if (!isLoading && NetworkUtil.hasConnection(context)) {
if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (loadMoreListener != null) {
loadMoreListener.onLoadMore();
}
isLoading = true;
}
}
}
});
}
#Override
public int getItemViewType(int position) {
if(data.get(position) instanceof Error)return VIEW_TYPE_NETWORK_ERROR;
if(data.get(position) instanceof Info)return VIEW_TYPE_INFO;
if(data.get(position) instanceof NativeAd)return VIEW_TYPE_AD;
if(SharedPrefernces.get_feed_images_show()
&& SharedPrefernces.get_feed_type() == 1
&& position==1 && data.get(position) instanceof Articles){
return VIEW_TYPE_HEADER;
}
if(data.get(position) == null)return VIEW_TYPE_LOADER;
return VIEW_TYPE_LIST;
}
public void setData(ArrayList<Object> objectList) {
Log.e("objectList size",String.valueOf(objectList.size()));
this.data.clear();
this.data.addAll(objectList);
Log.e("data size",String.valueOf(data.size()));
this.notifyDataSetChanged();
}
public void setMoreData(ArrayList<Articles> articles) {
//int start = data.size() + 2;
data.addAll(articles);
//this.notifyItemRangeInserted(start, articles.size());
this.notifyDataSetChanged();
}
public void setAd(NativeAd ad, int pos) {
data.add(pos, ad);
this.notifyItemInserted(pos);
}
#Override
public int getItemCount() {
return data != null ? data.size() : 0;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
lastItemPosition = position;
//Log.e("view type",String.valueOf(holder.getItemViewType()));
switch (holder.getItemViewType()) {
case VIEW_TYPE_LIST: case VIEW_TYPE_HEADER:
final ArticleViewHolder viewHolder = (ArticleViewHolder) holder;
viewHolder.bindTo((Articles) data.get(position));
break;
case VIEW_TYPE_LOADER:
final ViewLoader viewLoader = (ViewLoader) holder;
viewLoader.rotateLoading.start();
break;
case VIEW_TYPE_NETWORK_ERROR:
ViewError viewError = (ViewError) holder;
if(SharedPrefernces.getUseNightMode()){
viewError.img.setColorFilter(App.getContext().getResources().getColor(R.color.white));
}else{
viewError.img.setColorFilter(App.getContext().getResources().getColor(R.color.black));
}
break;
case VIEW_TYPE_INFO:
final ViewInfo viewInfo = (ViewInfo) holder;
Info info = (Info)data.get(position);
viewInfo.body.setText(info.getContent());
break;
case VIEW_TYPE_AD:
final AdsViewHolder adsViewHolder = (AdsViewHolder) holder;
NativeAd nativeAd = (NativeAd)data.get(position);
adsViewHolder.bind(nativeAd);
break;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(context);
switch (i) {
case VIEW_TYPE_HEADER:
View v = inflater.inflate(R.layout.feeds_header, parent, false);
viewHolder = new ArticleViewHolder(v, articleListener);
break;
case VIEW_TYPE_LIST:
View va;
if(SharedPrefernces.get_feed_images_show() && SharedPrefernces.get_feed_type()==0){
va = inflater.inflate(R.layout.large_image_feeds_list, parent, false);
}else{
va = inflater.inflate(R.layout.feeds_list, parent, false);
}
viewHolder = new ArticleViewHolder(va, articleListener);
break;
case VIEW_TYPE_LOADER:
View ld = inflater.inflate(R.layout.loader, parent, false);
viewHolder = new ViewLoader(ld);
break;
case VIEW_TYPE_NETWORK_ERROR:
View ne = inflater.inflate(R.layout.no_stories, parent, false);
viewHolder = new ViewError(ne);
break;
case VIEW_TYPE_INFO:
View info = inflater.inflate(R.layout.info, parent, false);
viewHolder = new ViewInfo(info);
break;
case VIEW_TYPE_AD:
View ads = inflater.inflate(R.layout.ad_item_large, parent, false);
viewHolder = new AdsViewHolder(ads);
break;
}
return viewHolder;
}
#Override
public void onClick(View view) {
//int pos = (int) view.getTag();
switch (view.getId()){
case R.id.pin:
break;
case R.id.share:
break;
}
}
public class ViewLoader extends RecyclerView.ViewHolder {
private RotateLoading rotateLoading;
ViewLoader(View view) {
super(view);
rotateLoading = (RotateLoading) view.findViewById(R.id.rotateloading);
}
}
public class ViewError extends RecyclerView.ViewHolder {
private ImageView img;
ViewError(View view) {
super(view);
img = view.findViewById(R.id.img);
}
}
public class ViewInfo extends RecyclerView.ViewHolder {
private TextView body;
ViewInfo(View view) {
super(view);
body = view.findViewById(R.id.body);
}
}
public void setLoaded(){
data.remove(data.size()-1);
this.notifyItemRemoved(data.size()-1);
isLoading = false;
}
public void setLoadMoreListener(LoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void setLoader(){
data.add(null);
this.notifyItemInserted(data.size()-1);
}
}
Search Adapter:
public class SearchAdapter extends RecyclerView.Adapter< RecyclerView.ViewHolder>{
private List<Object> items = new ArrayList<>();
private final int VIEW_TYPE_MEDIA = 0;
private final int VIEW_TYPE_LOADING = 1;
private final int VIEW_TYPE_AD = 2;
private SearchClickListener searchClickListener;
private LoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 2;
public int firstVisibleItem,lastVisibleItem, totalItemCount;
private int lastItemPosition = -1;
public SearchAdapter(RecyclerView mRecyclerView, SearchClickListener searchClickListener) {
this.searchClickListener = searchClickListener;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if ((firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD) % Constants.ADS.LOAD_ADS_AT_POSITION == 0){
//
int pos = firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD;
if(pos > lastItemPosition && items.size()>pos && items.get(pos - 1) != null/*dont load ad if we r currently making a request*/) {
if (!(items.get(pos) instanceof NativeAd)) {
searchClickListener.requestAds(pos);
}
}
}
if (!isLoading && NetworkUtil.hasConnection(App.getContext())) {
if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (items.size() > 1 && mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
}
});
}
public void setMoreAdapter(List<Search> data) {
items.addAll(data);
//items.addAll((items.size()-1),data);
this.notifyDataSetChanged();
}
public void setAdapter(List<Search> data) {
items = new ArrayList<>();
items.addAll(data);
this.notifyDataSetChanged();
}
#Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
#Override
public int getItemViewType(int position) {
if(items.get(position) instanceof NativeAd)return VIEW_TYPE_AD;
if(items.get(position)==null && position == (items.size()-1)){
return VIEW_TYPE_LOADING;
}else{
return VIEW_TYPE_MEDIA;
}
}
public void setLoader() {
items.add(null);
this.notifyItemInserted(items.size() - 1);
}
public void setAd(NativeAd ad, int pos) {
items.add(pos, ad);
this.notifyItemInserted(pos);
}
public void removeLoader() {
items.remove(items.size() - 1);
this.notifyItemRemoved(items.size());
}
public void setOnLoadMoreListener(LoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (i) {
case VIEW_TYPE_MEDIA:
View v = inflater.inflate(R.layout.search_list, viewGroup, false);
viewHolder = new SearchViewHolder(v,searchClickListener);
viewHolder.itemView.setClickable(true);
break;
case VIEW_TYPE_LOADING:
View vL = inflater.inflate(R.layout.loader, viewGroup, false);
viewHolder = new LoadingViewHolder(vL);
break;
case VIEW_TYPE_AD:
View ads = inflater.inflate(R.layout.ad_item_small, viewGroup, false);
viewHolder = new AdsViewHolder(ads);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
lastItemPosition = i;
switch (holder.getItemViewType()) {
case VIEW_TYPE_LOADING:
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.start();
break;
case VIEW_TYPE_MEDIA:
final SearchViewHolder viewHolder = (SearchViewHolder) holder;
final Search ci = (Search)items.get(i);
viewHolder.bindTo(ci);
break;
case VIEW_TYPE_AD:
final AdsViewHolder adsViewHolder = (AdsViewHolder) holder;
NativeAd nativeAd = (NativeAd)items.get(i);
adsViewHolder.bind(nativeAd);
break;
}
}
private static class LoadingViewHolder extends RecyclerView.ViewHolder {
private RotateLoading progressBar;
private LoadingViewHolder(View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.rotateloading);
}
}
public void setLoaded() {
isLoading = false;
}
public interface SearchClickListener {
void onClick(Search search);
void requestAds(int position);
}
}
Seriously any help will be greatly appreciated.
Due to the character limit, I'm posting my viewHolder code here as a comment.
ArticleViewHolder:
public class ArticleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, LocalMessageCallback {
private Articles articles;
private TextView title,interest,time,source,content;
private LinearLayout revealView;
private ImageView thumbnail,pin,source_link;
private Animation alphaAnimation;
private float pixelDensity;
private boolean flag = false;
private RelativeLayout revealLayout,layoutButtons;
private ArticleListener articleListener;
private CardView cardView;
private String pin_action = "add";
public ArticleViewHolder(View view, ArticleListener articleListener) {
super(view);
this.articleListener = articleListener;
pixelDensity = App.getContext().getResources().getDisplayMetrics().density;
alphaAnimation = AnimationUtils.loadAnimation(App.getContext(), R.anim.alpha_anim);
LocalMessageManager.getInstance().addListener(this);
FrameLayout source_holder = view.findViewById(R.id.source_holder);
cardView = view.findViewById(R.id.card_view);
source_link = view.findViewById(R.id.source_link);
revealLayout = view.findViewById(R.id.revealLayout);
revealView = view.findViewById(R.id.revealView);
layoutButtons = view.findViewById(R.id.layoutButtons);
title = view.findViewById(R.id.title);
content = view.findViewById(R.id.content);
interest = view.findViewById(R.id.interest);
thumbnail = view.findViewById(R.id.thumbnail);
time = view.findViewById(R.id.time);
source = view.findViewById(R.id.source);
ImageView reveal = view.findViewById(R.id.reveal);
ImageView close = view.findViewById(R.id.close);
pin = view.findViewById(R.id.pin);
ImageView share = view.findViewById(R.id.share);
reveal.setOnClickListener(this);
close.setOnClickListener(this);
pin.setOnClickListener(this);
share.setOnClickListener(this);
title.setOnClickListener(this);
content.setOnClickListener(this);
thumbnail.setOnClickListener(this);
source_holder.setOnClickListener(this);
}
public void bindTo(Articles articles) {
this.articles = articles;
title.setText(articles.getTitle());
content.setText(articles.getContent().replace("\n", " ").replace("\r", " "));
interest.setText(articles.getInterest());
//Log.e("thumbnail",String.valueOf(articles.getThumbnail()));
if(SharedPrefernces.get_feed_images_show()) {
thumbnail.setVisibility(View.VISIBLE);
ImageLoader.loadImage(thumbnail, articles.getThumbnail());
}else{
thumbnail.setVisibility(View.GONE);
}
time.setText(TimUtil.timeAgo(articles.getTimeStamp()));
String _source = articles.getSource();
source.setText(_source.substring(0,1).toUpperCase() + _source.substring(1).toLowerCase());
if(articleListener.IsPinned(articles)){
set_pin_view(true);
pin_action = App.getContext().getResources().getString(R.string.remove_pin);
}else{
set_pin_view(false);
pin_action = App.getContext().getResources().getString(R.string.add_pin);
}
if(flag){
revealView.setVisibility(View.VISIBLE);
layoutButtons.setVisibility(View.VISIBLE);
}else{
revealView.setVisibility(View.GONE);
layoutButtons.setVisibility(View.GONE);
}
if(articleListener.isSingleFeedsActivity()){
source_link.setVisibility(View.GONE);
}else{
source_link.setVisibility(View.VISIBLE);
}
if(!SharedPrefernces.getUseNightMode()){
cardView.setCardBackgroundColor(App.getContext().getResources().getColor(R.color.material_grey_100));
}
}
private void set_pin_view(boolean isPinned){
Drawable mDrawable;
if(!isPinned){
mDrawable = ContextCompat.getDrawable(App.getContext(),R.drawable.pin_outline);
mDrawable.setColorFilter(new
PorterDuffColorFilter(App.getContext().getResources().getColor(R.color.material_grey_200), PorterDuff.Mode.SRC_IN));
}else{
mDrawable = ContextCompat.getDrawable(App.getContext(),R.drawable.pin_outline);
mDrawable.setColorFilter(new
PorterDuffColorFilter(App.getContext().getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN));
}
pin.setImageDrawable(mDrawable);
}
#Override
public void onClick(View view) {
LocalMessageManager.getInstance().send(R.id.hide_reveal_layout,articles.getId());
if (articleListener != null) {
if(view.getId() == R.id.reveal || view.getId() == R.id.close){
revealLayout();
}else if(view.getId() == R.id.source_holder){
articleListener.loadSingleFeedsActivity(articles);
}else if(view.getId() == R.id.pin){
articleListener.OnPinClick(articles,pin_action);
if(pin_action.equalsIgnoreCase(App.getContext().getResources().getString(R.string.add_pin))){
pin_action = App.getContext().getResources().getString(R.string.remove_pin);
set_pin_view(true);
}else{
pin_action = App.getContext().getResources().getString(R.string.add_pin);
set_pin_view(false);
}
revealLayout();
}else if(view.getId() == R.id.share){
articleListener.OnShareClick(articles);
revealLayout();
}else if(view.getId() == R.id.title || view.getId() == R.id.thumbnail|| view.getId() == R.id.content) {
articleListener.OnItemClick(articles);
}
}
}
private void revealLayout() {
/*
MARGIN_RIGHT = 16;
FAB_BUTTON_RADIUS = 28;
*/
boolean isAttachedToWindow = ViewCompat.isAttachedToWindow(revealView);
if (isAttachedToWindow) {
int x = revealLayout.getRight();
int y = revealLayout.getBottom();
x -= ((28 * pixelDensity) + (16 * pixelDensity));
int hypotenuse = (int) Math.hypot(revealLayout.getWidth(), revealLayout.getHeight());
if (!flag) {
RelativeLayout.LayoutParams parameters = (RelativeLayout.LayoutParams)
revealView.getLayoutParams();
parameters.height = revealLayout.getHeight();
revealView.setLayoutParams(parameters);
Animator anim = ViewAnimationUtils.createCircularReveal(revealView, x, y, 0, hypotenuse);
anim.setDuration(200);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
layoutButtons.setVisibility(View.VISIBLE);
layoutButtons.startAnimation(alphaAnimation);
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
revealView.setVisibility(View.VISIBLE);
anim.start();
flag = true;
} else {
Animator anim = ViewAnimationUtils.createCircularReveal(revealView, x, y, hypotenuse, 0);
anim.setDuration(200);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
revealView.setVisibility(View.GONE);
layoutButtons.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.start();
flag = false;
}
}
}
#Override
public void handleMessage(#NonNull LocalMessage localMessage) {
switch (localMessage.getId()){
case R.id.hide_reveal_layout:
int id = localMessage.getArg1();
if(flag && id != articles.getId()){
revealLayout();
}
break;
case R.id.recyclerview_scroll:
if(flag){
revealLayout();
}
break;
}
}
}
There is Scroll by loading RecyclerView(Lazy loading). When an item quantity is incremented by adding the plus button to say 10. after loading the next set of items while scrolling, The item quantity(10) is reset to 1 and 10 will be displayed for another item.
In the same sequence, if the unit is changed(by the spinner) to another unit the corresponding image will be loaded but after scrolling the unit and image will change back to initial unit.
When the image of an item is clicked, a dialog will show the details of the selected item . Sometimes the image in the dialog is correct but image of the RecyclerView is incorrect, will take time to load or will not load.
public class ArticleRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements Filterable {
private static final String TAG = "ArticleAdapter";
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private Context context;
private Dialog articleDescriptionDialog;
private UOMOffersLIistViewAdapter uomOffersLIistViewAdapter;
private List<ArticleDetails> articleDetailsList;
private HomeActivityViewModel homeActivityViewModel;
private ItemFilter itemFilter = new ItemFilter();
private GetViewListener getViewListener;
private int lastPosition = -1;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
/*
* isLoading - to set the remote loading and complete status to fix back to back load more call
* isMoreDataAvailable - to set whether more data from server available or not.
* It will prevent useless load more request even after all the server data loaded
* */
public ArticleRecyclerViewAdapter(Context context, List<ArticleDetails> articleDetailsList
, HomeActivityViewModel homeActivityViewModel, Fragment fragment) {
this.context = context;
this.articleDetailsList = articleDetailsList;
this.homeActivityViewModel = homeActivityViewModel;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == VIEW_TYPE_ITEM) {
return new ItemViewHolder(inflater.inflate(R.layout.recycler_view_article_layout, parent, false));
} else {
return new LoadHolder(inflater.inflate(R.layout.item_loading_layout, parent, false));
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
if (getItemViewType(position) == VIEW_TYPE_ITEM) {
populateItemRows((ItemViewHolder) viewHolder, position);
}
//No else part needed as load holder doesn't bind any data
}
#Override
public int getItemViewType(int position) {
if (articleDetailsList.get(position).isLoading()) {
return VIEW_TYPE_LOADING;
} else {
return VIEW_TYPE_ITEM;
}
}
#Override
public int getItemCount() {
return articleDetailsList.size();
}
#Override
public long getItemId(int position) {
return position;
}
/* VIEW HOLDERS */
static class ItemViewHolder extends RecyclerView.ViewHolder {
private ImageView stockImageView, copyStockImageView;
private TextView articleNameTextView, articleStockAmountTextView, articleOfferTextView, addCartTextView;
private NumberPicker articleStockQuantityNumberPicker;
private Spinner articleStockSpinner;
private ImageButton offerInfoImageButton;
private int selectedStockItemPosition, stockQuantity;
private String articleStockQuantityString = "";
private Integer stockId;
private double stockAmount;
public ItemViewHolder(View itemView) {
super(itemView);
stockImageView = itemView.findViewById(R.id.stockImgv);
copyStockImageView = itemView.findViewById(R.id.copyStockImgv);//for fly to cart animation
articleNameTextView = itemView.findViewById(R.id.articleNameTxt);
articleStockAmountTextView = itemView.findViewById(R.id.stock_amount_txt);
articleOfferTextView = itemView.findViewById(R.id.offer_txt);
offerInfoImageButton = itemView.findViewById(R.id.offerInfo_imgbtn);
addCartTextView = itemView.findViewById(R.id.addCart_txt);
articleStockSpinner = itemView.findViewById(R.id.stock_spnr);
articleStockQuantityNumberPicker = itemView.findViewById(R.id.qty_numberPicker);
articleStockQuantityNumberPicker.setMin(1);
articleStockQuantityNumberPicker.setUnit(1);
// no limit.
// viewHolder.quantityNumberPicker.setMax(15);
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
public LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
/**
* notifyDataSetChanged is final method so we can't override it
* call articleRecyclerViewAdapter.notifyDataChanged(); after update the list
*/
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
private void populateItemRows(ItemViewHolder itemViewHolder, int itemPos) {
int itemPosition = itemViewHolder.getAdapterPosition();
try {
itemViewHolder.copyStockImageView.setImageResource(R.drawable.error_logo);//initialize with error logo.
itemViewHolder.stockImageView.setImageResource(R.drawable.error_logo);//initialize with error logo.
} catch (Exception e) {
e.printStackTrace();
}
itemViewHolder.articleNameTextView.setText(articleDetailsList.get(itemPosition).getArticleName());
itemViewHolder.articleNameTextView.setSelected(true);//for marquee
itemViewHolder.articleOfferTextView.setSelected(true);//for marquee
itemViewHolder.articleStockAmountTextView.setSelected(true);//for marquee
itemViewHolder.articleOfferTextView.setVisibility(View.GONE);//for demo (now no offer and schemes).
itemViewHolder.offerInfoImageButton.setVisibility(View.GONE);//for demo
setStockSpinner(itemViewHolder, itemPosition);
itemViewHolder.offerInfoImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//setUOMOffersDIalog(articleDetailsList.get(itemPosition));
}
});
itemViewHolder.articleStockQuantityNumberPicker.setValueChangedListener(new ValueChangedListener() {
#Override
public void valueChanged(int quantity, ActionEnum action) {
itemViewHolder.articleStockQuantityString = Integer.valueOf(quantity).toString();
}
});
itemViewHolder.addCartTextView.setOnClickListener(new SingleClickListener() {
#Override
public void onSingleClick(View v) {
itemViewHolder.articleStockQuantityString = Integer.valueOf(itemViewHolder.articleStockQuantityNumberPicker.getValue()).toString();
itemViewHolder.stockQuantity = Integer.valueOf(itemViewHolder.articleStockQuantityString);
itemViewHolder.stockAmount = articleDetailsList.get(itemPosition).getStockDetailsList()
.get(itemViewHolder.articleStockSpinner.getSelectedItemPosition()).getmRP();
itemViewHolder.stockId = articleDetailsList.get(itemPosition).getStockDetailsList()
.get(itemViewHolder.articleStockSpinner.getSelectedItemPosition()).getStockId();
Double stockDiscountAmount = 0.0;
//TODO: 26-Oct-19 discount hardcoded.
if (itemViewHolder.stockQuantity > 0) {
addItemToCart(itemViewHolder, itemViewHolder.stockId, itemViewHolder.stockQuantity, itemViewHolder.stockAmount, stockDiscountAmount);
} else {
//not using (used for when user enter invalid quantity)
MDToast.makeText(context, FinalVariables.ToastMessages.VALID_QUANTITY
, MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show();
}
}
});
itemViewHolder.stockImageView.setOnClickListener(new SingleClickListener() {
#Override
public void onSingleClick(View v) {
itemViewHolder.articleOfferTextView.setVisibility(View.VISIBLE);
itemViewHolder.articleOfferTextView.setText( ""+ itemViewHolder.stockQuantity);
DialogUtils.showArticleDescription(context, articleDetailsList.get(itemPosition)
, itemViewHolder.selectedStockItemPosition, new DialogButtonClickListener() {
#Override
public void positiveButtonClick() {
//do nothing.
}
});
}
});
// Here you apply the animation when the view is bound
setAnimation(itemViewHolder.itemView, itemPosition);
}
private void setStockSpinner(ItemViewHolder itemViewHolder, int itemPosition) {
UOMSpinnerAdapter uomSpinnerAdapter = new UOMSpinnerAdapter(context, R.layout.spinner_uom_layout
, StringUtils.makeUomStringArrayForSpinner(articleDetailsList.get(itemPosition).getStockDetailsList()));
itemViewHolder.articleStockSpinner.setAdapter(uomSpinnerAdapter);
// Setting OnItemClickListener to the Spinner
itemViewHolder.articleStockSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
itemViewHolder.selectedStockItemPosition = position;
itemViewHolder.articleStockAmountTextView.setText(StringUtils.addAED(StringUtils.round3(
+articleDetailsList.get(itemPosition)
.getStockDetailsList().get(position).getmRP())));
//show image from link
try {
if (!articleDetailsList.get(itemPosition).getStockDetailsList().
get(position).getStockImageDetailsList().isEmpty()) {
ImageUtils.setGlide(context, itemViewHolder.stockImageView
, articleDetailsList.get(itemPosition).getStockDetailsList().
get(position).getStockImageDetailsList().get(0).getStockImage());
//same as stockImageView but used to animate fly to cart
ImageUtils.setGlide(context, itemViewHolder.copyStockImageView
, articleDetailsList.get(itemPosition).getStockDetailsList().
get(position).getStockImageDetailsList().get(0).getStockImage());
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if (articleDetailsList.get(itemPosition).getStockDetailsList().size() > 0)
itemViewHolder.articleStockAmountTextView.setText(StringUtils.addAED(
StringUtils.round3(+articleDetailsList.get(itemPosition).getStockDetailsList().get(0).getmRP())));
itemViewHolder.selectedStockItemPosition = itemViewHolder.articleStockSpinner.getSelectedItemPosition();
}
});
}
private void addItemToCart(ItemViewHolder itemViewHolder, Integer stockId, Integer stockQuantity
, Double stockAmount, Double stockDiscountAmount) {
homeActivityViewModel.isItemAlreadyCarted(stockId
, new RetrieveDataListner() {
#Override
public void onDone(Object object) {
boolean isItemAlreadyCarted = (boolean) object;
if (!isItemAlreadyCarted) {//item not in cart,add to cart.
CartedItems cartedItem = new CartedItems();
cartedItem.setStockId(stockId);
cartedItem.setStockQuantity(stockQuantity);
cartedItem.setStockAmount(stockAmount);
cartedItem.setTotalAmount(CalcUtils.calculateTotalAmount(stockQuantity, stockAmount));
cartedItem.setNetAmount(CalcUtils.calculateNetAmount(stockQuantity
, stockAmount, stockDiscountAmount));
homeActivityViewModel.insertCartedItem(cartedItem
, new InsertDbSuccessListner() {
#Override
public void onSuccess() {
//set view to call back method for fly to cart animation
if (getViewListener != null){
getViewListener.onGetView(itemViewHolder.copyStockImageView);
}
itemViewHolder.articleStockQuantityNumberPicker.setValue(1);//reset item quantity in ui.
// TODO: 21-Mar-19 check fly to cart only in home activity or not
if (context instanceof MainActivity) {
MDToast.makeText(context, TextMessages.ITEM_ADDED
, MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show();
} else if (context instanceof HomeActivity) {
try {
((HomeActivity) context).setCartDetails();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure() {
}
});
} else {//item already carted,asking to add new quantity to carted quantity.
DialogUtils.showConformAlertDialog1(context, TextMessages.ITEM_ALREADY_CARTED
, TextMessages.ITEM_ALREADY_CARTED_WARNING
, StringValues.NO, StringValues.YES, new DialogButtonClickListener() {
#Override
public void positiveButtonClick() {//adding new quantity to existing quantity.
//set view to call back method for fly to cart animation
if (getViewListener != null)
getViewListener.onGetView(itemViewHolder.copyStockImageView);
homeActivityViewModel.updateCartedItemWithExistingValues(stockId, stockQuantity
, CalcUtils.calculateTotalAmount(stockQuantity, stockAmount),
CalcUtils.calculateNetAmount(stockQuantity, stockAmount, stockDiscountAmount)
, null);
itemViewHolder.articleStockQuantityNumberPicker.setValue(1);//reset item quantity in ui.
}
#Override
public void negativeButtonClick() {
}
});
}
}
});
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.fall_down);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
/**
* register listener for get article image(copyStockImageView)
* for fly to cart animation.
* the view get back to the call back(categorizedArticleFragment)).
*
* #param getViewListener
*/
public void setGetViewListener(GetViewListener getViewListener) {
this.getViewListener = getViewListener;
}
#Override
public Filter getFilter() {
return itemFilter;
}
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<ArticleDetails> list = articleDetailsList;
int count = list.size();
final List<ArticleDetails> nlist = new ArrayList<ArticleDetails>(count);
ArticleDetails filterableString;
for (int i = 0; i < count; i++) {
filterableString = list.get(i);
if (filterableString.getArticleName().toLowerCase().contains(filterString)) {
nlist.add(filterableString);
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
articleDetailsList = (ArrayList<ArticleDetails>) results.values;
notifyDataSetChanged();
}
}
}
Fragments onCreate
#Override
public View onCreateView(#NonNull LayoutInflater layoutInflater, ViewGroup viewGroup,
Bundle savedInstanceState) {
context = viewGroup.getContext();
parentView = layoutInflater.inflate(R.layout.fragment_article, viewGroup, false);
homeActivityViewModel = getViewModel();
articleRecyclerView = parentView.findViewById(R.id.subcategory_rcylv);
Bundle bundle = getArguments();
Integer offset = bundle.getInt(TagNames.OFFSET, 0);
Integer numberOfRows = bundle.getInt(TagNames.NUMBER_OF_ROWS, FinalVariables.GETTING_DATA_COUNT_FROM_API);
filterTypeId = bundle.getInt(TagNames.FILTER_TYPE_ID, FilterTypes.SUGGESTED);
String filterText = bundle.getString(TagNames.FILTER_TEXT, "");
Integer categoryId = bundle.getInt(TagNames.CATEGORY_ID, 0);
initArticleRecyclerViewAdapter(articleDetailsList, filterText, categoryId, offset, numberOfRows);
return parentView;
}
Initializing Adapter
private void initArticleRecyclerViewAdapter(List<ArticleDetails> articleDetailsList
, String filterText, Integer categoryId, int offset, int numberOfRows) {
articleRecyclerViewAdapter = new ArticleRecyclerViewAdapter(context, this.articleDetailsList, homeActivityViewModel, this);
articleRecyclerViewAdapter.setLoadMoreListener(new ArticleRecyclerViewAdapter.OnLoadMoreListener() {
#Override
public void onLoadMore() {
articleRecyclerView.post(new Runnable() {
#Override
public void run() {
int index = ArticleFragment.this.articleDetailsList.size();
loadMore(filterText, categoryId, index, numberOfRows);
Log.e(TAG, "scrolling,index: " + index);
}
});
//Calling loadMore function in Runnable to fix the
// java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling error
}
});
articleRecyclerView.setHasFixedSize(true);
articleRecyclerView.setLayoutManager(new GridLayoutManager(context, 3));
articleRecyclerView.setAdapter(articleRecyclerViewAdapter);
load(filterText, categoryId, offset, numberOfRows);
}
Loading data
private void loadMore(String filterText, Integer categoryId, int offset, int numberOfRows) {
//add loading progress view
articleDetailsList.add(new ArticleDetails(true));
articleRecyclerViewAdapter.notifyItemInserted(articleDetailsList.size() - 1);
Integer storeId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.STORE_ID);
Integer distributionChannelId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.DISTRIBUTION_CHANNEL_ID);
homeActivityViewModel.getAllStockItemByCustomer(
DeviceUtils.getCredential(context, ServiceNames.GET_ALL_STOCK_ITEM_BY_CUSTOMER)
, storeId, distributionChannelId, filterTypeId, filterText, categoryId, offset, numberOfRows
, new ApiCallbackListener() {
#Override
public void onSuccess(Object object) {
try {
if (object != null) {
if (object instanceof GetAllStockItemByCustomerStatusReturn) {
//otp generation failed,
GetAllStockItemByCustomerStatusReturn getAllStockItemByCustomerStatusReturn
= (GetAllStockItemByCustomerStatusReturn) object;
showGetAllStockItemByCustomerErrorDialog(getAllStockItemByCustomerStatusReturn);
} else if (object instanceof List) {
List<GetAllStockItemByCustomerResponseData> getAllStockItemByCustomerResponseDataList
= (List<GetAllStockItemByCustomerResponseData>) object;
//remove loading view
articleDetailsList.remove(articleDetailsList.size() - 1);
List<ArticleDetails> result = new ArrayList<>();
result = homeActivityViewModel.getArticles(getAllStockItemByCustomerResponseDataList);
homeActivityViewModel.insertAllStockItemByCustomer(context,filterTypeId
, getAllStockItemByCustomerResponseDataList, null);
if (result.size() > 0) {
//add loaded data
articleDetailsList.addAll(result);
} else {//result size 0 means there is no more data available at server
articleRecyclerViewAdapter.setMoreDataAvailable(false);
//telling articleRecyclerViewAdapter to stop calling load more as no more server data available
//Toast.makeText(context, "No More Data Available", Toast.LENGTH_LONG).show();
}
articleRecyclerViewAdapter.notifyDataChanged();
//should call the custom method articleRecyclerViewAdapter.notifyDataChanged here to get the correct loading status
} else {
MDToast.makeText(context, FinalVariables.ToastMessages.SOMETHING_WENT_WRONG
, MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show();
}
} else {
MDToast.makeText(context, FinalVariables.ToastMessages.SOMETHING_WENT_WRONG
, MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void load(String filterText, Integer categoryId, int offset, int numberOfRows) {
Integer storeId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.STORE_ID);
Integer distributionChannelId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.DISTRIBUTION_CHANNEL_ID);
homeActivityViewModel.getAllStockItemByCustomer(
DeviceUtils.getCredential(context, ServiceNames.GET_ALL_STOCK_ITEM_BY_CUSTOMER)
, storeId, distributionChannelId, filterTypeId, filterText, categoryId, offset, numberOfRows
, new ApiCallbackListener() {
#Override
public void onSuccess(Object object) {
try {
if (object != null) {
if (object instanceof GetAllStockItemByCustomerStatusReturn) {
GetAllStockItemByCustomerStatusReturn getAllStockItemByCustomerStatusReturn
= (GetAllStockItemByCustomerStatusReturn) object;
showGetAllStockItemByCustomerErrorDialog(getAllStockItemByCustomerStatusReturn);
} else if (object instanceof List) {
List<GetAllStockItemByCustomerResponseData> getAllStockItemByCustomerResponseDataList
= (List<GetAllStockItemByCustomerResponseData>) object;
if (!getAllStockItemByCustomerResponseDataList.isEmpty()) {
if (offset == 0 && getAllStockItemByCustomerResponseDataList.get(0)
.getCategoryID() == StatusCodes.INVALID_CODE
&& filterTypeId == FilterTypes.SUGGESTED) {
//shows all article from store (filter type 0) if no article is mapped in suggested.
filterTypeId = FilterTypes.ALL;
load(filterText, categoryId, offset, numberOfRows);
}
}
articleDetailsList.addAll(homeActivityViewModel.getArticles(getAllStockItemByCustomerResponseDataList));
homeActivityViewModel.insertAllStockItemByCustomer(context,filterTypeId
, getAllStockItemByCustomerResponseDataList, null);
articleRecyclerViewAdapter.notifyDataChanged();
} else {
}
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
I make whole video player app but stuck at mediacontroller. I want to show my own mediacontroller with different button, not the default one. It's 4rth day, i'm just trying to make my own mediacontroller but didn't succeed.
I succeed by doing it with surfaceview but i want to use it with videoview.
I try the following code.
public class MyMediaController extends MediaController {
private static final String TAG = "VideoControllerView";
MediaController.MediaPlayerControl mPlayer;
private Context mContext;
private View mAnchor;
private View mRoot;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet;
StringBuilder mFormatBuilder;
Formatter mFormatter;
private ImageButton mPauseButton;
private ImageButton mSubtitleButton;
private ImageButton mResizeButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
private final AccessibilityManager mAccessibilityManager;
public MyMediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = null;
mContext = context;
mUseFastForward = true;
mFromXml = true;
mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
public MyMediaController(Context context, boolean useFastForward) {
super(context, useFastForward);
mUseFastForward = useFastForward;
mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
public MyMediaController(Context context) {
this(context, true);
mContext = context;
}
#Override
public void setMediaPlayer(MediaController.MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
#Override
public void setAnchorView(View view) {
mAnchor = view;
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
protected View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = inflate.inflate(R.layout.media_controller_layout, null);
initControllerView(mRoot);
return mRoot;
}
private void initControllerView(View mRoot) {
mPauseButton = mRoot.findViewById(R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mResizeButton = mRoot.findViewById(R.id.resize);
if (mResizeButton != null) {
mResizeButton.requestFocus();
mResizeButton.setOnClickListener(mResizeListener);
}
mSubtitleButton = mRoot.findViewById(R.id.subtitle);
if (mSubtitleButton != null)
{
mSubtitleButton.requestFocus();
mSubtitleButton.setOnClickListener(mSubtitleListener);
}
mNextButton = mRoot.findViewById(R.id.next);
if (mNextButton != null ) {
mNextButton.requestFocus();
mNextButton.setOnClickListener(mNextListener);
}
mPrevButton = mRoot.findViewById(R.id.prev);
if (mPrevButton != null ) {
mPrevButton.requestFocus();
mPrevButton.setOnClickListener(mPrevListener);
}
mProgress = mRoot.findViewById(R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = mRoot.findViewById(R.id.time);
mCurrentTime = mRoot.findViewById(R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
}
public final View.OnClickListener mPauseListener = new OnClickListener() {
#Override
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private void doPauseResume() {
if (mPlayer == null) {
return;
}
if (mPlayer.isPlaying()) {
mPlayer.pause();
} else {
mPlayer.start();
}
updatePausePlay();
}
private void updatePausePlay() {
if (mRoot == null || mPauseButton == null)
return;
if (mPlayer.isPlaying())
mPauseButton.setImageResource(R.drawable.ic_pause);
else
mPauseButton.setImageResource(R.drawable.ic_play);
}
public final View.OnClickListener mResizeListener = new OnClickListener() {
#Override
public void onClick(View v) {
//Todo
Toast.makeText(mContext,"Resize is clicked",Toast.LENGTH_SHORT).show();
}
};
public final View.OnClickListener mNextListener = new OnClickListener() {
#Override
public void onClick(View v) {
//Todo
Toast.makeText(mContext,"NextBtn is clicked",Toast.LENGTH_SHORT).show();
}
};
public final View.OnClickListener mPrevListener = new OnClickListener() {
#Override
public void onClick(View v) {
//Todo
Toast.makeText(mContext,"PreviousBtn is clicked",Toast.LENGTH_SHORT).show();
}
};
public final View.OnClickListener mSubtitleListener = new OnClickListener() {
#Override
public void onClick(View v) {
//Todo
Toast.makeText(mContext,"subtitleBtn is clicked",Toast.LENGTH_SHORT).show();
}
};
private final SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
mDragging = true;
// By removing these pending progress messages we make sure
// that a) we won't update the progress while the user adjusts
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
removeCallbacks(mShowProgress);
}
#Override
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (!fromuser) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return;
}
long duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo( (int) newposition);
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime( (int) newposition));
}
#Override
public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
updatePausePlay();
show(sDefaultTimeout);
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
post(mShowProgress);
}
};
private int setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
int position = mPlayer.getCurrentPosition();
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
mProgress.setProgress( (int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
return position;
}
private String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
private final Runnable mShowProgress = new Runnable() {
#Override
public void run() {
int pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
postDelayed(mShowProgress, 1000 - (pos % 1000));
}
}
};
#Override
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
if (mPauseButton != null) {
mPauseButton.requestFocus();
}
FrameLayout.LayoutParams tlp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.BOTTOM
);
addView(this, tlp);
mShowing = true;
}
updatePausePlay();
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
post(mShowProgress);
if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
removeCallbacks(mFadeOut);
postDelayed(mFadeOut, timeout);
}
}
#Override
public boolean isShowing() {
return mShowing;
}
/**
* Remove the controller from the screen.
*/
#Override
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
removeCallbacks(mShowProgress);
removeView(this);
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
}
mShowing = false;
}
}
private final Runnable mFadeOut = new Runnable() {
#Override
public void run() {
hide();
}
};
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
show(0);
break;
case MotionEvent.ACTION_UP:
show(sDefaultTimeout);
break;
case MotionEvent.ACTION_CANCEL:
hide();
break;
default:
break;
}
return true;
}
}
Plz someone suggest my the right way to do it. I realy need help.
I'm currently developing an android application which detect objects using camera using tensorflow detection API. I want to take screenshot of the camera activity where the detection is happening.
How can I take screenshot of the camera activity including the camera preview itself?
This code came from tensorflow demo application. I just want to add a screenshot functionality using a button. That's why I added a button and an Image View. The Image View is where the screenshot preview will show but I dont have any idea on how to implement this :(
This is the code for the camera activity:
CameraActivity.java
public abstract class CameraActivity extends Activity
implements OnImageAvailableListener, Camera.PreviewCallback {
private static final Logger LOGGER = new Logger();
private static final int PERMISSIONS_REQUEST = 1;
private static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
private static final String PERMISSION_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
private boolean debug = false;
private Handler handler;
private HandlerThread handlerThread;
private boolean useCamera2API;
private boolean isProcessingFrame = false;
private byte[][] yuvBytes = new byte[3][];
private int[] rgbBytes = null;
private int yRowStride;
protected int previewWidth = 0;
protected int previewHeight = 0;
private Runnable postInferenceCallback;
private Runnable imageConverter;
#Override
protected void onCreate(final Bundle savedInstanceState) {
LOGGER.d("onCreate " + this);
super.onCreate(null);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_camera);
if (hasPermission()) {
setFragment();
} else {
requestPermission();
}
}
private byte[] lastPreviewFrame;
protected int[] getRgbBytes() {
imageConverter.run();
return rgbBytes;
}
protected int getLuminanceStride() {
return yRowStride;
}
protected byte[] getLuminance() {
return yuvBytes[0];
}
/**
* Callback for android.hardware.Camera API
*/
#Override
public void onPreviewFrame(final byte[] bytes, final Camera camera) {
if (isProcessingFrame) {
LOGGER.w("Dropping frame!");
return;
}
try {
// Initialize the storage bitmaps once when the resolution is known.
if (rgbBytes == null) {
Camera.Size previewSize = camera.getParameters().getPreviewSize();
previewHeight = previewSize.height;
previewWidth = previewSize.width;
rgbBytes = new int[previewWidth * previewHeight];
onPreviewSizeChosen(new Size(previewSize.width, previewSize.height), 90);
}
} catch (final Exception e) {
LOGGER.e(e, "Exception!");
return;
}
isProcessingFrame = true;
lastPreviewFrame = bytes;
yuvBytes[0] = bytes;
yRowStride = previewWidth;
imageConverter =
new Runnable() {
#Override
public void run() {
ImageUtils.convertYUV420SPToARGB8888(bytes, previewWidth, previewHeight, rgbBytes);
}
};
postInferenceCallback =
new Runnable() {
#Override
public void run() {
camera.addCallbackBuffer(bytes);
isProcessingFrame = false;
}
};
processImage();
}
/**
* Callback for Camera2 API
*/
#Override
public void onImageAvailable(final ImageReader reader) {
//We need wait until we have some size from onPreviewSizeChosen
if (previewWidth == 0 || previewHeight == 0) {
return;
}
if (rgbBytes == null) {
rgbBytes = new int[previewWidth * previewHeight];
}
try {
final Image image = reader.acquireLatestImage();
if (image == null) {
return;
}
if (isProcessingFrame) {
image.close();
return;
}
isProcessingFrame = true;
Trace.beginSection("imageAvailable");
final Plane[] planes = image.getPlanes();
fillBytes(planes, yuvBytes);
yRowStride = planes[0].getRowStride();
final int uvRowStride = planes[1].getRowStride();
final int uvPixelStride = planes[1].getPixelStride();
imageConverter =
new Runnable() {
#Override
public void run() {
ImageUtils.convertYUV420ToARGB8888(
yuvBytes[0],
yuvBytes[1],
yuvBytes[2],
previewWidth,
previewHeight,
yRowStride,
uvRowStride,
uvPixelStride,
rgbBytes);
}
};
postInferenceCallback =
new Runnable() {
#Override
public void run() {
image.close();
isProcessingFrame = false;
}
};
processImage();
} catch (final Exception e) {
LOGGER.e(e, "Exception!");
Trace.endSection();
return;
}
Trace.endSection();
}
#Override
public synchronized void onStart() {
LOGGER.d("onStart " + this);
super.onStart();
}
#Override
public synchronized void onResume() {
LOGGER.d("onResume " + this);
super.onResume();
handlerThread = new HandlerThread("inference");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
}
#Override
public synchronized void onPause() {
LOGGER.d("onPause " + this);
if (!isFinishing()) {
LOGGER.d("Requesting finish");
finish();
}
handlerThread.quitSafely();
try {
handlerThread.join();
handlerThread = null;
handler = null;
} catch (final InterruptedException e) {
LOGGER.e(e, "Exception!");
}
super.onPause();
}
#Override
public synchronized void onStop() {
LOGGER.d("onStop " + this);
super.onStop();
}
#Override
public synchronized void onDestroy() {
LOGGER.d("onDestroy " + this);
super.onDestroy();
}
protected synchronized void runInBackground(final Runnable r) {
if (handler != null) {
handler.post(r);
}
}
#Override
public void onRequestPermissionsResult(
final int requestCode, final String[] permissions, final int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
setFragment();
} else {
requestPermission();
}
}
}
private boolean hasPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return checkSelfPermission(PERMISSION_CAMERA) == PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(PERMISSION_STORAGE) == PackageManager.PERMISSION_GRANTED;
} else {
return true;
}
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(PERMISSION_CAMERA) ||
shouldShowRequestPermissionRationale(PERMISSION_STORAGE)) {
Toast.makeText(CameraActivity.this,
"Camera AND storage permission are required for this demo", Toast.LENGTH_LONG).show();
}
requestPermissions(new String[] {PERMISSION_CAMERA, PERMISSION_STORAGE}, PERMISSIONS_REQUEST);
}
}
// Returns true if the device supports the required hardware level, or better.
private boolean isHardwareLevelSupported(
CameraCharacteristics characteristics, int requiredLevel) {
int deviceLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
return requiredLevel == deviceLevel;
}
// deviceLevel is not LEGACY, can use numerical sort
return requiredLevel <= deviceLevel;
}
private String chooseCamera() {
final CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
for (final String cameraId : manager.getCameraIdList()) {
final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
final StreamConfigurationMap map =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
// Fallback to camera1 API for internal cameras that don't have full support.
// This should help with legacy situations where using the camera2 API causes
// distorted or otherwise broken previews.
useCamera2API = (facing == CameraCharacteristics.LENS_FACING_EXTERNAL)
|| isHardwareLevelSupported(characteristics,
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
LOGGER.i("Camera API lv2?: %s", useCamera2API);
return cameraId;
}
} catch (CameraAccessException e) {
LOGGER.e(e, "Not allowed to access camera");
}
return null;
}
protected void setFragment() {
String cameraId = chooseCamera();
Fragment fragment;
if (useCamera2API) {
CameraConnectionFragment camera2Fragment =
CameraConnectionFragment.newInstance(
new CameraConnectionFragment.ConnectionCallback() {
#Override
public void onPreviewSizeChosen(final Size size, final int rotation) {
previewHeight = size.getHeight();
previewWidth = size.getWidth();
CameraActivity.this.onPreviewSizeChosen(size, rotation);
}
},
this,
getLayoutId(),
getDesiredPreviewFrameSize());
camera2Fragment.setCamera(cameraId);
fragment = camera2Fragment;
} else {
fragment =
new LegacyCameraConnectionFragment(this, getLayoutId(), getDesiredPreviewFrameSize());
}
getFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
protected void fillBytes(final Plane[] planes, final byte[][] yuvBytes) {
// Because of the variable row stride it's not possible to know in
// advance the actual necessary dimensions of the yuv planes.
for (int i = 0; i < planes.length; ++i) {
final ByteBuffer buffer = planes[i].getBuffer();
if (yuvBytes[i] == null) {
LOGGER.d("Initializing buffer %d at size %d", i, buffer.capacity());
yuvBytes[i] = new byte[buffer.capacity()];
}
buffer.get(yuvBytes[i]);
}
}
public boolean isDebug() {
return debug;
}
public void requestRender() {
final OverlayView overlay = (OverlayView) findViewById(R.id.debug_overlay);
if (overlay != null) {
overlay.postInvalidate();
}
}
public void addCallback(final OverlayView.DrawCallback callback) {
final OverlayView overlay = (OverlayView) findViewById(R.id.debug_overlay);
if (overlay != null) {
overlay.addCallback(callback);
}
}
public void onSetDebug(final boolean debug) {}
#Override
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
debug = !debug;
requestRender();
onSetDebug(debug);
return true;
}
return super.onKeyDown(keyCode, event);
}
protected void readyForNextImage() {
if (postInferenceCallback != null) {
postInferenceCallback.run();
}
}
protected int getScreenOrientation() {
switch (getWindowManager().getDefaultDisplay().getRotation()) {
case Surface.ROTATION_270:
return 270;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_90:
return 90;
default:
return 0;
}
}
protected abstract void processImage();
protected abstract void onPreviewSizeChosen(final Size size, final int rotation);
protected abstract int getLayoutId();
protected abstract Size getDesiredPreviewFrameSize();
}
And this is the layout file
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="500dp"
tools:context="org.tensorflow.demo.CameraActivity">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Screenshot" />
</FrameLayout>
<ImageView
android:id="#+id/imageView"
android:layout_width="140dp"
android:layout_height="160dp"
android:layout_marginStart="205dp"
android:layout_marginTop="0dp" />
I just want to take screenshot of the activity including the camera where the detection is happening. I tried some tutorials on how to take screenshot. It captures all the parts of the screen but doesnt capture the camera part. It only shows black screen. HELP!
//I have created RecycleView in Fragment as follows:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_new_shop, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
stackView = (RelativeLayout) view.findViewById(R.id.stack_view);
firstStack = (CustomImageView) view.findViewById(R.id.firstStack);
secondStack = (CustomImageView) view.findViewById(R.id.secondStack);
thirdStack = (CustomImageView) view.findViewById(R.id.thirdStack);
stackTopGap = view.findViewById(R.id.view);
new Handler().post(new Runnable() {
#Override
public void run() {
firstStack.getLayoutParams().width = stackView.getWidth() - 40;
secondStack.getLayoutParams().width = stackView.getWidth() - 80;
thirdStack.getLayoutParams().width = stackView.getWidth() - 120;
width = thirdStack.getLayoutParams().width;
recyclerView.getLayoutParams().height = recyclerView.getHeight() - (firstStack.getHeight() + stackTopGap.getHeight());
stackView.getLayoutParams().height = firstStack.getHeight();
}
});
recyclerView.setHasFixedSize(true);
linearLayoutManager=new LinearLayoutManager(getActivity()) {
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
// A good idea would be to create this instance in some initialization method, and just set the target position in this method.
LinearSmoothScroller smoothScroller = new LinearSmoothScroller(getContext()) {
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
//int yDelta = calculateCurrentDistanceToPosition(targetPosition);
return new PointF(0, 200);
}
// This is the important method. This code will return the amount of time it takes to scroll 1 pixel.
// This code will request X milliseconds for every Y DP units.
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 7 / TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 7, displayMetrics);
}
};
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
};
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(final RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final int positionView = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
if (dy > 0) {
if (positionView >= 2) {
final View view = recyclerView.getChildAt(2);
if (view != null && recyclerView.getChildAdapterPosition(view) == positionView) {
TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 200, 0);
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (counter == 0) {
if (recyclerView.getAdapter().getItemCount() - 4 >= positionView) {
createStackImageView();
}
if (stackView.getChildAt(1) != null) {
//stackView.getChildAt(1).setScaleX(1.5f);
}
counter++;
}
recyclerView.smoothScrollToPosition(positionView);
}
#Override
public void onAnimationEnd(Animation animation) {
view.clearAnimation();
stackView.requestLayout();
stackView.removeView(stackView.getChildAt(1));
stackView.invalidate();
try {
for (int i = 1; i < 4; i++) {
Glide.with(getActivity())
.load(JSONUrl.IMAGE_BASE_URL + imageList.get(positionView + i))
.into((ImageView) stackView.getChildAt(i));
}
} catch (IndexOutOfBoundsException | NullPointerException | IllegalArgumentException ex) {
ex.printStackTrace();
}
counter = 0;
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
translateAnimation.setDuration(150);
view.setAnimation(translateAnimation);
}
}
for (int i = stackView.getChildCount() - 1; i >= 2; i--) {
ResizeAnimation resizeAnimation = new ResizeAnimation(stackView.getChildAt(i));
resizeAnimation.setHeights(stackView.getChildAt(i).getHeight(), stackView.getChildAt(i - 1).getHeight());
resizeAnimation.setWidths(stackView.getChildAt(i).getWidth(), stackView.getChildAt(i - 1).getWidth());
resizeAnimation.setDuration(200);
stackView.getChildAt(i).startAnimation(resizeAnimation);
}
} else if (dy < 0) {
final int position = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
if (position == imageList.size() - 1) {
stackView.removeView(firstStack);
stackView.addView(firstStack);
stackView.invalidate();
stackView.requestLayout();
stackView.getChildAt(1).setVisibility(View.VISIBLE);
Glide.with(getActivity())
.load(JSONUrl.IMAGE_BASE_URL + imageList.get(imageList.size() - 1))
.into((ImageView) stackView.getChildAt(1));
} else if (position == imageList.size() - 2) {
stackView.removeView(secondStack);
stackView.addView(secondStack);
secondStack.getLayoutParams().height = firstStack.getHeight() - 20;
secondStack.getLayoutParams().width = firstStack.getWidth() - 40;
stackView.invalidate();
stackView.requestLayout();
stackView.getChildAt(2).setVisibility(View.VISIBLE);
Glide.with(getActivity())
.load(JSONUrl.IMAGE_BASE_URL + imageList.get(imageList.size() - 2))
.into((ImageView) stackView.getChildAt(2));
} else if (position == imageList.size() - 3) {
stackView.removeView(thirdStack);
stackView.addView(thirdStack);
thirdStack.getLayoutParams().height = secondStack.getHeight() - 20;
thirdStack.getLayoutParams().width = secondStack.getWidth() - 40;
stackView.invalidate();
stackView.requestLayout();
stackView.getChildAt(3).setVisibility(View.VISIBLE);
Glide.with(getActivity())
.load(JSONUrl.IMAGE_BASE_URL + imageList.get(imageList.size() - 3))
.into((ImageView) stackView.getChildAt(3));
} else {
stackView.removeView(firstStack);
stackView.addView(firstStack);
stackView.invalidate();
stackView.requestLayout();
}
}
}
});
return view;
}
//In validateToken method data is taken from the json and set to adapter as follows.
private void validateToken() {
final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (new ConnectionManager(getActivity()).isConnectedToInternet()) {
final SweetAlertDialog pDialog = new AlertDIalogMessage().showProgressDialog(getActivity(), "Loading...");
if (sharedPreferences.getString(SharedPrefrenceInfo.IS_TOKEN_VALID, "token_invalid").equals("token_invalid")) {
Utils.setTokenInfo(getActivity(), pDialog, new AccessTokenInfoHolder() {
#Override
public void setAcessTokenInfo(String accessToken, String expires_in, String token_type) {
Log.e("Access Token", accessToken);
new ShopFragmentJson(getActivity()).getShopPageContent(pDialog, sharedPreferences.getString(SharedPrefrenceInfo.TOKEN_TYPE, "") + " " + sharedPreferences.getString(SharedPrefrenceInfo.IS_TOKEN_VALID, ""), new ShopPageContentHolder() {
#Override
public void setErrorShopPageContent(String statusCode, String statusText) {
//do nothing here since the case unauthorized will not arrive for the first time
}
#Override
public void setSuccessShopPageContent(String success, String data) {
if (success.equals("true")) {
shoppageInfoList = getShopPageContent(data);
//set the adapter after loading data from url
final NewShopFragmentAdapter recyclerViewAdapter = new NewShopFragmentAdapter(getActivity(), recyclerView.getHeight(), shoppageInfoList);
recyclerView.setAdapter(recyclerViewAdapter);
pDialog.dismiss();
} else {
pDialog.dismiss();
new AlertDIalogMessage().showErrorDialog(getActivity(), data);
}
}
});
}
});
} else {
new ShopFragmentJson(getActivity()).getShopPageContent(pDialog, sharedPreferences.getString(SharedPrefrenceInfo.TOKEN_TYPE, "") + " " + sharedPreferences.getString(SharedPrefrenceInfo.IS_TOKEN_VALID, ""), new ShopPageContentHolder() {
#Override
public void setErrorShopPageContent(String statusCode, String statusText) {
//this method is invoked when unauthorized response come from server
Utils.setTokenInfo(getActivity(), pDialog, new AccessTokenInfoHolder() {
#Override
public void setAcessTokenInfo(String accessToken, String expires_in, String token_type) {
new ShopFragmentJson(getActivity()).getShopPageContent(pDialog, sharedPreferences.getString(SharedPrefrenceInfo.TOKEN_TYPE, "") + " " + sharedPreferences.getString(SharedPrefrenceInfo.IS_TOKEN_VALID, ""), new ShopPageContentHolder() {
#Override
public void setErrorShopPageContent(String statusCode, String statusText) {
//do nothing here since the case unauthorized will not arrive for the first time
}
#Override
public void setSuccessShopPageContent(String success, String data) {
if (success.equals("true")) {
List<ShoppageInfo> shoppageInfoList = getShopPageContent(data);
final NewShopFragmentAdapter recyclerViewAdapter = new NewShopFragmentAdapter(getActivity(), recyclerView.getHeight(), shoppageInfoList);
recyclerView.setAdapter(recyclerViewAdapter);
pDialog.dismiss();
} else {
pDialog.dismiss();
new AlertDIalogMessage().showErrorDialog(getActivity(), data);
}
}
});
}
});
}
#Override
public void setSuccessShopPageContent(String success, String data) {
if (success.equals("true")) {
List<ShoppageInfo> shoppageInfoList = getShopPageContent(data);
//set the adapter after loading data from url
final NewShopFragmentAdapter recyclerViewAdapter = new NewShopFragmentAdapter(getActivity(), recyclerView.getHeight(), shoppageInfoList);
recyclerView.setAdapter(recyclerViewAdapter);
pDialog.dismiss();
} else {
pDialog.dismiss();
new AlertDIalogMessage().showErrorDialog(getActivity(), data);
}
}
});
}
} else {
new SweetAlertDialog(getActivity(), SweetAlertDialog.ERROR_TYPE)
.setTitleText("Oops...")
.setContentText("No internet connection!")
.show();
}
}
No in onResume method i called validate token as follows:
#Override
public void onResume() {
super.onResume();
validateToken();
}
//Now when I call some activity from this fragment and come back with back pressed validate method is called and RecyclerView adapter is reloaded. Now what I want is to maintain the state of RecyclerView such that when I came back from activity RecyclerView stays in the scroll position from when activity is called. But problem for me is it always come from the start. I also see some Stack Overflow post and they suggest me to use Parceable but i don't get any benefit. Is is doing nothing.
Can try this.
You need to maintain an identifier for each row. Then save the first visible row's identifier before you go to the activity. Then when you come back you select that particular row again.