Android Open Source - com.elsewhat.android.slideshow Custom Gallery






From Project

Back to project page com.elsewhat.android.slideshow.

License

The source code is released under:

Copyright (C) 2012 Dagfinn Parnas <dagfinn.parnas@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Sof...

If you think the Android project com.elsewhat.android.slideshow listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.elsewhat.android.slideshow.api;
/* w w w. j  a v a  2  s .  co  m*/
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Random;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.view.animation.Animation.AnimationListener;
import android.widget.Adapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.ViewAnimator;

import com.elsewhat.android.slideshow.R;
import com.elsewhat.android.slideshow.activities.SlideshowActivity;


public class CustomGallery extends Gallery implements AnimationListener {


  boolean mDoCustomTransition=false;
  Animation inAnimation=null;
  Animation outAnimation=null;
  ViewAnimator viewAnimator=null;
  boolean userCreatedTouchEvent = false;
  boolean ongoingAnimation= false;
  
  


  public CustomGallery(Context context) {
    super(context);
     initAnimators();
  }

  public CustomGallery(Context context, AttributeSet attrs) {
    super(context, attrs);
     initAnimators();
  }

  public CustomGallery(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
     initAnimators();
  }
  
  protected void initAnimators() {
    inAnimation = new AlphaAnimation(0.0f, 1.0f);
    inAnimation.setDuration(2500);
    inAnimation.setAnimationListener(this);
    
    outAnimation = new AlphaAnimation(1.0f, 0.0f);
    outAnimation.setDuration(1500);
  }

  /*
   * (non-Javadoc)
   * 
   * @see android.widget.Gallery#onKeyDown(int, android.view.KeyEvent)
   */
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    Log.i("CustomGallery", "onKeydown in Customer Gallery . Key code "+keyCode);
    if(event instanceof FlingKeyEvent){
      //use the default handling if this came from a fling event
      return super.onKeyDown(keyCode,null);
    }if(!mDoCustomTransition){
      //leave the transition to the super class
      userCreatedTouchEvent=true;
      //we hardcode this here, since it is changed in onFling and we do not know when that action is finished
      setAnimationDuration(5500);
      return super.onKeyDown(keyCode, event);
    }else {
      //handle the switch without transition ourselves
      switch (keyCode) {
      case KeyEvent.KEYCODE_DPAD_LEFT:
        userCreatedTouchEvent=true;
        if (getCount() > 0 && getSelectedItemPosition() >0) {
          setSelection(getSelectedItemPosition()-1);
        }
        return true;

      case KeyEvent.KEYCODE_DPAD_RIGHT:
        userCreatedTouchEvent=true;
        //Log.i("CustomGallery", "Before anim Current: " + getSelectedItemPosition() + " visible:"+ getFirstVisiblePosition()+ " count:"+ getCount());
        if (getCount() > 0 && getSelectedItemPosition() < getCount() - 1) {
          View currentView = getSelectedView();
          if(currentView==null){
            Log.w("CustomGallery", "CurrentView is null in onKeyDown. Should not happen, but lets try to skip to the next photo.");
            nextSelection();
            return true;
          }
          
          View unboundNewView= getAdapter().getView(getSelectedItemPosition()+1, null, null);
          
          Log.d("CustomGallery","About to evaluate an animation. OngoignAnimation="+ongoingAnimation+ " inanim="+inAnimation+" outanim="+outAnimation);
          
          //check if we already have an animation as well
          if(inAnimation==null && outAnimation==null || ongoingAnimation){
            nextSelection();
            //assume it is not ongoing anymore
            //could also be the action listener which is invalid
            //ongoingAnimation=false;
          }else {
            
            viewAnimator = (ViewAnimator)currentView;
            viewAnimator.addView(unboundNewView);
            //setup animation
            
            viewAnimator.setInAnimation(inAnimation);
            viewAnimator.setOutAnimation(outAnimation);
            //trigger the animation and the event listener when finished
            ongoingAnimation=true;
            viewAnimator.showNext();
            
          }
        }
        return true;
      }

      return super.onKeyDown(keyCode, event);
    }

  }
  
  public void nextSelection(){
    //first condition should not happen
    if(getSelectedItemPosition()+1 >= getCount()){
      setSelection(0);
    }else {
      setSelection(getSelectedItemPosition()+1);
    }
    //make sure we clean up after us. Remove the temporary view
    if(viewAnimator!=null && viewAnimator.getChildCount()==2){
      //remove animations in order to make sure event listener is not triggered
      viewAnimator.setInAnimation(null);
      viewAnimator.setOutAnimation(null);
      viewAnimator.removeViewAt(1);
      ongoingAnimation=false;
    }
    //
    
    //let's make sure the visibility of the title matches what the user wants
    //this is required since the view may be cached when the visibility was changed
    View selectedView = getSelectedView();
    ImageAdapter adapter = (ImageAdapter)getAdapter();
    int visibility =adapter.shouldDisplayPhotoTitle()?View.VISIBLE:View.INVISIBLE;
    SlideshowActivity.setVisibilityOfSlideshowText(selectedView,visibility);
    
    //Notify the adapter that a new photo is being display.
    //this is used for initiating the TextSwitcher of the description
    ImageAdapter imageAdapter = (ImageAdapter)adapter;
    imageAdapter.onGalleryNewPhoto(selectedView);
    
    //this is an experimental feature for zooming in on the photo.not quite ready due to performance
    //new ZoomCurrentViewSoonTask(100).execute();

  }
  

  
  /**
   * @return the inAnimation
   */
  public Animation getInAnimation() {
    return inAnimation;
  }

  /* See http://stackoverflow.com/questions/2373617/how-to-stop-scrolling-in-a-gallery-widget
   * @see android.widget.Gallery#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)
   */
  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
      float velocityY) {
    //Log.d("CustomGallery", "onFling called");
    userCreatedTouchEvent=true;
    //the animation event listener might not trigger
    ongoingAnimation=false;
    
    float velMax = 2500f;
      float velMin = 1000f;
      float velX = Math.abs(velocityX);
      if (velX > velMax) {
        velX = velMax;
      } else if (velX < velMin) {
        velX = velMin;
      }
      velX -= 600;
      int k = 500000;
      int speed = (int) Math.floor(1f / velX * k);
      setAnimationDuration(speed);

      int kEvent;
      if (isScrollingLeft(e1, e2)) {
        // Check if scrolling left
        kEvent = KeyEvent.KEYCODE_DPAD_LEFT;
      } else {
        // Otherwise scrolling right
        kEvent = KeyEvent.KEYCODE_DPAD_RIGHT;
      }
      onKeyDown(kEvent, new FlingKeyEvent(0, 0));

      return true;
    
      //TODO:remove
    //nextSelection();
    //reducing the speed of the fling to a more suitable level
    //return super.onFling(e1, e2, velocityX/3, velocityY/3);
  }
  
  /* (non-Javadoc)
   * @see android.widget.Gallery#onSingleTapUp(android.view.MotionEvent)
   */
  @Override
  public boolean onSingleTapUp(MotionEvent motionEvent) {
    Log.d("CustomGallery", "onSingleTapUp called for selection " + getSelectedItemPosition());
    
    Object currentObject = getAdapter().getItem(getSelectedItemPosition());
    if(currentObject!=null && currentObject instanceof SlideshowPhoto){
      SlideshowPhoto currentSlideshowPhoto = (SlideshowPhoto)currentObject;
      if(currentSlideshowPhoto.isPromotion()){
        
        Analytics.trackEvent(getContext(), "actions", "promotion", "clicked");
        Log.d("CustomGallery", "Promotion clicked, sending the user to the market for the app com.stuckincustoms.slideshow.premium" );
        try {
          getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.stuckincustoms.slideshow.premium")));
        }catch (ActivityNotFoundException e) {
          getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://market.android.com/details?id=com.stuckincustoms.slideshow.premium")));
        }
        return true;
      }else {
        Adapter adapter = getAdapter();
        if(adapter instanceof ImageAdapter){
          ImageAdapter imageAdapter = (ImageAdapter)adapter;
          imageAdapter.triggerActionToggleTitle();
          return true;
        }
      }
      
    }
    return super.onSingleTapUp(motionEvent);
  }
  
  private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2){
      return e2.getX() > e1.getX();
    }
  
  /**
   * Set when a touch event is called on this gallery
   * @return the userCreatedTouchEvent
   */
  public boolean hasUserCreatedTouchEvent() {
    return userCreatedTouchEvent;
  }

  /**
   * @param userCreatedTouchEvent the userCreatedTouchEvent to set
   */
  public void setUserCreatedTouchEvent(boolean userCreatedTouchEvent) {
    this.userCreatedTouchEvent = userCreatedTouchEvent;
  }

  /**
   * @param inAnimation the inAnimation to set
   */
  public void setInAnimation(Animation inAnimation) {
    this.inAnimation = inAnimation;
    if(inAnimation!=null){
      inAnimation.setAnimationListener(this);
    }
  }

  /**
   * @return the outAnimation
   */
  public Animation getOutAnimation() {
    return outAnimation;
  }

  /**
   * @param outAnimation the outAnimation to set
   */
  public void setOutAnimation(Animation outAnimation) {
    this.outAnimation = outAnimation;
  }
  
  public void setDoCustomTransition(boolean doCustomTransition){
    mDoCustomTransition= doCustomTransition;
  }

  
  public boolean getDoCustomTransition(){
    return mDoCustomTransition;
  }

  @Override
  public void onAnimationEnd(Animation arg0) {
    ongoingAnimation=false;
    nextSelection();
    
    


    
  }

  @Override
  public void onAnimationRepeat(Animation animation) {
    //ignore
  }

  @Override
  public void onAnimationStart(Animation animation) {
    //ignore
  }
  
  /* (non-Javadoc)
   * @see android.widget.Gallery#onLayout(boolean, int, int, int, int)
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    try {
      super.onLayout(changed, l, t, r, b);
    }catch (ClassCastException e) {
      Log.e("CustomGallery", "Got a ClassCastException in onLayout most likely caused by a racecondition in the mRecycle bin ", e);
      
      
      Class classGallery = this.getClass().getSuperclass().getSuperclass();
      Method methodRecycle;
      try {
        methodRecycle = classGallery.getDeclaredMethod("recycleAllViews");
        methodRecycle.setAccessible(true);
        methodRecycle.invoke(this);
        Log.i("CustomGallery", "Succeeded in calling recycleAllViews");
        return;
      } catch (SecurityException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
      } catch (NoSuchMethodException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
      } catch (IllegalArgumentException e3) {
        // TODO Auto-generated catch block
        e3.printStackTrace();
      } catch (IllegalAccessException e4) {
        // TODO Auto-generated catch block
        e4.printStackTrace();
      } catch (InvocationTargetException e5) {
        // TODO Auto-generated catch block
        e5.printStackTrace();
      }
      Log.i("CustomGallery", "Failed in calling recycleAllViews");
      
      /*
      //let us call onLayout slightly in the future
      final boolean oldChanged=changed;
      final int oldL=l;
      final int oldT=t;
      final int oldR=r;
      final int oldB=b;
      final Runnable callOnLayout = new Runnable() {
               public void run() {
                 onLayout(oldChanged,oldL,oldT,oldR,oldB);
               }
        };
        
        final Handler handler = new Handler();
        handler.postAtTime(callOnLayout, 300L);
          */ 
    }
    
  }  
  
    /**
     * Asynch task for displaying a new photo at a regular interval
     * 
     */
    public class ZoomCurrentViewSoonTask extends AsyncTask<Void, Void, Void> {
      long sleepMS;
    
    public ZoomCurrentViewSoonTask(long ms){
      sleepMS=ms;
    }
    
    protected void onPostExecute(Void result) {
      View currentView = getSelectedView();
      if(currentView!=null){
        //transfering the image from the already loaded view, to the unbound one
        ImageView photo = (ImageView)currentView.findViewById(R.id.slideshow_photo);
        
        Random random = new Random (System.nanoTime());
        float pivotXFactor = random.nextFloat();
        float pivotYFactor = random.nextFloat();
        float scaleFactor;
        scaleFactor =  1.0f+ random.nextFloat()/4;
        
        
        Animation zoomAnimation = new ScaleAnimation(1.0f,scaleFactor,1.0f,scaleFactor,Animation.RELATIVE_TO_SELF,pivotXFactor,Animation.RELATIVE_TO_SELF,pivotYFactor);
        zoomAnimation.setDuration(10000);
        zoomAnimation.setFillAfter(false);
        zoomAnimation.setFillBefore(false);
        photo.startAnimation(zoomAnimation);
      }
    }

    @Override
    protected Void doInBackground(Void... arg0) {  
      try
          {
              Thread.sleep(sleepMS);
          }
          catch (InterruptedException ie)
          {
            Log.d("CustomGallery", "SlideshowTimerTask received  InterruptedException", ie);
          }
      // TODO Auto-generated method stub
      return null;
    }

    }

}




Java Source Code List

com.elsewhat.android.slideshow.activities.ChromecastAddin.java
com.elsewhat.android.slideshow.activities.ISlideshowInstance.java
com.elsewhat.android.slideshow.activities.SlideshowActivity.java
com.elsewhat.android.slideshow.activities.SlideshowDreamService.java
com.elsewhat.android.slideshow.activities.SlideshowPreferences.java
com.elsewhat.android.slideshow.api.Analytics.java
com.elsewhat.android.slideshow.api.AndroidUtils.java
com.elsewhat.android.slideshow.api.AsyncQueueableObject.java
com.elsewhat.android.slideshow.api.AsyncReadQueue.java
com.elsewhat.android.slideshow.api.CustomGallery.java
com.elsewhat.android.slideshow.api.DeletablePreference.java
com.elsewhat.android.slideshow.api.DownloadableObject.java
com.elsewhat.android.slideshow.api.FileDownloader.java
com.elsewhat.android.slideshow.api.FileUtils.java
com.elsewhat.android.slideshow.api.FlingKeyEvent.java
com.elsewhat.android.slideshow.api.ImageAdapter.java
com.elsewhat.android.slideshow.api.QueueablePhotoObject.java
com.elsewhat.android.slideshow.api.ReadOnlyPreference.java
com.elsewhat.android.slideshow.api.SlideshowBackend.java
com.elsewhat.android.slideshow.api.SlideshowPhotoCached.java
com.elsewhat.android.slideshow.api.SlideshowPhotoDrawable.java
com.elsewhat.android.slideshow.api.SlideshowPhoto.java
com.elsewhat.android.slideshow.backend.FlickrPublicSetBackend.java
com.elsewhat.android.slideshow.backend.OPMLBackend.java
com.elsewhat.android.slideshow.backend.SmugMugRecentBackend.java