package com.aviary.android.feather.widget;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.util.concurrent.Future;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import com.aviary.android.feather.Constants;
import com.aviary.android.feather.FeatherActivity;
import com.aviary.android.feather.FilterManager;
import com.aviary.android.feather.R;
import com.aviary.android.feather.library.content.FeatherIntent;
import com.aviary.android.feather.library.plugins.PluginManager.ExternalPlugin;
import com.aviary.android.feather.library.services.EffectContext;
import com.aviary.android.feather.library.services.FutureListener;
import com.aviary.android.feather.library.services.ImageCacheService;
import com.aviary.android.feather.library.services.ImageCacheService.SimpleCachedRemoteBitmap;
import com.aviary.android.feather.library.services.PluginService;
import com.aviary.android.feather.library.services.ThreadPoolService;
import com.aviary.android.feather.library.services.ThreadPoolService.BackgroundCallable;
import com.aviary.android.feather.library.tracking.Tracker;
import com.aviary.android.feather.widget.wp.CellLayout;
import com.aviary.android.feather.widget.wp.CellLayout.CellInfo;
import com.aviary.android.feather.widget.wp.Workspace;
import com.aviary.android.feather.widget.wp.Workspace.OnPageChangeListener;
import com.aviary.android.feather.widget.wp.WorkspaceIndicator;
public class IapDialog extends LinearLayout implements OnPageChangeListener, OnClickListener {
public interface OnCloseListener {
void onClose();
}
private int mMainLayoutResId = R.layout.feather_iap_workspace_screen_stickers;
private int mCellResId = R.layout.feather_iap_cell_item_stickers;
private View mBackground;
private TextViewCustomFont mTitle, mSubTitle, mDescription;
private Button mButton;
private Workspace mWorkspace;
private WorkspaceIndicator mWorkspaceIndicator;
private ImageView mIcon;
private ExternalPlugin mPlugin;
private int mPluginType;
private ThreadPoolService mThreadService;
private ImageCacheService mCacheService;
private FilterManager mController;
private boolean mDownloadOnDemand = true;
private OnCloseListener mCloseListener;
int mRows;
int mCols;
int mItemsPerPage;
public IapDialog( Context context, AttributeSet attrs ) {
super( context, attrs );
}
@Override
protected void onAttachedToWindow() {
Log.i( VIEW_LOG_TAG, "onAttachedFromWindow" );
super.onAttachedToWindow();
computeLayoutItems( getResources() );
mDownloadOnDemand = Constants.getApplicationMaxMemory() < 48;
mIcon = (ImageView) findViewById( R.id.icon );
mBackground = findViewById( R.id.main_iap_dialog );
mButton = (Button) findViewById( R.id.button );
mTitle = (TextViewCustomFont) findViewById( R.id.title );
mSubTitle = (TextViewCustomFont) findViewById( R.id.subtitle );
mDescription = (TextViewCustomFont) findViewById( R.id.description );
mWorkspace = (Workspace) findViewById( R.id.workspace );
mWorkspaceIndicator = (WorkspaceIndicator) findViewById( R.id.workspace_indicator );
mBackground.setOnClickListener( this );
}
private void computeLayoutItems( Resources res ) {
if ( mPluginType == FeatherIntent.PluginType.TYPE_FILTER || mPluginType == FeatherIntent.PluginType.TYPE_BORDER ) {
mMainLayoutResId = R.layout.feather_iap_workspace_screen_effects;
mCellResId = R.layout.feather_iap_cell_item_effects;
mCols = res.getInteger( R.integer.feather_iap_dialog_cols_effects );
mRows = res.getInteger( R.integer.feather_iap_dialog_rows_effects );
} else {
mMainLayoutResId = R.layout.feather_iap_workspace_screen_stickers;
mCellResId = R.layout.feather_iap_cell_item_stickers;
mCols = res.getInteger( R.integer.feather_iap_dialog_cols );
mRows = res.getInteger( R.integer.feather_iap_dialog_rows );
}
mItemsPerPage = mRows * mCols;
}
@Override
protected void onDetachedFromWindow() {
Log.i( VIEW_LOG_TAG, "onDetachedFromWindow" );
super.onDetachedFromWindow();
mButton.setOnClickListener( null );
mWorkspace.setAdapter( null );
mWorkspace.setOnPageChangeListener( null );
mBackground.setOnClickListener( null );
mCloseListener = null;
mController = null;
mThreadService = null;
mCacheService = null;
mPlugin = null;
}
@Override
public void onClick( View v ) {
if ( v.equals( mBackground ) ) {
if ( mCloseListener != null ) {
mCloseListener.onClose();
}
}
}
private void initWorkspace( ExternalPlugin plugin ) {
if ( null != plugin && null != plugin.getItems() ) {
String[] items = plugin.getItems();
String folder = getRemoteFolder( plugin );
mWorkspace.setAdapter( new WorkspaceAdapter( getContext(), folder, mMainLayoutResId, -1, items ) );
mWorkspace.setOnPageChangeListener( this );
if ( plugin.getItems().length <= mItemsPerPage ) {
mWorkspaceIndicator.setVisibility( View.INVISIBLE );
} else {
mWorkspaceIndicator.setVisibility( View.VISIBLE );
}
} else {
mWorkspace.setAdapter( null );
mWorkspace.setOnPageChangeListener( null );
}
}
private String getRemoteFolder( ExternalPlugin plugin ) {
if ( null != plugin && null != plugin.getPackageName() ) {
String[] pkg = plugin.getPackageName().split( "\\." );
String folder = null;
if ( pkg.length >= 2 ) {
folder = PluginService.CONTENT_DEFAULT_URL + "/" + pkg[pkg.length - 2] + "/" + pkg[pkg.length - 1];
return folder;
}
}
return "";
}
public void setOnCloseListener( OnCloseListener listener ) {
mCloseListener = listener;
}
public ExternalPlugin getPlugin() {
return mPlugin;
}
public int getPluginType() {
return mPluginType;
}
public void setPlugin( ExternalPlugin value, int type, Context context ) {
mPlugin = value;
mPluginType = type;
computeLayoutItems( getResources() );
Log.d( VIEW_LOG_TAG, "cols: " + mCols + ", rows: " + mRows );
if ( null != context && null == mController ) {
if ( context instanceof FeatherActivity ) {
mController = ( (FeatherActivity) context ).getController();
if ( null != mController ) {
mThreadService = mController.getService( ThreadPoolService.class );
mCacheService = mController.getService( ImageCacheService.class );
}
}
}
mTitle.setText( value.getLabel( mPluginType ) );
mSubTitle.setText( "(" + value.getNumItems( mPluginType ) + ")" );
mDescription.setText( value.getDescription() != null ? value.getDescription() : "" );
if ( null != mPlugin.getPackageName() ) {
mWorkspace.setIndicator( mWorkspaceIndicator );
initWorkspace( mPlugin );
downloadPackIcon( mPlugin );
mButton.setOnClickListener( new OnClickListener() {
@Override
public void onClick( View v ) {
if ( null != mController ) {
Tracker.recordTag( "Unpurchased(" + mPlugin.getLabel( mPluginType ) + ") : StoreButtonClicked" );
mController.downloadPlugin( mPlugin.getPackageName(), mPluginType );
postDelayed( new Runnable() {
@Override
public void run() {
if ( mCloseListener != null ) {
mCloseListener.onClose();
}
}
}, 500 );
}
}
} );
}
}
/**
* Fetch the current pack icon
*
* @param plugin
*/
private void downloadPackIcon( ExternalPlugin plugin ) {
if ( null != plugin ) {
if ( null != mThreadService && null != mIcon ) {
final String url = PluginService.CONTENT_DEFAULT_URL + "/" + plugin.getIconUrl();
BackgroundImageLoader callable = new BackgroundImageLoader( mCacheService, false );
BackgroundImageLoaderListener listener = new BackgroundImageLoaderListener( mIcon, url );
mThreadService.submit( callable, listener, url );
}
}
}
class WorkspaceAdapter extends ArrayAdapter<String> {
LayoutInflater mLayoutInflater;
int mResId;
String mUrlPrefix;
public WorkspaceAdapter( Context context, String urlPrefix, int resource, int textResourceId, String[] objects ) {
super( context, resource, textResourceId, objects );
mUrlPrefix = urlPrefix;
mResId = resource;
mLayoutInflater = LayoutInflater.from( getContext() );
}
public String getUrlPrefix() {
return mUrlPrefix;
}
@Override
public int getCount() {
return (int) Math.ceil( (double) super.getCount() / mItemsPerPage );
}
/**
* Gets the real num of items.
*
* @return the real count
*/
public int getRealCount() {
return super.getCount();
}
@Override
public View getView( int position, View convertView, ViewGroup parent ) {
Log.i( VIEW_LOG_TAG, "getView: " + position + ", convertView: " + convertView );
if ( convertView == null ) {
convertView = mLayoutInflater.inflate( mResId, mWorkspace, false );
}
CellLayout cell = (CellLayout) convertView;
cell.setNumCols( mCols );
cell.setNumRows( mRows );
for ( int i = 0; i < mItemsPerPage; i++ ) {
View toolView;
CellInfo cellInfo = cell.findVacantCell();
if ( cellInfo == null ) {
toolView = cell.getChildAt( i );
} else {
toolView = mLayoutInflater.inflate( mCellResId, parent, false );
CellLayout.LayoutParams lp = new CellLayout.LayoutParams( cellInfo.cellX, cellInfo.cellY, cellInfo.spanH, cellInfo.spanV );
cell.addView( toolView, -1, lp );
}
final int index = ( position * mItemsPerPage ) + i;
final ImageView imageView = (ImageView) toolView.findViewById( R.id.image );
final View progress = toolView.findViewById( R.id.progress );
if ( index < getRealCount() ) {
final String url = getUrlPrefix() + "/" + getItem( index ) + ".png";
final String tag = (String) imageView.getTag();
if ( mDownloadOnDemand ) {
// if on demand we can clean up the bitmap
if ( tag == null || !url.equals( tag ) ) {
imageView.setImageBitmap( null );
imageView.setTag( null );
}
} else {
// download the image immediately
if ( null != mThreadService ) {
if ( null != progress ) {
progress.setVisibility( View.VISIBLE );
}
imageView.setImageBitmap( null );
imageView.setTag( null );
BackgroundImageLoader callable = new BackgroundImageLoader( mCacheService, true );
BackgroundImageLoaderListener listener = new BackgroundImageLoaderListener( imageView, url );
mThreadService.submit( callable, listener, url );
}
}
} else {
if ( null != progress ) {
progress.setVisibility( View.GONE );
}
imageView.setImageBitmap( null );
imageView.setTag( null );
}
}
convertView.requestLayout();
return convertView;
}
}
@Override
public void onPageChanged( int which, int old ) {
if ( !mDownloadOnDemand ) return;
Log.i( VIEW_LOG_TAG, "onPageChanged: " + which + " from " + old );
if ( null != mWorkspace && null != getContext() ) {
WorkspaceAdapter adapter = (WorkspaceAdapter) mWorkspace.getAdapter();
int index = which * mItemsPerPage;
int endIndex = index + mItemsPerPage;
int total = adapter.getRealCount();
for ( int i = index; i < endIndex; i++ ) {
CellLayout cellLayout = (CellLayout) mWorkspace.getScreenAt( which );
View toolView = cellLayout.getChildAt( i - index );
if ( i < total ) {
final String url = adapter.getUrlPrefix() + "/" + adapter.getItem( i ) + ".png";
final ImageView imageView = (ImageView) toolView.findViewById( R.id.image );
final String tag = (String) imageView.getTag();
if ( tag == null || !url.equals( tag ) ) {
if ( null != mThreadService ) {
Log.d( VIEW_LOG_TAG, "fetching image: " + url );
BackgroundImageLoader callable = new BackgroundImageLoader( mCacheService, true );
BackgroundImageLoaderListener listener = new BackgroundImageLoaderListener( imageView, url );
mThreadService.submit( callable, listener, url );
}
} else {
Log.w( VIEW_LOG_TAG, "image already loaded?" );
}
}
}
}
}
/**
* Hide the current view and remove from its parent once the hide animation is completed
*/
public void hide() {
if ( null != mPlugin ) {
Tracker.recordTag( "Unpurchased(" + mPlugin.getLabel( mPluginType ) + ") : Cancelled" );
}
if ( null != getHandler() ) {
getHandler().post( mHide );
}
}
private Runnable mHide = new Runnable() {
@Override
public void run() {
handleHide();
}
};
private void handleHide() {
Animation animation = AnimationUtils.loadAnimation( getContext(), R.anim.feather_iap_close_animation );
AnimationListener listener = new AnimationListener() {
@Override
public void onAnimationStart( Animation animation ) {}
@Override
public void onAnimationRepeat( Animation animation ) {}
@Override
public void onAnimationEnd( Animation animation ) {
ViewGroup parent = (ViewGroup) getParent();
if ( null != parent ) {
parent.removeView( IapDialog.this );
}
}
};
animation.setAnimationListener( listener );
startAnimation( animation );
}
class BackgroundImageLoaderListener implements FutureListener<Bitmap> {
WeakReference<ImageView> mImageView;
String mUrl;
public BackgroundImageLoaderListener( final ImageView view, final String url ) {
mImageView = new WeakReference<ImageView>( view );
mUrl = url;
}
@Override
public void onFutureDone( Future<Bitmap> future ) {
final ImageView image = mImageView.get();
if ( null != image ) {
try {
final Bitmap bitmap = future.get();
if ( null != getHandler() ) {
getHandler().post( new Runnable() {
@SuppressWarnings("deprecation")
@Override
public void run() {
if ( null == bitmap ) {
image.setScaleType( ScaleType.CENTER );
image.setImageResource( R.drawable.feather_iap_dialog_image_na );
} else {
image.setScaleType( ScaleType.FIT_CENTER );
image.setImageDrawable( new BitmapDrawable( bitmap ) );
}
View parent = (View) image.getParent();
if ( null != parent ) {
View progress = parent.findViewById( R.id.progress );
if ( null != progress ) {
progress.setVisibility( View.INVISIBLE );
}
}
Animation anim = AnimationUtils.loadAnimation( getContext(), android.R.anim.fade_in );
image.startAnimation( anim );
image.setTag( mUrl );
}
} );
}
} catch ( Throwable e ) {
e.printStackTrace();
}
} else {
Log.w( VIEW_LOG_TAG, "imageView is null" );
}
}
}
/**
* Background loader for the remote images
*
* @author alessandro
*
*/
static class BackgroundImageLoader extends BackgroundCallable<String, Bitmap> {
WeakReference<ImageCacheService> mImageCache;
boolean mSaveToCache;
public BackgroundImageLoader( ImageCacheService service, boolean saveToCache ) {
mImageCache = new WeakReference<ImageCacheService>( service );
mSaveToCache = saveToCache;
}
@Override
public Bitmap call( EffectContext context, String url ) {
if ( null != url ) {
Options options = new Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inInputShareable = true;
options.inPurgeable = true;
ImageCacheService service = mImageCache.get();
if ( null != service ) {
SimpleCachedRemoteBitmap remoteRequest;
try {
remoteRequest = service.requestRemoteBitmap( url );
} catch ( MalformedURLException e ) {
e.printStackTrace();
return null;
}
try {
return remoteRequest.getBitmap( options );
} catch ( IOException e ) {
e.printStackTrace();
return null;
}
}
}
return null;
}
}
}