Sunday 26 March 2017

app4 Interfaces/utility/febmenu

pacakges: interfaces/utility/febmenu
******com.app.interfaces******
1)BackPressedEventListener.java
===============================
package com.eppico.interfaces;

public interface BackPressedEventListener {
   public void onBackPressed();}
2)ClickEventListener.java
==========================
package com.eppico.interfaces;
/** * Created by ip4 on 15-06-2016. */import android.view.View;
public interface ClickEventListener {
    public void clickEvent(View v);}
3)LocationUpdateListener.java
==============================
package com.eppico.interfaces;
import android.location.Location;
public interface LocationUpdateListener {
    /**Called when got location of user*/    void onLocationUpdate(Location location);    /**Called when user deny to request of enable Location permission*/    void onLocationPermissionDeny();    /**Called when user deny to request to enable GPS*/    void onGPSRequestDeny();}
4)RecyclerViewItemClickListener.java
=====================================
package com.eppico.interfaces;
import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;
public class RecyclerViewItemClickListener implements RecyclerView.OnItemTouchListener {
        private OnItemClickListener mListener;
        public interface OnItemClickListener {
            public void onItemClick(View view, int position);        }

        GestureDetector mGestureDetector;
        public RecyclerViewItemClickListener(Context context, OnItemClickListener listener) {
            mListener = listener;            mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onSingleTapUp(MotionEvent e) {
                    return true;                }
            });        }

        @Override
        public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
            View childView = view.findChildViewUnder(e.getX(), e.getY());            if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
                mListener.onItemClick(childView, view.getChildAdapterPosition(childView));            }
            return false;        }

        @Override
        public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
        }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}
*********************com.app.utility*********************
1)Constants.java
======================
package com.eppico.utility;
import android.graphics.Bitmap;import android.net.Uri;
/** * Created by manisha on 12/12/16. */
public class Constants {
    /*public static Uri IMAGE_URI;    public static Bitmap CROPPED_BITMAP;*/    public static boolean BTN_OK_CLICKED = false;    public final static int MY_PERMISSIONS_REQUEST_URI = 111;    public final static int REQUEST_PERMISSION_SETTING = 112;
    public static final int TYPE_HEADER = 0;    public static final int TYPE_ITEM = 1;    public static final int TYPE_FOOTER = 2;
    public static final int FIRST_PAGE_NO=0;
    public static final int REQ_CODE_CAPTURE_IMAGE=50,REQ_CODE_GALLERY_IMAGE=51,REQ_CODE_RECORD_VIDEO=52,REQ_CODE_CROP_IMAGE=53;
    public enum SPOT_TYPE{PUBLIC,PRIVATE};    public enum POST_MEDIA_TYPE{IMAGE,VIDEO};    public enum SPOT_LIST_TYPE{INVITED_SPOT,MY_SPOT};    public enum FROM_SCREEN{CREATE_SPOT_MAP,SPOT_DETAIL,PROFILE,MENU};    public enum FOLLOW_STATUS{UNFOLLOW,FOLLOW};    public enum FOLLOW_LIST{FOLLOWERS,FOLLOWING};    public enum INVITATION_STATUS{NOT_INVITED,INVITED};    public enum SPOT_ACTIVE_STATUS{INACTIVE,ACITVE}
    public enum POPUP_TYPE{CATEGORY,RADIUS}
    public enum TAB_SEARCH{SPOT,USER}
    public enum CMS_PAGE{PRIVACY_POLICY,TERMS_CONDITION}

    public enum LEADER_SHIP_TYPE{LEADERSHIP,CHMAPIONSHIP};}
2)CustomDialog.java
======================
package com.eppico.utility;
import android.app.AlertDialog;import android.app.ProgressDialog;import android.content.Context;import android.content.DialogInterface;import android.support.annotation.NonNull;
import com.eppico.R;
public class CustomDialog {
    private static CustomDialog customDialog;    ProgressDialog progressDialog;
    public static CustomDialog getInstance() {
        if (customDialog == null) {
            customDialog = new CustomDialog();        }
        return customDialog;    }

    /**     * Show progress dialog without message, Before show new dialog it is hide previous showing dialog     * @param context Context of activity.     * @param cancelable true: Hide out side touch or back press, false: Can not hide out side touch     * */    public void show(@NonNull Context context, boolean cancelable) {
        try {
            //Before show new dialog hide previous showing dialog            hide();
            progressDialog = new ProgressDialog(context);            progressDialog.setCancelable(cancelable);            progressDialog.setMessage(context.getString(R.string.msgLoading));            progressDialog.show();            /*if (progressDialog != null) {                if (!progressDialog.isShowing()) {                    progressDialog.show();                }            }*/        } catch (Exception e) {
            e.printStackTrace();        }

    }

    /**     * Show progress dialog without message, Before show new dialog it is hide previous showing dialog     * @param context Context of activity.     * @param message Message of dialog.     * @param cancelable true: Hide out side touch or back press, false: Can not hide out side touch     * */    public void show(@NonNull Context context,@NonNull String message,boolean cancelable) {

        try {

            //Before show new dialog hide previous showing dialog            hide();            //Set default dialog message "Loading"            message=(message!=null && message.trim().length()>0)?message:context.getString(R.string.msgLoading);            progressDialog = new ProgressDialog(context);            progressDialog.setMessage(message);            progressDialog.setCancelable(cancelable);
            progressDialog.show();

            /*if (progressDialog != null) {                if (!progressDialog.isShowing()) {                    progressDialog.show();                }            }*/        } catch (Exception e) {
            e.printStackTrace();        }

    }

    public void hide() {
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();        }
    }

    public boolean isDialogShowing() {
        if (progressDialog != null)
            return progressDialog.isShowing();        else            return false;    }

    //Show alert dialog    public void showMessageDialog(Context context, String title, String message) {
       /* if(title == null && title.equalsIgnoreCase("")){            title = "Eppico";        }*/                if (message != null && message.trim().length() > 0) {
            AlertDialog.Builder builder = new AlertDialog.Builder(context);            //builder.setTitle(title);            builder.setCancelable(true);            builder.setMessage(message);            builder.setPositiveButton(context.getString(R.string.btnOk),                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.dismiss();                        }
                    });            // create alert dialog            AlertDialog alertDialog = builder.create();            // show it            alertDialog.show();        }
    }

    //Show alert dialog    public void showMessageDialog(Context context,String message) {
        if (message != null && message.trim().length() > 0) {
            AlertDialog.Builder builder = new AlertDialog.Builder(context);            //builder.setTitle(title);            builder.setCancelable(true);            builder.setMessage(message);            builder.setPositiveButton(context.getString(R.string.btnOk),                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.dismiss();                        }
                    });            // create alert dialog            AlertDialog alertDialog = builder.create();            // show it            alertDialog.show();        }
    }

}
3)FileUtils.java
==================
package com.eppico.utility;
import android.content.Context;import android.graphics.Bitmap;import android.net.Uri;import android.os.Environment;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.util.Log;
import com.eppico.R;
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;
/** * Created by rushil on 14/12/16. */
public class FileUtils {

    private String TAG=FileUtils.class.getName();    private static FileUtils fileUtils;    public enum MEDIA_TYPE{PICTURE,VIDEO}
    public static FileUtils getInstance()
    {
        if(fileUtils==null)
            fileUtils=new FileUtils();        return fileUtils;    }


    /**     * Save bitmap to Application name folder and return Path     * @param context Context of activity or application     * @param bitmap Bitmap image     * @param subDir Sub directory name which will create under App name folder     */    public String saveBitmap(@NonNull Context context,@NonNull Bitmap bitmap,@Nullable String subDir) {
        try {

            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), context.getString(R.string.app_name));
            File myDir;            if (subDir != null && subDir.length() > 0)
                myDir = new File(mediaStorageDir + File.separator + subDir);            else                myDir = new File(mediaStorageDir + "");
            if (!myDir.exists())
                myDir.mkdirs();

            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());            String imgName = "IMG-" + timeStamp + ".jpg";
            File file = new File(myDir, imgName);            if (file.exists())
                file.delete();

            if (bitmap != null) {
                FileOutputStream out = new FileOutputStream(file);                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);                out.flush();                out.close();            }

            return file.getPath();
        } catch (Exception e) {
            e.printStackTrace();        }
        return "";    }

    public String saveBitmapWithPath(@NonNull Bitmap bitmap,String filePathWithName) {
        try {

            File file = new File(filePathWithName);            if (file.exists())
                file.delete();
            if (bitmap != null) {
                FileOutputStream out = new FileOutputStream(file);                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);                out.flush();                out.close();            }

            return file.getPath();
        } catch (Exception e) {
            e.printStackTrace();        }
        return "";    }

    /**Return File URI according media type*/    public Uri getFileUri(Context context,MEDIA_TYPE mediaType)
    {
        try {

            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), context.getString(R.string.app_name));            //Create Media Directory            File  mediaDir=new File(mediaStorageDir + File.separator + context.getString(R.string.dirMedia));            if(!mediaDir.exists())
                mediaDir.mkdirs();
            String subDirName="",fileExtension="";            switch (mediaType)
            {
                case PICTURE:
                    subDirName=context.getString(R.string.dirImages);                    fileExtension=".jpg";                    break;                case VIDEO:
                    subDirName=context.getString(R.string.dirVideos);                    fileExtension=".mp4";                    break;            }
            File subDir = new File(mediaDir + File.separator + subDirName);            if(!subDir.exists())
                subDir.mkdirs();
            String mediaFileName = System.currentTimeMillis() + fileExtension;
            File mediaFile = new File(subDir, mediaFileName);
            return Uri.fromFile(mediaFile);
        }catch (Exception e)
        {
            e.printStackTrace();        }
        return null;    }

    /**Return File path according media type*/    public String getFilePath(Context context,MEDIA_TYPE mediaType)
    {
        try {

            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), context.getString(R.string.app_name));            //Create Media Directory            File  mediaDir=new File(mediaStorageDir + File.separator + context.getString(R.string.dirMedia));            if(!mediaDir.exists())
                mediaDir.mkdirs();
            String subDirName="",fileExtension="";            switch (mediaType)
            {
                case PICTURE:
                    subDirName=context.getString(R.string.dirImages);                    fileExtension=".jpg";                    break;                case VIDEO:
                    subDirName=context.getString(R.string.dirVideos);                    fileExtension=".mp4";                    break;            }
            File subDir = new File(mediaDir + File.separator + subDirName);            if(!subDir.exists())
                subDir.mkdirs();
            String mediaFileName = System.currentTimeMillis() + fileExtension;
            File mediaFile = new File(subDir, mediaFileName);
            return mediaFile.getAbsolutePath();
        }catch (Exception e)
        {
            e.printStackTrace();        }
        return null;    }

    /**Return File directory path*/    public String getFileDirPath(Context context,MEDIA_TYPE mediaType)
    {
        try {

            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), context.getString(R.string.app_name));            //Create Media Directory            File  mediaDir=new File(mediaStorageDir + File.separator + context.getString(R.string.dirMedia));            if(!mediaDir.exists())
                mediaDir.mkdirs();
            String subDirName="";            switch (mediaType)
            {
                case PICTURE:
                    subDirName=context.getString(R.string.dirImages);                    break;                case VIDEO:
                    subDirName=context.getString(R.string.dirVideos);                    break;            }
            File subDir = new File(mediaDir + File.separator + subDirName);            if(!subDir.exists())
                subDir.mkdirs();
            return subDir.getAbsolutePath();
        }catch (Exception e)
        {
            e.printStackTrace();        }
        return null;    }

    /**Copy file from source to target location with target file name and extension     * @param sourcePath Source file path     * @param targetPath Target File path with file name e.g path/filName.jpg     * */    public String copyFile(String sourcePath,String targetPath) {
        InputStream in = null;        OutputStream out = null;        try {

            //create output directory if it doesn't exist            /*File dir = new File (targetPath);            if (!dir.exists())            {                dir.mkdirs();            }*/            //File sourceFile=new File(inputPath);            File outputFile=new File(targetPath);//            File outputFile=new File(outputPath + File.separator + sourceFile.getName());
            in = new FileInputStream(sourcePath);            out = new FileOutputStream(outputFile.getAbsoluteFile());
            byte[] buffer = new byte[1024];            int read;            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);            }
            in.close();            //in = null;
            // write the output file (You have now copied the file)            out.flush();            out.close();            //out = null;
            return outputFile.getAbsolutePath();
        }  catch (FileNotFoundException fnfe1) {
            Log.e(TAG, fnfe1.getMessage());        }
        catch (Exception e) {
            Log.e(TAG, e.getMessage());        }
        return "";    }

    public  void copyDirectory(File sourceLocation, File targetLocation)
            throws IOException {

        if (sourceLocation.isDirectory()) {
            if (!targetLocation.exists()) {
                targetLocation.mkdir();            }

            String[] children = sourceLocation.list();            for (int i = 0; i < sourceLocation.listFiles().length; i++) {

                copyDirectory(new File(sourceLocation, children[i]),                        new File(targetLocation, children[i]));            }
        } else {

            InputStream in = new FileInputStream(sourceLocation);
            OutputStream out = new FileOutputStream(targetLocation);
            // Copy the bits from instream to outstream            byte[] buf = new byte[1024];            int len;            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);            }
            in.close();            out.close();        }

    }


}
4)ItemClickSupport.java
========================
package com.eppico.utility;
import android.support.v7.widget.RecyclerView;import android.view.View;
import com.eppico.R;
/** * Created by Admin on 13/12/2016. */
public class ItemClickSupport {
    private final RecyclerView mRecyclerView;    private OnItemClickListener mOnItemClickListener;    private OnItemLongClickListener mOnItemLongClickListener;    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);                mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);            }
        }
    };    private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            if (mOnItemLongClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);                return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);            }
            return false;        }
    };    private RecyclerView.OnChildAttachStateChangeListener mAttachListener
            = new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(View view) {
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);            }
        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {

        }
    };
    private ItemClickSupport(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;        mRecyclerView.setTag(R.id.item_click_support, this);        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);    }

    public static ItemClickSupport addTo(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);        if (support == null) {
            support = new ItemClickSupport(view);        }
        return support;    }

    public static ItemClickSupport removeFrom(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);        if (support != null) {
            support.detach(view);        }
        return support;    }

    public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;        return this;    }

    public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
        mOnItemLongClickListener = listener;        return this;    }

    private void detach(RecyclerView view) {
        view.removeOnChildAttachStateChangeListener(mAttachListener);        view.setTag(R.id.item_click_support, null);    }

    public interface OnItemClickListener {
        void onItemClicked(RecyclerView recyclerView, int position, View v);    }

    public interface OnItemLongClickListener {

        boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);    }
}
5)LocationHelper.java
========================
package com.eppico.utility;
import android.Manifest;import android.app.Activity;import android.content.pm.PackageManager;import android.location.Location;import android.os.Bundle;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.support.v4.app.ActivityCompat;import android.util.Log;
import com.google.android.gms.common.ConnectionResult;import com.google.android.gms.common.GoogleApiAvailability;import com.google.android.gms.common.api.GoogleApiClient;import com.google.android.gms.location.LocationListener;import com.google.android.gms.location.LocationRequest;import com.google.android.gms.location.LocationServices;
/** * Created by rushil on 13/12/16. */
public class LocationHelper implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private static LocationHelper locationHelper;    private LocationRequest mLocationRequest;    private GoogleApiClient mGoogleApiClient;
    private static final int REQUEST_CODE_RECOVER_PLAY_SERVICES = 101;    private static final int REQUEST_CHECK_SETTINGS = 102;    private static final int REQ_PERMISSION_LOCATION = 103;
    private Activity activity;    Location mLastLocation;
    public static LocationHelper getInstance() {
        if (locationHelper == null)
            locationHelper = new LocationHelper();        return locationHelper;
    }

    private void getCurrentLatLong(Activity activity) {
        this.activity = activity;        buildGoogleApiClient(activity);
        if (checkLocationPermission(activity)) {
            //Connect Google API client            if (checkGooglePlayServices(activity)) {

                /**Note: This dialog is hide at getNearestLocation() and onLocationChanged()*/                //customDialog.show(getActivity(),getString(R.string.txtLoadingFindingLocation),false);                CustomDialog.getInstance().show(activity,false);                buildGoogleApiClient(activity);                //prepare connection request                createLocationRequest();            }
        }
    }

    private synchronized void buildGoogleApiClient(Activity activity) {
        mGoogleApiClient = new GoogleApiClient.Builder(activity)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();    }

    private boolean checkLocationPermission(Activity activity) {
        // Check if the Location permission is already available.        if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            // Camera permission has not been granted.
            requestLocationPermission(activity);
        } else {
            // Camera permissions is already available, show the camera preview.            return true;        }
        return false;    }

    /**     * Requests the Location permission.     * If the permission has been denied previously, a SnackBar will prompt the user to grant the     * permission, otherwise it is requested directly.     */    private void requestLocationPermission(Activity activity) {

        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},                REQ_PERMISSION_LOCATION);    }

    /**     * Initialize location request     */    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();        mLocationRequest.setInterval(20000);        mLocationRequest.setFastestInterval(5000);        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        if (checkLocationPermission(activity)) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);        }

        //settingsRequest();    }

    private boolean checkGooglePlayServices(Activity activity) {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();        int result = googleAPI.isGooglePlayServicesAvailable(activity);        if (result != ConnectionResult.SUCCESS) {
            if (googleAPI.isUserResolvableError(result)) {
                googleAPI.getErrorDialog(activity, result,                        REQUEST_CODE_RECOVER_PLAY_SERVICES).show();            }

            return false;        }

        return true;    }

    protected void startLocationUpdates() {
        if (checkLocationPermission(activity)) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);        }
    }

    /**     * Stop Location update listener     */    private void stopLocationUpdates() {
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);        }
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {

        startLocationUpdates();    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }

    @Override
    public void onLocationChanged(Location location) {

        MyLog.v("onLocationChanged","Location: " + location.getLatitude() + " : " + location.getLongitude());
    }
}
6)MyLog.java
==============
package com.eppico.utility;
import android.os.Environment;import android.support.annotation.NonNull;import android.util.Log;
import com.eppico.BuildConfig;
import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;
public class MyLog {
    //private static final String TAG = "SKApp";    //public static boolean IS_DEBUG = BuildConfig.DEBUG;
    public static void i(@NonNull String tag, final String msg) {
        if (BuildConfig.DEBUG)
            Log.i(tag, msg);
    }
    public static void v(@NonNull String tag, final String msg) {
        if (BuildConfig.DEBUG)
            Log.v(tag, msg);
    }
    public static void d(@NonNull String tag, final String msg) {
        if (BuildConfig.DEBUG)
            Log.d(tag, msg);
    }
    public static void e(@NonNull String tag, final String msg) {
        if (BuildConfig.DEBUG)
            Log.e(tag, msg);
    }
    public static void w(@NonNull String tag, final String msg) {
        if (BuildConfig.DEBUG)
            Log.w(tag, msg);    }


    public static void writeLogIntoFile(@NonNull String text,@NonNull String fileName) {
        final File logFile = new File(Environment.getExternalStorageDirectory() + fileName + ".txt");        if (!logFile.exists()) {
            try {
                logFile.createNewFile();            } catch (final IOException e) {
                e.printStackTrace();            }
        }
        try {
            // BufferedWriter for performance, true to set append to file flag            final BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));            buf.append(text);            buf.newLine();            buf.close();        } catch (final IOException e) {
            e.printStackTrace();        }
    }
}
7)PermissionUtil.java
=============================
/** Copyright 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.eppico.utility;
import android.Manifest;import android.app.Activity;import android.content.pm.PackageManager;
import java.util.ArrayList;
/** * Utility class that wraps access to the runtime permissions API in M and provides basic helper * methods. */public class PermissionUtil {

    static PermissionUtil permissionUtil;
    public static PermissionUtil getInstance()
    {
        if(permissionUtil==null)
            permissionUtil=new PermissionUtil();        return permissionUtil;    }


    /**     * Check that all given permissions have been granted by verifying that each entry in the     * given array is of the value {@link PackageManager#PERMISSION_GRANTED}.     *     * @see Activity#onRequestPermissionsResult(int, String[], int[])     */    public static boolean verifyPermissions(int[] grantResults) {
        // At least one result must be checked.        if(grantResults.length < 1){
            return false;        }

        // Verify that each required permission has been granted, otherwise return false.        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false;            }
        }
        return true;    }



    public  ArrayList<String> verifyPermissions(String permissions[],int[] grantResults) {
        // At least one result must be checked.
        if(permissions!=null && grantResults!=null && permissions.length>0 && grantResults.length>0)
        {
            ArrayList<String> listPermissionsNotGranted=new ArrayList<String>();            // Verify that each required permission has been granted, otherwise return false.            for (int i=0;i<grantResults.length;i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    listPermissionsNotGranted.add(permissions[i]);                }
            }

            return listPermissionsNotGranted;        }

        return null;
    }

    public ArrayList<String> getCameraPermissionsList()
    {
        ArrayList<String> listPermissionsNeed=new ArrayList<String>();        listPermissionsNeed.add(Manifest.permission.CAMERA);        listPermissionsNeed.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        return listPermissionsNeed;    }
    public ArrayList<String> getGalleryPermission()
    {
        ArrayList<String> listPermissionsNeed=new ArrayList<String>();        listPermissionsNeed.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        return listPermissionsNeed;    }

}
8)PrefHelper.java
=====================
package com.eppico.utility;
import android.content.SharedPreferences.Editor;import android.util.Log;
import com.eppico.MyApplication;
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Map;
/** * This class is help to store/get data into preference * */public class PrefHelper {

   public static void setString(String key, String value) {
      final Editor editor = MyApplication.myPref.edit();      editor.putString(key, value);      apply(editor);   }

   public static String getString(String key,String defaultValue) {
      return MyApplication.myPref.getString(key, defaultValue);   }

   public static void setInt(String key,int value) {
      final Editor editor = MyApplication.myPref.edit();      editor.putInt(key, value);      apply(editor);   }

   public static int getInt(String key,int defaultValue) {
      return MyApplication.myPref.getInt(key, defaultValue);   }

   public static boolean getBoolean(String key,boolean defaultValue) {
      return MyApplication.myPref.getBoolean(key, defaultValue);   }

   public static void setBoolean(String key,boolean value) {
      final Editor editor = MyApplication.myPref.edit();      editor.putBoolean(key, value);      apply(editor);   }

   public static long getLong(String key,long defaultValue) {
      return MyApplication.myPref.getLong(key, defaultValue);   }

   public static void setLong(String key,long value) {
      final Editor editor = MyApplication.myPref.edit();      editor.putLong(key, value);      apply(editor);   }

   public static double getDouble(String key,double defaultValue) {
//    return MyApplication.myPref.getLong(key, defaultValue);      return Double.longBitsToDouble(MyApplication.myPref.getLong(key, Double.doubleToLongBits(defaultValue)));   }

   public static void setDouble(String key,double value) {
      final Editor editor = MyApplication.myPref.edit();      editor.putLong(key, Double.doubleToRawLongBits(value));      apply(editor);   }

   public static void deletePreference(String key) {
      final Editor editor = MyApplication.myPref.edit();      editor.remove(key);      apply(editor);   }

   public static void deletePreferences(String[] keys) {
      if(keys!=null && keys.length>0)
      {
//       Editor editor = null;         for(int i=0;i<keys.length;i++)
         {
            final Editor editor= MyApplication.myPref.edit();            editor.remove(keys[i]);            apply(editor);         }
      }
   }

   public static void deleteAllPreferences() {
      final Editor editor = MyApplication.myPref.edit();      editor.clear();      apply(editor);   }

   /*Delete all preference of app except passed argument*/   public static void deletePreferencesExcept(ArrayList<String> keysNotDelete) {
      //SharedPreferences pref=PreferenceManager.getDefaultSharedPreferences(MyApplication.appInstance);      Map<String,?> keys = MyApplication.myPref.getAll();
      for(Map.Entry<String,?> entry : keys.entrySet()){
         Log.d("map values", entry.getKey() + ": " +
               entry.getValue().toString());         if(!keysNotDelete.contains(entry.getKey()))
         {
            final Editor editor= MyApplication.myPref.edit();            editor.remove(entry.getKey());            apply(editor);         }
      }
   }

   // Faster pref saving for high performance   private static final Method sApplyMethod = findApplyMethod();
   private static Method findApplyMethod() {
      try {
         final Class<Editor> cls = Editor.class;         return cls.getMethod("apply");      } catch (final NoSuchMethodException unused) {
         // fall through      }
      return null;   }

   public static void apply(final Editor editor) {
      if (sApplyMethod != null) {
         try {
            sApplyMethod.invoke(editor);            return;         } catch (final InvocationTargetException unused) {
            // fall through         } catch (final IllegalAccessException unused) {
            // fall through         }
      }
      editor.commit();   }
}
9)TimeAgo.java
================
package com.eppico.utility;
import android.content.Context;import com.eppico.R;import java.util.Arrays;import java.util.Calendar;import java.util.List;import java.util.concurrent.TimeUnit;
public class TimeAgo {
    private  static List<Long> times;    private  static List<String> timesString;    private static TimeAgo timeAgo;
    public static TimeAgo getInstance(){
        if(timeAgo == null){
            timeAgo = new TimeAgo();        }
         return timeAgo;    }

    public void init(Context context)
    {
        if(times == null) {
            times = Arrays.asList(
                    TimeUnit.DAYS.toMillis(365),                    TimeUnit.DAYS.toMillis(30),                    TimeUnit.DAYS.toMillis(1),                    TimeUnit.HOURS.toMillis(1),                    TimeUnit.MINUTES.toMillis(1),                    TimeUnit.SECONDS.toMillis(1));        }

        if(timesString == null) {
            timesString = Arrays.asList(context.getString(R.string.strYear), context.getString(R.string.strMonth),                    context.getString(R.string.strDay), context.getString(R.string.strHour), context.getString(R.string.strMinute),                    context.getString(R.string.strSecond));        }
    }

    public String toDuration(Context context, long millisec) {
        init(context);        long todayMilli= Calendar.getInstance().getTimeInMillis();        long duration=todayMilli-millisec;        StringBuffer res = new StringBuffer();
        for(int i=0;i< times.size(); i++) {
            Long current = times.get(i);            long temp = duration/current;            if(temp>0) {
                res.append(temp).append(" ").append( timesString.get(i)).append(temp > 1 ? context.getString(R.string.strS) : "")
                        .append(" " + context.getString(R.string.strAgo));                break;            }
        }
        if("".equals(res.toString()))
            return context.getString(R.string.strJustNow);        else            return res.toString();    }

    public static void main(String args[]) {}

//    /**//     * Function to convert millisecond in human readable date format.//     * @param millisec contains millisecond value.//     * @return human readable format date.//     *///    public String toGetDuration(Context mContext,long millisec) {//        init(mContext);//        millisec= millisec * 1000;//        long todayMilli= Calendar.getInstance().getTimeInMillis();//        long duration=todayMilli-millisec;//        StringBuffer res = new StringBuffer();//        for(int i=0;i< times.size(); i++) {//            Long current = times.get(i);//            long temp = duration/current;////            if(temp>0) {//                res.append(temp).append(" ").append(timesString.get(i) ).append(temp > 1 ? mContext.getString(R.string.strS) : "")//                        .append(" " + mContext.getString(R.string.strAgo));//                break;//            }//        }////        if("".equals(res.toString()))//            return mContext.getString(R.string.strJustNow);//        else//            return res.toString();//    }}
10)ToastHelper.java
====================
package com.eppico.utility;
import android.content.Context;import android.support.annotation.NonNull;import android.widget.Toast;

public class ToastHelper {
    private static Toast toast = null;    private static ToastHelper toastHelper;
    public static ToastHelper getInstance() {
        if (toastHelper == null)
            toastHelper = new ToastHelper();        return toastHelper;    }


    public void showToast(@NonNull Context context, String message) {

        if (toast != null) {
            toast.cancel();        }
        toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);        toast.show();    }

    public void showToast(@NonNull Context context, String message, int duration) {

        if (toast != null) {
            toast.cancel();        }
        toast = Toast.makeText(context, message, duration);        toast.show();    }


    /*public void showToast(@NonNull Context context, String message, int duration, int gravity) {
        if (toast != null) {            toast.cancel();        }        toast = Toast.makeText(context, message, duration);        toast.setGravity(gravity, 0, 0);        toast.show();    }*/}
11)Utils.java
==============
package com.eppico.utility;
import android.annotation.SuppressLint;import android.app.AlertDialog;import android.content.Context;import android.content.DialogInterface;import android.content.SharedPreferences;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.Signature;import android.database.Cursor;import android.net.ConnectivityManager;import android.net.Uri;import android.os.Environment;import android.provider.MediaStore;import android.support.annotation.NonNull;import android.support.design.widget.Snackbar;import android.util.Base64;import android.util.DisplayMetrics;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.view.inputmethod.InputMethodManager;import android.widget.EditText;import android.widget.Toast;
import com.eppico.R;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.File;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Calendar;import java.util.Date;import java.util.regex.Matcher;import java.util.regex.Pattern;
/** * Created by manisha on 12/12/16. */public class Utils {
    private static Utils utils;    public static Utils getInstance() {
        if (utils == null)
            utils = new Utils();        return utils;    }

    public boolean isEmailValid(String email) {
        String expression = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";        CharSequence inputStr = email;        boolean flag = false;        Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);        Matcher matcher = pattern.matcher(inputStr);        if (matcher.matches()) {
            flag = true;        }
        return flag;    }

    public boolean checkInternetConnection(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);        // test for connection        if (cm.getActiveNetworkInfo() != null                && cm.getActiveNetworkInfo().isAvailable()
                && cm.getActiveNetworkInfo().isConnected()) {
            return true;        } else {
            Log.v("", "Internet Connection Not Available");            //Toast.makeText(context, context.getResources().getString(R.string.network_connectivity_not_available), Toast.LENGTH_SHORT).show();            return false;        }
    }

    public String generateHashKey(Context context) {
        String hashKey = "";        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);            for (Signature signature : info.signatures) {
                MessageDigest md = MessageDigest.getInstance("SHA");                md.update(signature.toByteArray());                hashKey = Base64.encodeToString(md.digest(), Base64.DEFAULT);                MyLog.v("TAG", "Hash Key:" + hashKey);            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();        }
        return hashKey;    }

    @SuppressLint("NewApi")
    public static boolean validateString(String object) {
        boolean flag = false;        if (object != null && !object.equalsIgnoreCase("null") && !object.equalsIgnoreCase("(null)") &&
                !object.isEmpty() && !object.equalsIgnoreCase("(null)")) {
            flag = true;        }
        return flag;    }

    /**     * Images is stored in share directory while sharing, or profile images while change profile image, delete those images     */    public void deleteTempImagesDirectory(@NonNull Context context) {
        try {
//            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Constants.DIR_MAIN);            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), context.getString(R.string.app_name));            if (mediaStorageDir.exists()) {
//                File shareDirectory = new File(mediaStorageDir + File.separator + Constants.DIR_SHARE);
                //Delete Settings directory where we save logged in user image while login                File shareDirectory = new File(mediaStorageDir + File.separator + context.getString(R.string.dirSettings));                if (shareDirectory.exists())
                    deleteRecursive(shareDirectory);
                //Delete Media directory. Which contain all images and videos use for upload spot and post                File dirMedia = new File(mediaStorageDir + File.separator + context.getString(R.string.dirMedia));                if (dirMedia.exists())
                    deleteRecursive(dirMedia);
            }
        } catch (Exception e) {
            e.printStackTrace();        }
    }

    /**     * Delete all files and directory itself     */    private void deleteRecursive(File fileOrDirectory) {
        if (fileOrDirectory.isDirectory())
            for (File child : fileOrDirectory.listFiles())
                deleteRecursive(child);
        fileOrDirectory.delete();    }

    public void hideKeyboard(View v, Context context) {
        InputMethodManager mgr = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);        mgr.hideSoftInputFromWindow(v.getWindowToken(), 0);    }

    public void showKeyboard(View v, Context context) {       /*     * InputMethodManager mgr =        * (InputMethodManager)context.getSystemService(       * Context.INPUT_METHOD_SERVICE); mgr.showSoftInput(v, 0);     */        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);        inputMethodManager.toggleSoftInputFromWindow(v.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0);    }

    /**     * Function is used to hide keyboard while user click outside of keyboard on screen.     * @param view  contains parent view id to get all child views.     */    @SuppressLint("ClickableViewAccessibility")
    public void setupOutSideTouchHideKeyboard(final View view)
    {
        if(view==null)
            return;        // Set up touch listener for non-text box views to hide keyboard.        if (!(view instanceof EditText))
        {
            view.setOnTouchListener(new View.OnTouchListener()
            {

                @Override
                public boolean onTouch(View v, MotionEvent event)
                {
                    hideKeyboard(view,view.getContext());                    return false;                }

            });        }

        // If a layout container, iterate over children and seed recursion.        if (view instanceof ViewGroup)
        {

            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
            {

                View innerView = ((ViewGroup) view).getChildAt(i);
                setupOutSideTouchHideKeyboard(innerView);            }
        }
    }

    public int[] getScreenWidthHeight(Context context)
    {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
      /*Display display = wm.getDefaultDisplay();      int width = display.getWidth(); // deprecated      int height = display.getHeight(); // deprecated*/
        DisplayMetrics displaymetrics = new DisplayMetrics();        wm.getDefaultDisplay().getMetrics(displaymetrics);        int screenWidth = displaymetrics.widthPixels;        int screenHeight = displaymetrics.heightPixels;        int[] wh = { screenWidth, screenHeight };//    int[] wh = { width, height };        return wh;    }

    public float getFileSizeInMb(File file)
    {
        try{
            if(!file.exists())
                return 0;            // Get length of file in bytes            long fileSizeInBytes = file.length();            // Convert the bytes to Kilobytes (1 KB = 1024 Bytes)            float fileSizeInKB = fileSizeInBytes / 1024;            // Convert the KB to MegaBytes (1 MB = 1024 KBytes)            float fileSizeInMB = fileSizeInKB / 1024;            return fileSizeInMB;        }catch (Exception e)
        {
            e.printStackTrace();        }
        return 0;    }

    /**Return image path of given URI*/    public String getRealPathFromURI(Context context,Uri contentURI) {
//        Cursor cursor = getActivity().getContentResolver().query(contentURI, null, null, null, null);        String[] projection = { MediaStore.Images.Media.DATA };        Cursor cursor = context.getContentResolver().query(contentURI, projection, null, null, null);        //Some of gallery application is return null        if (cursor == null) {
            return contentURI.getPath();        } else {
            cursor.moveToFirst();            int columnIndex = cursor.getColumnIndex(projection[0]);            String picturePath = cursor.getString(columnIndex);            cursor.close();            return picturePath;        }
    }

    /**It will encode the unicode characters properly before sending to web server.*/    public String escapeJava(String text)
    {
        if(text!=null && text.length()>0)
            return StringEscapeUtils.escapeJava(text);        return "";    }

    /**it will decode the unicode characters properly after receiving the response from web server.*/    public String unescapeJava(String text)
    {
        if(text!=null && text.length()>0)
            return StringEscapeUtils.unescapeJava(text);        return "";    }

    /**Return formatted date.*/    public String getFormattedDate(Context context,String date) {
        try {
            SimpleDateFormat sdfInput = new SimpleDateFormat(context.getString(R.string.dateFormatOfAPI));            SimpleDateFormat sdfOutput = new SimpleDateFormat(context.getString(R.string.dateFormatOfApp));
            return sdfOutput.format(sdfInput.parse(date));        } catch (Exception e) {
            e.printStackTrace();        }

        return "";    }

    /**Return formatted date of passed output format*/    public String getFormattedDate(String date, String input, String output) {
        try {
            SimpleDateFormat sdfInput = new SimpleDateFormat(input);            SimpleDateFormat sdfOutput = new SimpleDateFormat(output);
            return sdfOutput.format(sdfInput.parse(date));        } catch (Exception e) {
            e.printStackTrace();        }

        return "";    }

    public String getDateDifference(Context context,String date) {
        Date thenDate = covertStringToDate(date);        //getFormattedDate(thenDate);        String displayDate = Utils.getInstance().getFormattedDate(context,date);
        Calendar now = Calendar.getInstance();        Calendar then = Calendar.getInstance();        now.setTime(new Date());        then.setTime(thenDate);
        // Get the represented date in milliseconds        long nowMs = now.getTimeInMillis();        long thenMs = then.getTimeInMillis();        // Calculate difference in milliseconds        long diff = nowMs - thenMs;
        // Calculate difference in seconds        long diffSeconds = diff / 1000;        long diffMinutes = diff / (60 * 1000);        long diffHours = diff / (60 * 60 * 1000);        long diffDays = diff / (24 * 60 * 60 * 1000);
        if (diffMinutes < 60) {
            if (diffMinutes < 0)
                return displayDate;            else if (diffMinutes == 0)
                return context.getResources().getString(R.string.just_now);
            return diffMinutes + " " + context.getResources().getQuantityString(R.plurals.minuteAgo, (int) diffMinutes);            /*if (diffMinutes == 1)                return diffMinutes + " " + mContext.getResources().getString(R.string.minute_ago);            else                return diffMinutes + " " + mContext.getResources().getString(R.string.minutes_ago);*/
        } else if (diffHours < 24) {
            /*if (diffHours == 1)                return diffHours + " " + mContext.getResources().getString(R.string.hour_ago);            else                return diffHours + " " + mContext.getResources().getString(R.string.hours_ago);*/
            return diffHours + " " + context.getResources().getQuantityString(R.plurals.hourAgo, (int) diffHours);
        } else if (diffDays < 30) {
            /*if (diffDays == 1)                return diffDays + " " + mContext.getResources().getString(R.string.day_ago);            else                return diffDays + " " + mContext.getResources().getString(R.string.days_ago);*/
            return diffDays + " " + context.getResources().getQuantityString(R.plurals.dayAgo, (int) diffDays);        } else {
            return displayDate;        }
    }

    public Date covertStringToDate(String strDate) {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");        Date date = null;
        try {
            date = formatter.parse(strDate);        } catch (ParseException e) {
            e.printStackTrace();        }
        return date;    }

}
*******************com.app.febmenu*********************
1)FloatingActionButton.java
===========================
package com.eppico.fabmenu;
import android.annotation.TargetApi;import android.content.Context;import android.content.res.ColorStateList;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorFilter;import android.graphics.Outline;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.RectF;import android.graphics.Xfermode;import android.graphics.drawable.ColorDrawable;import android.graphics.drawable.Drawable;import android.graphics.drawable.LayerDrawable;import android.graphics.drawable.RippleDrawable;import android.graphics.drawable.ShapeDrawable;import android.graphics.drawable.StateListDrawable;import android.graphics.drawable.shapes.OvalShape;import android.graphics.drawable.shapes.Shape;import android.os.Build;import android.os.Parcel;import android.os.Parcelable;import android.os.SystemClock;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.ViewOutlineProvider;import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.widget.ImageButton;import android.widget.TextView;
import com.eppico.R;
public class FloatingActionButton extends ImageButton {

    public static final int SIZE_NORMAL = 0;    public static final int SIZE_MINI = 1;
    int mFabSize;    boolean mShowShadow;    int mShadowColor;    int mShadowRadius = Util.dpToPx(getContext(), 4f);    int mShadowXOffset = Util.dpToPx(getContext(), 1f);    int mShadowYOffset = Util.dpToPx(getContext(), 3f);
    private static final Xfermode PORTER_DUFF_CLEAR = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);    private static final long PAUSE_GROWING_TIME = 200;    private static final double BAR_SPIN_CYCLE_TIME = 500;    private static final int BAR_MAX_LENGTH = 270;
    private int mColorNormal;    private int mColorPressed;    private int mColorDisabled;    private int mColorRipple;    private Drawable mIcon;    private int mIconSize = Util.dpToPx(getContext(), 24f);    private Animation mShowAnimation;    private Animation mHideAnimation;    private String mLabelText;    private OnClickListener mClickListener;    private Drawable mBackgroundDrawable;    private boolean mUsingElevation;    private boolean mUsingElevationCompat;
    // Progress    private boolean mProgressBarEnabled;    private int mProgressWidth = Util.dpToPx(getContext(), 6f);    private int mProgressColor;    private int mProgressBackgroundColor;    private boolean mShouldUpdateButtonPosition;    private float mOriginalX = -1;    private float mOriginalY = -1;    private boolean mButtonPositionSaved;    private RectF mProgressCircleBounds = new RectF();    private Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    private Paint mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    private boolean mProgressIndeterminate;    private long mLastTimeAnimated;    private float mSpinSpeed = 195.0f; //The amount of degrees per second    private long mPausedTimeWithoutGrowing = 0;    private double mTimeStartGrowing;    private boolean mBarGrowingFromFront = true;    private int mBarLength = 16;    private float mBarExtraLength;    private float mCurrentProgress;    private float mTargetProgress;    private int mProgress;    private boolean mAnimateProgress;    private boolean mShouldProgressIndeterminate;    private boolean mShouldSetProgress;    private int mProgressMax = 100;    private boolean mShowProgressBackground;
    public FloatingActionButton(Context context) {
        this(context, null);    }

    public FloatingActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);    }

    public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);        init(context, attrs, defStyleAttr);    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);        init(context, attrs, defStyleAttr);    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingActionButton, defStyleAttr, 0);        mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, 0xFFDA4336);        mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, 0xFFE75043);        mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, 0xFFAAAAAA);        mColorRipple = attr.getColor(R.styleable.FloatingActionButton_fab_colorRipple, 0x99FFFFFF);        mShowShadow = attr.getBoolean(R.styleable.FloatingActionButton_fab_showShadow, true);        mShadowColor = attr.getColor(R.styleable.FloatingActionButton_fab_shadowColor, 0x66000000);        mShadowRadius = attr.getDimensionPixelSize(R.styleable.FloatingActionButton_fab_shadowRadius, mShadowRadius);        mShadowXOffset = attr.getDimensionPixelSize(R.styleable.FloatingActionButton_fab_shadowXOffset, mShadowXOffset);        mShadowYOffset = attr.getDimensionPixelSize(R.styleable.FloatingActionButton_fab_shadowYOffset, mShadowYOffset);        mFabSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL);        mLabelText = attr.getString(R.styleable.FloatingActionButton_fab_label);        mShouldProgressIndeterminate = attr.getBoolean(R.styleable.FloatingActionButton_fab_progress_indeterminate, false);        mProgressColor = attr.getColor(R.styleable.FloatingActionButton_fab_progress_color, 0xFF009688);        mProgressBackgroundColor = attr.getColor(R.styleable.FloatingActionButton_fab_progress_backgroundColor, 0x4D000000);        mProgressMax = attr.getInt(R.styleable.FloatingActionButton_fab_progress_max, mProgressMax);        mShowProgressBackground = attr.getBoolean(R.styleable.FloatingActionButton_fab_progress_showBackground, true);
        if (attr.hasValue(R.styleable.FloatingActionButton_fab_progress)) {
            mProgress = attr.getInt(R.styleable.FloatingActionButton_fab_progress, 0);            mShouldSetProgress = true;        }

        if (attr.hasValue(R.styleable.FloatingActionButton_fab_elevationCompat)) {
            float elevation = attr.getDimensionPixelOffset(R.styleable.FloatingActionButton_fab_elevationCompat, 0);            if (isInEditMode()) {
                setElevation(elevation);            } else {
                setElevationCompat(elevation);            }
        }

        initShowAnimation(attr);        initHideAnimation(attr);        attr.recycle();
        if (isInEditMode()) {
            if (mShouldProgressIndeterminate) {
                setIndeterminate(true);            } else if (mShouldSetProgress) {
                saveButtonOriginalPosition();                setProgress(mProgress, false);            }
        }

//        updateBackground();        setClickable(true);    }

    private void initShowAnimation(TypedArray attr) {
        int resourceId = attr.getResourceId(R.styleable.FloatingActionButton_fab_showAnimation, R.anim.fab_scale_up);        mShowAnimation = AnimationUtils.loadAnimation(getContext(), resourceId);    }

    private void initHideAnimation(TypedArray attr) {
        int resourceId = attr.getResourceId(R.styleable.FloatingActionButton_fab_hideAnimation, R.anim.fab_scale_down);        mHideAnimation = AnimationUtils.loadAnimation(getContext(), resourceId);    }

    private int getCircleSize() {
        return getResources().getDimensionPixelSize(mFabSize == SIZE_NORMAL
                ? R.dimen.fab_size_normal : R.dimen.fab_size_mini);    }

    private int calculateMeasuredWidth() {
        int width = getCircleSize() + calculateShadowWidth();        if (mProgressBarEnabled) {
            width += mProgressWidth * 2;        }
        return width;    }

    private int calculateMeasuredHeight() {
        int height = getCircleSize() + calculateShadowHeight();        if (mProgressBarEnabled) {
            height += mProgressWidth * 2;        }
        return height;    }

    int calculateShadowWidth() {
        return hasShadow() ? getShadowX() * 2 : 0;    }

    int calculateShadowHeight() {
        return hasShadow() ? getShadowY() * 2 : 0;    }

    private int getShadowX() {
        return mShadowRadius + Math.abs(mShadowXOffset);    }

    private int getShadowY() {
        return mShadowRadius + Math.abs(mShadowYOffset);    }

    private float calculateCenterX() {
        return (float) (getMeasuredWidth() / 2);    }

    private float calculateCenterY() {
        return (float) (getMeasuredHeight() / 2);    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(calculateMeasuredWidth(), calculateMeasuredHeight());    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mProgressBarEnabled) {
            if (mShowProgressBackground) {
                canvas.drawArc(mProgressCircleBounds, 360, 360, false, mBackgroundPaint);            }

            boolean shouldInvalidate = false;
            if (mProgressIndeterminate) {
                shouldInvalidate = true;
                long deltaTime = SystemClock.uptimeMillis() - mLastTimeAnimated;                float deltaNormalized = deltaTime * mSpinSpeed / 1000.0f;
                updateProgressLength(deltaTime);
                mCurrentProgress += deltaNormalized;                if (mCurrentProgress > 360f) {
                    mCurrentProgress -= 360f;                }

                mLastTimeAnimated = SystemClock.uptimeMillis();                float from = mCurrentProgress - 90;                float to = mBarLength + mBarExtraLength;
                if (isInEditMode()) {
                    from = 0;                    to = 135;                }

                canvas.drawArc(mProgressCircleBounds, from, to, false, mProgressPaint);            } else {
                if (mCurrentProgress != mTargetProgress) {
                    shouldInvalidate = true;                    float deltaTime = (float) (SystemClock.uptimeMillis() - mLastTimeAnimated) / 1000;                    float deltaNormalized = deltaTime * mSpinSpeed;
                    if (mCurrentProgress > mTargetProgress) {
                        mCurrentProgress = Math.max(mCurrentProgress - deltaNormalized, mTargetProgress);                    } else {
                        mCurrentProgress = Math.min(mCurrentProgress + deltaNormalized, mTargetProgress);                    }
                    mLastTimeAnimated = SystemClock.uptimeMillis();                }

                canvas.drawArc(mProgressCircleBounds, -90, mCurrentProgress, false, mProgressPaint);            }

            if (shouldInvalidate) {
                invalidate();            }
        }
    }

    private void updateProgressLength(long deltaTimeInMillis) {
        if (mPausedTimeWithoutGrowing >= PAUSE_GROWING_TIME) {
            mTimeStartGrowing += deltaTimeInMillis;
            if (mTimeStartGrowing > BAR_SPIN_CYCLE_TIME) {
                mTimeStartGrowing -= BAR_SPIN_CYCLE_TIME;                mPausedTimeWithoutGrowing = 0;                mBarGrowingFromFront = !mBarGrowingFromFront;            }

            float distance = (float) Math.cos((mTimeStartGrowing / BAR_SPIN_CYCLE_TIME + 1) * Math.PI) / 2 + 0.5f;            float length = BAR_MAX_LENGTH - mBarLength;
            if (mBarGrowingFromFront) {
                mBarExtraLength = distance * length;            } else {
                float newLength = length * (1 - distance);                mCurrentProgress += (mBarExtraLength - newLength);                mBarExtraLength = newLength;            }
        } else {
            mPausedTimeWithoutGrowing += deltaTimeInMillis;        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        saveButtonOriginalPosition();
        if (mShouldProgressIndeterminate) {
            setIndeterminate(true);            mShouldProgressIndeterminate = false;        } else if (mShouldSetProgress) {
            setProgress(mProgress, mAnimateProgress);            mShouldSetProgress = false;        } else if (mShouldUpdateButtonPosition) {
            updateButtonPosition();            mShouldUpdateButtonPosition = false;        }
        super.onSizeChanged(w, h, oldw, oldh);
        setupProgressBounds();        setupProgressBarPaints();        updateBackground();    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void setLayoutParams(ViewGroup.LayoutParams params) {
        if (params instanceof ViewGroup.MarginLayoutParams && mUsingElevationCompat) {
            ((ViewGroup.MarginLayoutParams) params).leftMargin += getShadowX();            ((ViewGroup.MarginLayoutParams) params).topMargin += getShadowY();            ((ViewGroup.MarginLayoutParams) params).rightMargin += getShadowX();            ((ViewGroup.MarginLayoutParams) params).bottomMargin += getShadowY();        }
        super.setLayoutParams(params);    }

    void updateBackground() {
        LayerDrawable layerDrawable;        if (hasShadow()) {
            layerDrawable = new LayerDrawable(new Drawable[]{
                    new Shadow(),                    createFillDrawable(),                    getIconDrawable()
            });        } else {
            layerDrawable = new LayerDrawable(new Drawable[]{
                    createFillDrawable(),                    getIconDrawable()
            });        }

        int iconSize = -1;        if (getIconDrawable() != null) {
            iconSize = Math.max(getIconDrawable().getIntrinsicWidth(), getIconDrawable().getIntrinsicHeight());        }
        int iconOffset = (getCircleSize() - (iconSize > 0 ? iconSize : mIconSize)) / 2;        int circleInsetHorizontal = hasShadow() ? mShadowRadius + Math.abs(mShadowXOffset) : 0;        int circleInsetVertical = hasShadow() ? mShadowRadius + Math.abs(mShadowYOffset) : 0;
        if (mProgressBarEnabled) {
            circleInsetHorizontal += mProgressWidth;            circleInsetVertical += mProgressWidth;        }

        /*layerDrawable.setLayerInset(                mShowShadow ? 1 : 0,                circleInsetHorizontal,                circleInsetVertical,                circleInsetHorizontal,                circleInsetVertical        );*/        layerDrawable.setLayerInset(
                hasShadow() ? 2 : 1,                circleInsetHorizontal + iconOffset,                circleInsetVertical + iconOffset,                circleInsetHorizontal + iconOffset,                circleInsetVertical + iconOffset
        );
        setBackgroundCompat(layerDrawable);    }

    protected Drawable getIconDrawable() {
        if (mIcon != null) {
            return mIcon;        } else {
            return new ColorDrawable(Color.TRANSPARENT);        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private Drawable createFillDrawable() {
        StateListDrawable drawable = new StateListDrawable();        drawable.addState(new int[]{-android.R.attr.state_enabled}, createCircleDrawable(mColorDisabled));        drawable.addState(new int[]{android.R.attr.state_pressed}, createCircleDrawable(mColorPressed));        drawable.addState(new int[]{}, createCircleDrawable(mColorNormal));
        if (Util.hasLollipop()) {
            RippleDrawable ripple = new RippleDrawable(new ColorStateList(new int[][]{{}},                    new int[]{mColorRipple}), drawable, null);            setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    outline.setOval(0, 0, view.getWidth(), view.getHeight());                }
            });            setClipToOutline(true);            mBackgroundDrawable = ripple;            return ripple;        }

        mBackgroundDrawable = drawable;        return drawable;    }

    private Drawable createCircleDrawable(int color) {
        CircleDrawable shapeDrawable = new CircleDrawable(new OvalShape());        shapeDrawable.getPaint().setColor(color);        return shapeDrawable;    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void setBackgroundCompat(Drawable drawable) {
        if (Util.hasJellyBean()) {
            setBackground(drawable);        } else {
            setBackgroundDrawable(drawable);        }
    }

    private void saveButtonOriginalPosition() {
        if (!mButtonPositionSaved) {
            if (mOriginalX == -1) {
                mOriginalX = getX();            }

            if (mOriginalY == -1) {
                mOriginalY = getY();            }

            mButtonPositionSaved = true;        }
    }

    private void updateButtonPosition() {
        float x;        float y;        if (mProgressBarEnabled) {
            x = mOriginalX > getX() ? getX() + mProgressWidth : getX() - mProgressWidth;            y = mOriginalY > getY() ? getY() + mProgressWidth : getY() - mProgressWidth;        } else {
            x = mOriginalX;            y = mOriginalY;        }
        setX(x);        setY(y);    }

    private void setupProgressBarPaints() {
        mBackgroundPaint.setColor(mProgressBackgroundColor);        mBackgroundPaint.setStyle(Paint.Style.STROKE);        mBackgroundPaint.setStrokeWidth(mProgressWidth);
        mProgressPaint.setColor(mProgressColor);        mProgressPaint.setStyle(Paint.Style.STROKE);        mProgressPaint.setStrokeWidth(mProgressWidth);    }

    private void setupProgressBounds() {
        int circleInsetHorizontal = hasShadow() ? getShadowX() : 0;        int circleInsetVertical = hasShadow() ? getShadowY() : 0;        mProgressCircleBounds = new RectF(
                circleInsetHorizontal + mProgressWidth / 2,                circleInsetVertical + mProgressWidth / 2,                calculateMeasuredWidth() - circleInsetHorizontal - mProgressWidth / 2,                calculateMeasuredHeight() - circleInsetVertical - mProgressWidth / 2        );    }

    Animation getShowAnimation() {
        return mShowAnimation;    }

    Animation getHideAnimation() {
        return mHideAnimation;    }

    void playShowAnimation() {
        mHideAnimation.cancel();        startAnimation(mShowAnimation);    }

    void playHideAnimation() {
        mShowAnimation.cancel();        startAnimation(mHideAnimation);    }

    OnClickListener getOnClickListener() {
        return mClickListener;    }

    Label getLabelView() {
        return (Label) getTag(R.id.fab_label);    }

    void setColors(int colorNormal, int colorPressed, int colorRipple) {
        mColorNormal = colorNormal;        mColorPressed = colorPressed;        mColorRipple = colorRipple;    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    void onActionDown() {
        if (mBackgroundDrawable instanceof StateListDrawable) {
            StateListDrawable drawable = (StateListDrawable) mBackgroundDrawable;            drawable.setState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed});        } else if (Util.hasLollipop()) {
            RippleDrawable ripple = (RippleDrawable) mBackgroundDrawable;            ripple.setState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed});            ripple.setHotspot(calculateCenterX(), calculateCenterY());            ripple.setVisible(true, true);        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    void onActionUp() {
        if (mBackgroundDrawable instanceof StateListDrawable) {
            StateListDrawable drawable = (StateListDrawable) mBackgroundDrawable;            drawable.setState(new int[]{android.R.attr.state_enabled});        } else if (Util.hasLollipop()) {
            RippleDrawable ripple = (RippleDrawable) mBackgroundDrawable;            ripple.setState(new int[]{android.R.attr.state_enabled});            ripple.setHotspot(calculateCenterX(), calculateCenterY());            ripple.setVisible(true, true);        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mClickListener != null && isEnabled()) {
            Label label = (Label) getTag(R.id.fab_label);            if (label == null) return super.onTouchEvent(event);
            int action = event.getAction();            switch (action) {
                case MotionEvent.ACTION_UP:
                    if (label != null) {
                        label.onActionUp();                    }
                    onActionUp();                    break;
                case MotionEvent.ACTION_CANCEL:
                    if (label != null) {
                        label.onActionUp();                    }
                    onActionUp();                    break;            }
            mGestureDetector.onTouchEvent(event);        }
        return super.onTouchEvent(event);    }

    GestureDetector mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent e) {
            Label label = (Label) getTag(R.id.fab_label);            if (label != null) {
                label.onActionDown();            }
            onActionDown();            return super.onDown(e);        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            Label label = (Label) getTag(R.id.fab_label);            if (label != null) {
                label.onActionUp();            }
            onActionUp();            return super.onSingleTapUp(e);        }
    });
    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        ProgressSavedState ss = new ProgressSavedState(superState);
        ss.mCurrentProgress = this.mCurrentProgress;        ss.mTargetProgress = this.mTargetProgress;        ss.mSpinSpeed = this.mSpinSpeed;        ss.mProgressWidth = this.mProgressWidth;        ss.mProgressColor = this.mProgressColor;        ss.mProgressBackgroundColor = this.mProgressBackgroundColor;        ss.mShouldProgressIndeterminate = this.mProgressIndeterminate;        ss.mShouldSetProgress = this.mProgressBarEnabled && mProgress > 0 && !this.mProgressIndeterminate;        ss.mProgress = this.mProgress;        ss.mAnimateProgress = this.mAnimateProgress;        ss.mShowProgressBackground = this.mShowProgressBackground;
        return ss;    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof ProgressSavedState)) {
            super.onRestoreInstanceState(state);            return;        }

        ProgressSavedState ss = (ProgressSavedState) state;        super.onRestoreInstanceState(ss.getSuperState());
        this.mCurrentProgress = ss.mCurrentProgress;        this.mTargetProgress = ss.mTargetProgress;        this.mSpinSpeed = ss.mSpinSpeed;        this.mProgressWidth = ss.mProgressWidth;        this.mProgressColor = ss.mProgressColor;        this.mProgressBackgroundColor = ss.mProgressBackgroundColor;        this.mShouldProgressIndeterminate = ss.mShouldProgressIndeterminate;        this.mShouldSetProgress = ss.mShouldSetProgress;        this.mProgress = ss.mProgress;        this.mAnimateProgress = ss.mAnimateProgress;        this.mShowProgressBackground = ss.mShowProgressBackground;
        this.mLastTimeAnimated = SystemClock.uptimeMillis();    }

    private class CircleDrawable extends ShapeDrawable {

        private int circleInsetHorizontal;        private int circleInsetVertical;
        private CircleDrawable() {
        }

        private CircleDrawable(Shape s) {
            super(s);            circleInsetHorizontal = hasShadow() ? mShadowRadius + Math.abs(mShadowXOffset) : 0;            circleInsetVertical = hasShadow() ? mShadowRadius + Math.abs(mShadowYOffset) : 0;
            if (mProgressBarEnabled) {
                circleInsetHorizontal += mProgressWidth;                circleInsetVertical += mProgressWidth;            }
        }

        @Override
        public void draw(Canvas canvas) {
            setBounds(circleInsetHorizontal, circleInsetVertical, calculateMeasuredWidth()
                    - circleInsetHorizontal, calculateMeasuredHeight() - circleInsetVertical);            super.draw(canvas);        }
    }

    private class Shadow extends Drawable {

        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        private Paint mErase = new Paint(Paint.ANTI_ALIAS_FLAG);        private float mRadius;
        private Shadow() {
            this.init();        }

        private void init() {
            setLayerType(LAYER_TYPE_SOFTWARE, null);            mPaint.setStyle(Paint.Style.FILL);            mPaint.setColor(mColorNormal);
            mErase.setXfermode(PORTER_DUFF_CLEAR);
            if (!isInEditMode()) {
                mPaint.setShadowLayer(mShadowRadius, mShadowXOffset, mShadowYOffset, mShadowColor);            }

            mRadius = getCircleSize() / 2;
            if (mProgressBarEnabled && mShowProgressBackground) {
                mRadius += mProgressWidth;            }
        }

        @Override
        public void draw(Canvas canvas) {
            canvas.drawCircle(calculateCenterX(), calculateCenterY(), mRadius, mPaint);            canvas.drawCircle(calculateCenterX(), calculateCenterY(), mRadius, mErase);        }

        @Override
        public void setAlpha(int alpha) {

        }

        @Override
        public void setColorFilter(ColorFilter cf) {

        }

        @Override
        public int getOpacity() {
            return 0;        }
    }

    static class ProgressSavedState extends BaseSavedState {

        float mCurrentProgress;        float mTargetProgress;        float mSpinSpeed;        int mProgress;        int mProgressWidth;        int mProgressColor;        int mProgressBackgroundColor;        boolean mProgressBarEnabled;        boolean mProgressBarVisibilityChanged;        boolean mProgressIndeterminate;        boolean mShouldProgressIndeterminate;        boolean mShouldSetProgress;        boolean mAnimateProgress;        boolean mShowProgressBackground;
        ProgressSavedState(Parcelable superState) {
            super(superState);        }

        private ProgressSavedState(Parcel in) {
            super(in);            this.mCurrentProgress = in.readFloat();            this.mTargetProgress = in.readFloat();            this.mProgressBarEnabled = in.readInt() != 0;            this.mSpinSpeed = in.readFloat();            this.mProgress = in.readInt();            this.mProgressWidth = in.readInt();            this.mProgressColor = in.readInt();            this.mProgressBackgroundColor = in.readInt();            this.mProgressBarVisibilityChanged = in.readInt() != 0;            this.mProgressIndeterminate = in.readInt() != 0;            this.mShouldProgressIndeterminate = in.readInt() != 0;            this.mShouldSetProgress = in.readInt() != 0;            this.mAnimateProgress = in.readInt() != 0;            this.mShowProgressBackground = in.readInt() != 0;        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);            out.writeFloat(this.mCurrentProgress);            out.writeFloat(this.mTargetProgress);            out.writeInt((mProgressBarEnabled ? 1 : 0));            out.writeFloat(this.mSpinSpeed);            out.writeInt(this.mProgress);            out.writeInt(this.mProgressWidth);            out.writeInt(this.mProgressColor);            out.writeInt(this.mProgressBackgroundColor);            out.writeInt(this.mProgressBarVisibilityChanged ? 1 : 0);            out.writeInt(this.mProgressIndeterminate ? 1 : 0);            out.writeInt(this.mShouldProgressIndeterminate ? 1 : 0);            out.writeInt(this.mShouldSetProgress ? 1 : 0);            out.writeInt(this.mAnimateProgress ? 1 : 0);            out.writeInt(this.mShowProgressBackground ? 1 : 0);        }

        public static final Parcelable.Creator<ProgressSavedState> CREATOR =
                new Parcelable.Creator<ProgressSavedState>() {
                    public ProgressSavedState createFromParcel(Parcel in) {
                        return new ProgressSavedState(in);                    }

                    public ProgressSavedState[] newArray(int size) {
                        return new ProgressSavedState[size];                    }
                };    }

    /* ===== API methods ===== */
    @Override
    public void setImageDrawable(Drawable drawable) {
        if (mIcon != drawable) {
            mIcon = drawable;            updateBackground();        }
    }

    @Override
    public void setImageResource(int resId) {
        Drawable drawable = getResources().getDrawable(resId);        if (mIcon != drawable) {
            mIcon = drawable;            updateBackground();        }
    }

    @Override
    public void setOnClickListener(final OnClickListener l) {
        super.setOnClickListener(l);        mClickListener = l;        View label = (View) getTag(R.id.fab_label);        if (label != null) {
            label.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mClickListener != null) {
                        mClickListener.onClick(FloatingActionButton.this);                    }
                }
            });        }
    }

    /**     * Sets the size of the <b>FloatingActionButton</b> and invalidates its layout.     *     * @param size size of the <b>FloatingActionButton</b>. Accepted values: SIZE_NORMAL, SIZE_MINI.     */    public void setButtonSize(int size) {
        if (size != SIZE_NORMAL && size != SIZE_MINI) {
            throw new IllegalArgumentException("Use @FabSize constants only!");        }

        if (mFabSize != size) {
            mFabSize = size;            updateBackground();        }
    }

    public int getButtonSize() {
        return mFabSize;    }

    public void setColorNormal(int color) {
        if (mColorNormal != color) {
            mColorNormal = color;            updateBackground();        }
    }

    public void setColorNormalResId(int colorResId) {
        setColorNormal(getResources().getColor(colorResId));    }

    public int getColorNormal() {
        return mColorNormal;    }

    public void setColorPressed(int color) {
        if (color != mColorPressed) {
            mColorPressed = color;            updateBackground();        }
    }

    public void setColorPressedResId(int colorResId) {
        setColorPressed(getResources().getColor(colorResId));    }

    public int getColorPressed() {
        return mColorPressed;    }

    public void setColorRipple(int color) {
        if (color != mColorRipple) {
            mColorRipple = color;            updateBackground();        }
    }

    public void setColorRippleResId(int colorResId) {
        setColorRipple(getResources().getColor(colorResId));    }

    public int getColorRipple() {
        return mColorRipple;    }

    public void setColorDisabled(int color) {
        if (color != mColorDisabled) {
            mColorDisabled = color;            updateBackground();        }
    }

    public void setColorDisabledResId(int colorResId) {
        setColorDisabled(getResources().getColor(colorResId));    }

    public int getColorDisabled() {
        return mColorDisabled;    }

    public void setShowShadow(boolean show) {
        if (mShowShadow != show) {
            mShowShadow = show;            updateBackground();        }
    }

    public boolean hasShadow() {
        return !mUsingElevation && mShowShadow;    }

    /**     * Sets the shadow radius of the <b>FloatingActionButton</b> and invalidates its layout.     *     * @param dimenResId the resource identifier of the dimension     */    public void setShadowRadius(int dimenResId) {
        int shadowRadius = getResources().getDimensionPixelSize(dimenResId);        if (mShadowRadius != shadowRadius) {
            mShadowRadius = shadowRadius;            requestLayout();            updateBackground();        }
    }

    /**     * Sets the shadow radius of the <b>FloatingActionButton</b> and invalidates its layout.     * <p>
     * Must be specified in density-independent (dp) pixels, which are then converted into actual     * pixels (px).     *     * @param shadowRadiusDp shadow radius specified in density-independent (dp) pixels     */    public void setShadowRadius(float shadowRadiusDp) {
        mShadowRadius = Util.dpToPx(getContext(), shadowRadiusDp);        requestLayout();        updateBackground();    }

    public int getShadowRadius() {
        return mShadowRadius;    }

    /**     * Sets the shadow x offset of the <b>FloatingActionButton</b> and invalidates its layout.     *     * @param dimenResId the resource identifier of the dimension     */    public void setShadowXOffset(int dimenResId) {
        int shadowXOffset = getResources().getDimensionPixelSize(dimenResId);        if (mShadowXOffset != shadowXOffset) {
            mShadowXOffset = shadowXOffset;            requestLayout();            updateBackground();        }
    }

    /**     * Sets the shadow x offset of the <b>FloatingActionButton</b> and invalidates its layout.     * <p>
     * Must be specified in density-independent (dp) pixels, which are then converted into actual     * pixels (px).     *     * @param shadowXOffsetDp shadow radius specified in density-independent (dp) pixels     */    public void setShadowXOffset(float shadowXOffsetDp) {
        mShadowXOffset = Util.dpToPx(getContext(), shadowXOffsetDp);        requestLayout();        updateBackground();    }

    public int getShadowXOffset() {
        return mShadowXOffset;    }

    /**     * Sets the shadow y offset of the <b>FloatingActionButton</b> and invalidates its layout.     *     * @param dimenResId the resource identifier of the dimension     */    public void setShadowYOffset(int dimenResId) {
        int shadowYOffset = getResources().getDimensionPixelSize(dimenResId);        if (mShadowYOffset != shadowYOffset) {
            mShadowYOffset = shadowYOffset;            requestLayout();            updateBackground();        }
    }

    /**     * Sets the shadow y offset of the <b>FloatingActionButton</b> and invalidates its layout.     * <p>
     * Must be specified in density-independent (dp) pixels, which are then converted into actual     * pixels (px).     *     * @param shadowYOffsetDp shadow radius specified in density-independent (dp) pixels     */    public void setShadowYOffset(float shadowYOffsetDp) {
        mShadowYOffset = Util.dpToPx(getContext(), shadowYOffsetDp);        requestLayout();        updateBackground();    }

    public int getShadowYOffset() {
        return mShadowYOffset;    }

    public void setShadowColorResource(int colorResId) {
        int shadowColor = getResources().getColor(colorResId);        if (mShadowColor != shadowColor) {
            mShadowColor = shadowColor;            updateBackground();        }
    }

    public void setShadowColor(int color) {
        if (mShadowColor != color) {
            mShadowColor = color;            updateBackground();        }
    }

    public int getShadowColor() {
        return mShadowColor;    }

    /**     * Checks whether <b>FloatingActionButton</b> is hidden     *     * @return true if <b>FloatingActionButton</b> is hidden, false otherwise     */    public boolean isHidden() {
        return getVisibility() == INVISIBLE;    }

    /**     * Makes the <b>FloatingActionButton</b> to appear and sets its visibility to {@link #VISIBLE}     *     * @param animate if true - plays "show animation"     */    public void show(boolean animate) {
        if (isHidden()) {
            if (animate) {
                playShowAnimation();            }
            super.setVisibility(VISIBLE);        }
    }

    /**     * Makes the <b>FloatingActionButton</b> to disappear and sets its visibility to {@link #INVISIBLE}     *     * @param animate if true - plays "hide animation"     */    public void hide(boolean animate) {
        if (!isHidden()) {
            if (animate) {
                playHideAnimation();            }
            super.setVisibility(INVISIBLE);        }
    }

    public void toggle(boolean animate) {
        if (isHidden()) {
            show(animate);        } else {
            hide(animate);        }
    }

    public void setLabelText(String text) {
        mLabelText = text;        TextView labelView = getLabelView();        if (labelView != null) {
            labelView.setText(text);        }
    }

    public String getLabelText() {
        return mLabelText;    }

    public void setShowAnimation(Animation showAnimation) {
        mShowAnimation = showAnimation;    }

    public void setHideAnimation(Animation hideAnimation) {
        mHideAnimation = hideAnimation;    }

    public void setLabelVisibility(int visibility) {
        Label labelView = getLabelView();        if (labelView != null) {
            labelView.setVisibility(visibility);            labelView.setHandleVisibilityChanges(visibility == VISIBLE);        }
    }

    public int getLabelVisibility() {
        TextView labelView = getLabelView();        if (labelView != null) {
            return labelView.getVisibility();        }

        return -1;    }

    @Override
    public void setElevation(float elevation) {
        if (Util.hasLollipop() && elevation > 0) {
            super.setElevation(elevation);            if (!isInEditMode()) {
                mUsingElevation = true;                mShowShadow = false;            }
            updateBackground();        }
    }

    /**     * Sets the shadow color and radius to mimic the native elevation.     *     * <p><b>API 21+</b>: Sets the native elevation of this view, in pixels. Updates margins to     * make the view hold its position in layout across different platform versions.</p>
     */    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void setElevationCompat(float elevation) {
        mShadowColor = 0x26000000;        mShadowRadius = Math.round(elevation / 2);        mShadowXOffset = 0;        mShadowYOffset = Math.round(mFabSize == SIZE_NORMAL ? elevation : elevation / 2);
        if (Util.hasLollipop()) {
            super.setElevation(elevation);            mUsingElevationCompat = true;            mShowShadow = false;            updateBackground();
            ViewGroup.LayoutParams layoutParams = getLayoutParams();            if (layoutParams != null) {
                setLayoutParams(layoutParams);            }
        } else {
            mShowShadow = true;            updateBackground();        }
    }

    /**     * <p>Change the indeterminate mode for the progress bar. In indeterminate     * mode, the progress is ignored and the progress bar shows an infinite     * animation instead.</p>
     *     * @param indeterminate true to enable the indeterminate mode     */    public synchronized void setIndeterminate(boolean indeterminate) {
        if (!indeterminate) {
            mCurrentProgress = 0.0f;        }

        mProgressBarEnabled = indeterminate;        mShouldUpdateButtonPosition = true;        mProgressIndeterminate = indeterminate;        mLastTimeAnimated = SystemClock.uptimeMillis();        setupProgressBounds();//        saveButtonOriginalPosition();        updateBackground();    }

    public synchronized void setMax(int max) {
        mProgressMax = max;    }

    public synchronized int getMax() {
        return mProgressMax;    }

    public synchronized void setProgress(int progress, boolean animate) {
        if (mProgressIndeterminate) return;
        mProgress = progress;        mAnimateProgress = animate;
        if (!mButtonPositionSaved) {
            mShouldSetProgress = true;            return;        }

        mProgressBarEnabled = true;        mShouldUpdateButtonPosition = true;        setupProgressBounds();        saveButtonOriginalPosition();        updateBackground();
        if (progress < 0) {
            progress = 0;        } else if (progress > mProgressMax) {
            progress = mProgressMax;        }

        if (progress == mTargetProgress) {
            return;        }

        mTargetProgress = mProgressMax > 0 ? (progress / (float) mProgressMax) * 360 : 0;        mLastTimeAnimated = SystemClock.uptimeMillis();
        if (!animate) {
            mCurrentProgress = mTargetProgress;        }

        invalidate();    }

    public synchronized int getProgress() {
        return mProgressIndeterminate ? 0 : mProgress;    }

    public synchronized void hideProgress() {
        mProgressBarEnabled = false;        mShouldUpdateButtonPosition = true;        updateBackground();    }

    public synchronized void setShowProgressBackground(boolean show) {
        mShowProgressBackground = show;    }

    public synchronized boolean isProgressBackgroundShown() {
        return mShowProgressBackground;    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);        Label label = (Label) getTag(R.id.fab_label);        if (label != null) {
            label.setEnabled(enabled);        }
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);        Label label = (Label) getTag(R.id.fab_label);        if (label != null) {
            label.setVisibility(visibility);        }
    }

    /**     * <b>This will clear all AnimationListeners.</b>
     */    public void hideButtonInMenu(boolean animate) {
        if (!isHidden() && getVisibility() != GONE) {
            hide(animate);
            Label label = getLabelView();            if (label != null) {
                label.hide(animate);            }

            getHideAnimation().setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    setVisibility(GONE);                    getHideAnimation().setAnimationListener(null);                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });        }
    }

    public void showButtonInMenu(boolean animate) {
        if (getVisibility() == VISIBLE) return;
        setVisibility(INVISIBLE);        show(animate);        Label label = getLabelView();        if (label != null) {
            label.show(animate);        }
    }

    /**     * Set the label's background colors     */    public void setLabelColors(int colorNormal, int colorPressed, int colorRipple) {
        Label label = getLabelView();
        int left = label.getPaddingLeft();        int top = label.getPaddingTop();        int right = label.getPaddingRight();        int bottom = label.getPaddingBottom();
        label.setColors(colorNormal, colorPressed, colorRipple);        label.updateBackground();        label.setPadding(left, top, right, bottom);    }

    public void setLabelTextColor(int color) {
        getLabelView().setTextColor(color);    }

    public void setLabelTextColor(ColorStateList colors) {
        getLabelView().setTextColor(colors);    }
}
2)FloatingActionMenu.java
=========================
package com.eppico.fabmenu;
import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.ColorStateList;import android.content.res.TypedArray;import android.graphics.Color;import android.graphics.Typeface;import android.graphics.drawable.Drawable;import android.os.Handler;import android.text.TextUtils;import android.util.AttributeSet;import android.util.TypedValue;import android.view.ContextThemeWrapper;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.view.animation.AnticipateInterpolator;import android.view.animation.Interpolator;import android.view.animation.OvershootInterpolator;import android.widget.ImageView;
import com.eppico.R;
import java.util.ArrayList;import java.util.List;
public class FloatingActionMenu extends ViewGroup {

    private static final int ANIMATION_DURATION = 300;    private static final float CLOSED_PLUS_ROTATION = 0f;    private static final float OPENED_PLUS_ROTATION_LEFT = -90f - 45f;    private static final float OPENED_PLUS_ROTATION_RIGHT = 90f + 45f;
    private static final int OPEN_UP = 0;    private static final int OPEN_DOWN = 1;
    private static final int LABELS_POSITION_LEFT = 0;    private static final int LABELS_POSITION_RIGHT = 1;
    private AnimatorSet mOpenAnimatorSet = new AnimatorSet();    private AnimatorSet mCloseAnimatorSet = new AnimatorSet();    private AnimatorSet mIconToggleSet;
    private int mButtonSpacing = Util.dpToPx(getContext(), 0f);    private FloatingActionButton mMenuButton;    private int mMaxButtonWidth;    private int mLabelsMargin = Util.dpToPx(getContext(), 0f);    private int mLabelsVerticalOffset = Util.dpToPx(getContext(), 0f);    private int mButtonsCount;    private boolean mMenuOpened;    private boolean mIsMenuOpening;    private Handler mUiHandler = new Handler();    private int mLabelsShowAnimation;    private int mLabelsHideAnimation;    private int mLabelsPaddingTop = Util.dpToPx(getContext(), 4f);    private int mLabelsPaddingRight = Util.dpToPx(getContext(), 8f);    private int mLabelsPaddingBottom = Util.dpToPx(getContext(), 4f);    private int mLabelsPaddingLeft = Util.dpToPx(getContext(), 8f);    private ColorStateList mLabelsTextColor;    private float mLabelsTextSize;    private int mLabelsCornerRadius = Util.dpToPx(getContext(), 3f);    private boolean mLabelsShowShadow;    private int mLabelsColorNormal;    private int mLabelsColorPressed;    private int mLabelsColorRipple;    private boolean mMenuShowShadow;    private int mMenuShadowColor;    private float mMenuShadowRadius = 4f;    private float mMenuShadowXOffset = 1f;    private float mMenuShadowYOffset = 3f;    private int mMenuColorNormal;    private int mMenuColorPressed;    private int mMenuColorRipple;    private Drawable mIcon;    private int mAnimationDelayPerItem;    private Interpolator mOpenInterpolator;    private Interpolator mCloseInterpolator;    private boolean mIsAnimated = true;    private boolean mLabelsSingleLine;    private int mLabelsEllipsize;    private int mLabelsMaxLines;    private int mMenuFabSize;    private int mLabelsStyle;    private Typeface mCustomTypefaceFromFont;    private boolean mIconAnimated = true;    private ImageView mImageToggle;    private Animation mMenuButtonShowAnimation;    private Animation mMenuButtonHideAnimation;    private Animation mImageToggleShowAnimation;    private Animation mImageToggleHideAnimation;    private boolean mIsMenuButtonAnimationRunning;    private boolean mIsSetClosedOnTouchOutside;    private int mOpenDirection;    private OnMenuToggleListener mToggleListener;
    private ValueAnimator mShowBackgroundAnimator;    private ValueAnimator mHideBackgroundAnimator;    private int mBackgroundColor;
    private int mLabelsPosition;    private Context mLabelsContext;    private String mMenuLabelText;    private boolean mUsingMenuLabel;
    public interface OnMenuToggleListener {
        void onMenuToggle(boolean opened);    }

    public FloatingActionMenu(Context context) {
        this(context, null);    }

    public FloatingActionMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);    }

    public FloatingActionMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);        init(context, attrs);    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingActionMenu, 0, 0);        mButtonSpacing = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_buttonSpacing, mButtonSpacing);        mLabelsMargin = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_margin, mLabelsMargin);        mLabelsPosition = attr.getInt(R.styleable.FloatingActionMenu_menu_labels_position, LABELS_POSITION_LEFT);        mLabelsShowAnimation = attr.getResourceId(R.styleable.FloatingActionMenu_menu_labels_showAnimation,                mLabelsPosition == LABELS_POSITION_LEFT ? R.anim.fab_slide_in_from_right : R.anim.fab_slide_in_from_left);        mLabelsHideAnimation = attr.getResourceId(R.styleable.FloatingActionMenu_menu_labels_hideAnimation,                mLabelsPosition == LABELS_POSITION_LEFT ? R.anim.fab_slide_out_to_right : R.anim.fab_slide_out_to_left);        mLabelsPaddingTop = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingTop, mLabelsPaddingTop);        mLabelsPaddingRight = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingRight, mLabelsPaddingRight);        mLabelsPaddingBottom = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingBottom, mLabelsPaddingBottom);        mLabelsPaddingLeft = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingLeft, mLabelsPaddingLeft);        mLabelsTextColor = attr.getColorStateList(R.styleable.FloatingActionMenu_menu_labels_textColor);        // set default value if null same as for textview        if (mLabelsTextColor == null) {
            mLabelsTextColor = ColorStateList.valueOf(Color.WHITE);        }
        mLabelsTextSize = attr.getDimension(R.styleable.FloatingActionMenu_menu_labels_textSize, getResources().getDimension(R.dimen.labels_text_size));        mLabelsCornerRadius = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_cornerRadius, mLabelsCornerRadius);        mLabelsShowShadow = attr.getBoolean(R.styleable.FloatingActionMenu_menu_labels_showShadow, true);        mLabelsColorNormal = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_colorNormal, 0xFF333333);        mLabelsColorPressed = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_colorPressed, 0xFF444444);        mLabelsColorRipple = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_colorRipple, 0x66FFFFFF);        mMenuShowShadow = attr.getBoolean(R.styleable.FloatingActionMenu_menu_showShadow, true);        mMenuShadowColor = attr.getColor(R.styleable.FloatingActionMenu_menu_shadowColor, 0x66000000);        mMenuShadowRadius = attr.getDimension(R.styleable.FloatingActionMenu_menu_shadowRadius, mMenuShadowRadius);        mMenuShadowXOffset = attr.getDimension(R.styleable.FloatingActionMenu_menu_shadowXOffset, mMenuShadowXOffset);        mMenuShadowYOffset = attr.getDimension(R.styleable.FloatingActionMenu_menu_shadowYOffset, mMenuShadowYOffset);        mMenuColorNormal = attr.getColor(R.styleable.FloatingActionMenu_menu_colorNormal, 0xFFDA4336);        mMenuColorPressed = attr.getColor(R.styleable.FloatingActionMenu_menu_colorPressed, 0xFFE75043);        mMenuColorRipple = attr.getColor(R.styleable.FloatingActionMenu_menu_colorRipple, 0x99FFFFFF);        mAnimationDelayPerItem = attr.getInt(R.styleable.FloatingActionMenu_menu_animationDelayPerItem, 50);        mIcon = attr.getDrawable(R.styleable.FloatingActionMenu_menu_icon);        if (mIcon == null) {
            mIcon = getResources().getDrawable(R.mipmap.ic_add);        }
        mLabelsSingleLine = attr.getBoolean(R.styleable.FloatingActionMenu_menu_labels_singleLine, false);        mLabelsEllipsize = attr.getInt(R.styleable.FloatingActionMenu_menu_labels_ellipsize, 0);        mLabelsMaxLines = attr.getInt(R.styleable.FloatingActionMenu_menu_labels_maxLines, -1);        mMenuFabSize = attr.getInt(R.styleable.FloatingActionMenu_menu_fab_size, FloatingActionButton.SIZE_NORMAL);        mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionMenu_menu_labels_style, 0);        String customFont = attr.getString(R.styleable.FloatingActionMenu_menu_labels_customFont);        try {
            if (!TextUtils.isEmpty(customFont)) {
                mCustomTypefaceFromFont = Typeface.createFromAsset(getContext().getAssets(), customFont);            }
        } catch (RuntimeException ex) {
            throw new IllegalArgumentException("Unable to load specified custom font: " + customFont, ex);        }
        mOpenDirection = attr.getInt(R.styleable.FloatingActionMenu_menu_openDirection, OPEN_UP);        mBackgroundColor = attr.getColor(R.styleable.FloatingActionMenu_menu_backgroundColor, Color.TRANSPARENT);
        if (attr.hasValue(R.styleable.FloatingActionMenu_menu_fab_label)) {
            mUsingMenuLabel = true;            mMenuLabelText = attr.getString(R.styleable.FloatingActionMenu_menu_fab_label);        }

        if (attr.hasValue(R.styleable.FloatingActionMenu_menu_labels_padding)) {
            int padding = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_padding, 0);            initPadding(padding);        }

        mOpenInterpolator = new OvershootInterpolator();        mCloseInterpolator = new AnticipateInterpolator();        mLabelsContext = new ContextThemeWrapper(getContext(), mLabelsStyle);
        initBackgroundDimAnimation();        createMenuButton();        initMenuButtonAnimations(attr);
        attr.recycle();    }

    private void initMenuButtonAnimations(TypedArray attr) {
        int showResId = attr.getResourceId(R.styleable.FloatingActionMenu_menu_fab_show_animation, R.anim.fab_scale_up);        setMenuButtonShowAnimation(AnimationUtils.loadAnimation(getContext(), showResId));        mImageToggleShowAnimation = AnimationUtils.loadAnimation(getContext(), showResId);
        int hideResId = attr.getResourceId(R.styleable.FloatingActionMenu_menu_fab_hide_animation, R.anim.fab_scale_down);        setMenuButtonHideAnimation(AnimationUtils.loadAnimation(getContext(), hideResId));        mImageToggleHideAnimation = AnimationUtils.loadAnimation(getContext(), hideResId);    }

    private void initBackgroundDimAnimation() {
        final int maxAlpha = Color.alpha(mBackgroundColor);        final int red = Color.red(mBackgroundColor);        final int green = Color.green(mBackgroundColor);        final int blue = Color.blue(mBackgroundColor);
        mShowBackgroundAnimator = ValueAnimator.ofInt(0, maxAlpha);        mShowBackgroundAnimator.setDuration(ANIMATION_DURATION);        mShowBackgroundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer alpha = (Integer) animation.getAnimatedValue();                setBackgroundColor(Color.argb(alpha, red, green, blue));            }
        });
        mHideBackgroundAnimator = ValueAnimator.ofInt(maxAlpha, 0);        mHideBackgroundAnimator.setDuration(ANIMATION_DURATION);        mHideBackgroundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer alpha = (Integer) animation.getAnimatedValue();                setBackgroundColor(Color.argb(alpha, red, green, blue));            }
        });    }

    private boolean isBackgroundEnabled() {
        return mBackgroundColor != Color.TRANSPARENT;    }

    private void initPadding(int padding) {
        mLabelsPaddingTop = padding;        mLabelsPaddingRight = padding;        mLabelsPaddingBottom = padding;        mLabelsPaddingLeft = padding;    }

    private void createMenuButton() {
        mMenuButton = new FloatingActionButton(getContext());
        mMenuButton.mShowShadow = mMenuShowShadow;        if (mMenuShowShadow) {
            mMenuButton.mShadowRadius = Util.dpToPx(getContext(), mMenuShadowRadius);            mMenuButton.mShadowXOffset = Util.dpToPx(getContext(), mMenuShadowXOffset);            mMenuButton.mShadowYOffset = Util.dpToPx(getContext(), mMenuShadowYOffset);        }
        mMenuButton.setColors(mMenuColorNormal, mMenuColorPressed, mMenuColorRipple);        mMenuButton.mShadowColor = mMenuShadowColor;        mMenuButton.mFabSize = mMenuFabSize;        mMenuButton.updateBackground();        mMenuButton.setLabelText(mMenuLabelText);
        mImageToggle = new ImageView(getContext());        mImageToggle.setImageDrawable(mIcon);
        addView(mMenuButton, super.generateDefaultLayoutParams());        addView(mImageToggle);
        createDefaultIconAnimation();    }

    private void createDefaultIconAnimation() {
        float collapseAngle;        float expandAngle;        if (mOpenDirection == OPEN_UP) {
            collapseAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_LEFT : OPENED_PLUS_ROTATION_RIGHT;            expandAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_LEFT : OPENED_PLUS_ROTATION_RIGHT;        } else {
            collapseAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_RIGHT : OPENED_PLUS_ROTATION_LEFT;            expandAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_RIGHT : OPENED_PLUS_ROTATION_LEFT;        }

        ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(
                mImageToggle,                "rotation",                collapseAngle,                CLOSED_PLUS_ROTATION
        );
        ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(
                mImageToggle,                "rotation",                CLOSED_PLUS_ROTATION,                expandAngle
        );
        mOpenAnimatorSet.play(expandAnimator);        mCloseAnimatorSet.play(collapseAnimator);
        mOpenAnimatorSet.setInterpolator(mOpenInterpolator);        mCloseAnimatorSet.setInterpolator(mCloseInterpolator);
        mOpenAnimatorSet.setDuration(ANIMATION_DURATION);        mCloseAnimatorSet.setDuration(ANIMATION_DURATION);    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = 0;        int height = 0;        mMaxButtonWidth = 0;        int maxLabelWidth = 0;
        measureChildWithMargins(mImageToggle, widthMeasureSpec, 0, heightMeasureSpec, 0);
        for (int i = 0; i < mButtonsCount; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE || child == mImageToggle) continue;
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);            mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());        }

        for (int i = 0; i < mButtonsCount; i++) {
            int usedWidth = 0;            View child = getChildAt(i);
            if (child.getVisibility() == GONE || child == mImageToggle) continue;
            usedWidth += child.getMeasuredWidth();            height += child.getMeasuredHeight();
            Label label = (Label) child.getTag(R.id.fab_label);            if (label != null) {
                int labelOffset = (mMaxButtonWidth - child.getMeasuredWidth()) / (mUsingMenuLabel ? 1 : 2);                int labelUsedWidth = child.getMeasuredWidth() + label.calculateShadowWidth() + mLabelsMargin + labelOffset;                measureChildWithMargins(label, widthMeasureSpec, labelUsedWidth, heightMeasureSpec, 0);                usedWidth += label.getMeasuredWidth();                maxLabelWidth = Math.max(maxLabelWidth, usedWidth + labelOffset);            }
        }

        width = Math.max(mMaxButtonWidth, maxLabelWidth + mLabelsMargin) + getPaddingLeft() + getPaddingRight();
        height += mButtonSpacing * (mButtonsCount - 1) + getPaddingTop() + getPaddingBottom();        height = adjustForOvershoot(height);
        if (getLayoutParams().width == LayoutParams.MATCH_PARENT) {
            width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);        }

        if (getLayoutParams().height == LayoutParams.MATCH_PARENT) {
            height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);        }

        setMeasuredDimension(width, height);    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int buttonsHorizontalCenter = mLabelsPosition == LABELS_POSITION_LEFT
                ? r - l - mMaxButtonWidth / 2 - getPaddingRight()
                : mMaxButtonWidth / 2 + getPaddingLeft();        boolean openUp = mOpenDirection == OPEN_UP;
        int menuButtonTop = openUp
                ? b - t - mMenuButton.getMeasuredHeight() - getPaddingBottom()
                : getPaddingTop();        int menuButtonLeft = buttonsHorizontalCenter - mMenuButton.getMeasuredWidth() / 2;
        mMenuButton.layout(menuButtonLeft, menuButtonTop, menuButtonLeft + mMenuButton.getMeasuredWidth(),                menuButtonTop + mMenuButton.getMeasuredHeight());
        int imageLeft = buttonsHorizontalCenter - mImageToggle.getMeasuredWidth() / 2;        int imageTop = menuButtonTop + mMenuButton.getMeasuredHeight() / 2 - mImageToggle.getMeasuredHeight() / 2;
        mImageToggle.layout(imageLeft, imageTop, imageLeft + mImageToggle.getMeasuredWidth(),                imageTop + mImageToggle.getMeasuredHeight());
        int nextY = openUp
                ? menuButtonTop + mMenuButton.getMeasuredHeight() + mButtonSpacing
                : menuButtonTop;
        for (int i = mButtonsCount - 1; i >= 0; i--) {
            View child = getChildAt(i);
            if (child == mImageToggle) continue;
            FloatingActionButton fab = (FloatingActionButton) child;
            if (fab.getVisibility() == GONE) continue;
            int childX = buttonsHorizontalCenter - fab.getMeasuredWidth() / 2;            int childY = openUp ? nextY - fab.getMeasuredHeight() - mButtonSpacing : nextY;
            if (fab != mMenuButton) {
                fab.layout(childX, childY, childX + fab.getMeasuredWidth(),                        childY + fab.getMeasuredHeight());
                if (!mIsMenuOpening) {
                    fab.hide(false);                }
            }

            View label = (View) fab.getTag(R.id.fab_label);            if (label != null) {
                int labelsOffset = (mUsingMenuLabel ? mMaxButtonWidth / 2 : fab.getMeasuredWidth() / 2) + mLabelsMargin;                int labelXNearButton = mLabelsPosition == LABELS_POSITION_LEFT
                        ? buttonsHorizontalCenter - labelsOffset
                        : buttonsHorizontalCenter + labelsOffset;
                int labelXAwayFromButton = mLabelsPosition == LABELS_POSITION_LEFT
                        ? labelXNearButton - label.getMeasuredWidth()
                        : labelXNearButton + label.getMeasuredWidth();
                int labelLeft = mLabelsPosition == LABELS_POSITION_LEFT
                        ? labelXAwayFromButton
                        : labelXNearButton;
                int labelRight = mLabelsPosition == LABELS_POSITION_LEFT
                        ? labelXNearButton
                        : labelXAwayFromButton;
                int labelTop = childY - mLabelsVerticalOffset + (fab.getMeasuredHeight()
                        - label.getMeasuredHeight()) / 2;
                label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight());
                if (!mIsMenuOpening) {
                    label.setVisibility(INVISIBLE);                }
            }

            nextY = openUp
                    ? childY - mButtonSpacing
                    : childY + child.getMeasuredHeight() + mButtonSpacing;        }
    }

    private int adjustForOvershoot(int dimension) {
        return (int) (dimension * 0.03 + dimension);    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();        bringChildToFront(mMenuButton);        bringChildToFront(mImageToggle);        mButtonsCount = getChildCount();        createLabels();    }

    private void createLabels() {
        for (int i = 0; i < mButtonsCount; i++) {

            if (getChildAt(i) == mImageToggle) continue;
            final FloatingActionButton fab = (FloatingActionButton) getChildAt(i);
            if (fab.getTag(R.id.fab_label) != null) continue;
            addLabel(fab);
            if (fab == mMenuButton) {
                mMenuButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        toggle(mIsAnimated);                    }
                });            }
        }
    }

    private void addLabel(FloatingActionButton fab) {
        String text = fab.getLabelText();
        if (TextUtils.isEmpty(text)) return;
        final Label label = new Label(mLabelsContext);        label.setClickable(true);        label.setFab(fab);        label.setShowAnimation(AnimationUtils.loadAnimation(getContext(), mLabelsShowAnimation));        label.setHideAnimation(AnimationUtils.loadAnimation(getContext(), mLabelsHideAnimation));
        if (mLabelsStyle > 0) {
            label.setTextAppearance(getContext(), mLabelsStyle);            label.setShowShadow(false);            label.setUsingStyle(true);        } else {
            label.setColors(mLabelsColorNormal, mLabelsColorPressed, mLabelsColorRipple);            label.setShowShadow(mLabelsShowShadow);            label.setCornerRadius(mLabelsCornerRadius);            if (mLabelsEllipsize > 0) {
                setLabelEllipsize(label);            }
            label.setMaxLines(mLabelsMaxLines);            label.updateBackground();
            label.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLabelsTextSize);            label.setTextColor(mLabelsTextColor);
            int left = mLabelsPaddingLeft;            int top = mLabelsPaddingTop;            if (mLabelsShowShadow) {
                left += fab.getShadowRadius() + Math.abs(fab.getShadowXOffset());                top += fab.getShadowRadius() + Math.abs(fab.getShadowYOffset());            }

            label.setPadding(
                    left,                    top,                    mLabelsPaddingLeft,                    mLabelsPaddingTop
            );
            if (mLabelsMaxLines < 0 || mLabelsSingleLine) {
                label.setSingleLine(mLabelsSingleLine);            }
        }

        if (mCustomTypefaceFromFont != null) {
            label.setTypeface(mCustomTypefaceFromFont);        }
        label.setText(text);        label.setOnClickListener(fab.getOnClickListener());
        addView(label);        fab.setTag(R.id.fab_label, label);    }

    private void setLabelEllipsize(Label label) {
        switch (mLabelsEllipsize) {
            case 1:
                label.setEllipsize(TextUtils.TruncateAt.START);                break;            case 2:
                label.setEllipsize(TextUtils.TruncateAt.MIDDLE);                break;            case 3:
                label.setEllipsize(TextUtils.TruncateAt.END);                break;            case 4:
                label.setEllipsize(TextUtils.TruncateAt.MARQUEE);                break;        }
    }

    @Override
    public MarginLayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);    }

    @Override
    protected MarginLayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);    }

    @Override
    protected MarginLayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT,                MarginLayoutParams.WRAP_CONTENT);    }

    @Override
    protected boolean checkLayoutParams(LayoutParams p) {
        return p instanceof MarginLayoutParams;    }

    private void hideMenuButtonWithImage(boolean animate) {
        if (!isMenuButtonHidden()) {
            mMenuButton.hide(animate);            if (animate) {
                mImageToggle.startAnimation(mImageToggleHideAnimation);            }
            mImageToggle.setVisibility(INVISIBLE);            mIsMenuButtonAnimationRunning = false;        }
    }

    private void showMenuButtonWithImage(boolean animate) {
        if (isMenuButtonHidden()) {
            mMenuButton.show(animate);            if (animate) {
                mImageToggle.startAnimation(mImageToggleShowAnimation);            }
            mImageToggle.setVisibility(VISIBLE);        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mIsSetClosedOnTouchOutside) {
            boolean handled = false;            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    handled = isOpened();                    break;                case MotionEvent.ACTION_UP:
                    close(mIsAnimated);                    handled = true;            }

            return handled;        }

        return super.onTouchEvent(event);    }

    /* ===== API methods ===== */
    public boolean isOpened() {
        return mMenuOpened;    }

    public void toggle(boolean animate) {
        if (isOpened()) {
            close(animate);        } else {
            open(animate);        }
    }

    public void open(final boolean animate) {
        if (!isOpened()) {
            if (isBackgroundEnabled()) {
                mShowBackgroundAnimator.start();            }

            if (mIconAnimated) {
                if (mIconToggleSet != null) {
                    mIconToggleSet.start();                } else {
                    mCloseAnimatorSet.cancel();                    mOpenAnimatorSet.start();                }
            }

            int delay = 0;            int counter = 0;            mIsMenuOpening = true;            for (int i = getChildCount() - 1; i >= 0; i--) {
                View child = getChildAt(i);                if (child instanceof FloatingActionButton && child.getVisibility() != GONE) {
                    counter++;
                    final FloatingActionButton fab = (FloatingActionButton) child;                    mUiHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (isOpened()) return;
                            if (fab != mMenuButton) {
                                fab.show(animate);                            }

                            Label label = (Label) fab.getTag(R.id.fab_label);                            if (label != null && label.isHandleVisibilityChanges()) {
                                label.show(animate);                            }
                        }
                    }, delay);                    delay += mAnimationDelayPerItem;                }
            }

            mUiHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mMenuOpened = true;
                    if (mToggleListener != null) {
                        mToggleListener.onMenuToggle(true);                    }
                }
            }, ++counter * mAnimationDelayPerItem);        }
    }

    public void close(final boolean animate) {
        if (isOpened()) {
            if (isBackgroundEnabled()) {
                mHideBackgroundAnimator.start();            }

            if (mIconAnimated) {
                if (mIconToggleSet != null) {
                    mIconToggleSet.start();                } else {
                    mCloseAnimatorSet.start();                    mOpenAnimatorSet.cancel();                }
            }

            int delay = 0;            int counter = 0;            mIsMenuOpening = false;            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);                if (child instanceof FloatingActionButton && child.getVisibility() != GONE) {
                    counter++;
                    final FloatingActionButton fab = (FloatingActionButton) child;                    mUiHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (!isOpened()) return;
                            if (fab != mMenuButton) {
                                fab.hide(animate);                            }

                            Label label = (Label) fab.getTag(R.id.fab_label);                            if (label != null && label.isHandleVisibilityChanges()) {
                                label.hide(animate);                            }
                        }
                    }, delay);                    delay += mAnimationDelayPerItem;                }
            }

            mUiHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mMenuOpened = false;
                    if (mToggleListener != null) {
                        mToggleListener.onMenuToggle(false);                    }
                }
            }, ++counter * mAnimationDelayPerItem);        }
    }

    /**     * Sets the {@link android.view.animation.Interpolator} for <b>FloatingActionButton's</b> icon animation.     *     * @param interpolator the Interpolator to be used in animation     */    public void setIconAnimationInterpolator(Interpolator interpolator) {
        mOpenAnimatorSet.setInterpolator(interpolator);        mCloseAnimatorSet.setInterpolator(interpolator);    }

    public void setIconAnimationOpenInterpolator(Interpolator openInterpolator) {
        mOpenAnimatorSet.setInterpolator(openInterpolator);    }

    public void setIconAnimationCloseInterpolator(Interpolator closeInterpolator) {
        mCloseAnimatorSet.setInterpolator(closeInterpolator);    }

    /**     * Sets whether open and close actions should be animated     *     * @param animated if <b>false</b> - menu items will appear/disappear instantly without any animation     */    public void setAnimated(boolean animated) {
        mIsAnimated = animated;        mOpenAnimatorSet.setDuration(animated ? ANIMATION_DURATION : 0);        mCloseAnimatorSet.setDuration(animated ? ANIMATION_DURATION : 0);    }

    public boolean isAnimated() {
        return mIsAnimated;    }

    public void setAnimationDelayPerItem(int animationDelayPerItem) {
        mAnimationDelayPerItem = animationDelayPerItem;    }

    public int getAnimationDelayPerItem() {
        return mAnimationDelayPerItem;    }

    public void setOnMenuToggleListener(OnMenuToggleListener listener) {
        mToggleListener = listener;    }

    public void setIconAnimated(boolean animated) {
        mIconAnimated = animated;    }

    public boolean isIconAnimated() {
        return mIconAnimated;    }

    public ImageView getMenuIconView() {
        return mImageToggle;    }

    public void setIconToggleAnimatorSet(AnimatorSet toggleAnimatorSet) {
        mIconToggleSet = toggleAnimatorSet;    }

    public AnimatorSet getIconToggleAnimatorSet() {
        return mIconToggleSet;    }

    public void setMenuButtonShowAnimation(Animation showAnimation) {
        mMenuButtonShowAnimation = showAnimation;        mMenuButton.setShowAnimation(showAnimation);    }

    public void setMenuButtonHideAnimation(Animation hideAnimation) {
        mMenuButtonHideAnimation = hideAnimation;        mMenuButton.setHideAnimation(hideAnimation);    }

    public boolean isMenuHidden() {
        return getVisibility() == INVISIBLE;    }

    public boolean isMenuButtonHidden() {
        return mMenuButton.isHidden();    }

    /**     * Makes the whole {@link #FloatingActionMenu} to appear and sets its visibility to {@link #VISIBLE}     *     * @param animate if true - plays "show animation"     */    public void showMenu(boolean animate) {
        if (isMenuHidden()) {
            if (animate) {
                startAnimation(mMenuButtonShowAnimation);            }
            setVisibility(VISIBLE);        }
    }

    /**     * Makes the {@link #FloatingActionMenu} to disappear and sets its visibility to {@link #INVISIBLE}     *     * @param animate if true - plays "hide animation"     */    public void hideMenu(final boolean animate) {
        if (!isMenuHidden() && !mIsMenuButtonAnimationRunning) {
            mIsMenuButtonAnimationRunning = true;            if (isOpened()) {
                close(animate);                mUiHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (animate) {
                            startAnimation(mMenuButtonHideAnimation);                        }
                        setVisibility(INVISIBLE);                        mIsMenuButtonAnimationRunning = false;                    }
                }, mAnimationDelayPerItem * mButtonsCount);            } else {
                if (animate) {
                    startAnimation(mMenuButtonHideAnimation);                }
                setVisibility(INVISIBLE);                mIsMenuButtonAnimationRunning = false;            }
        }
    }

    public void toggleMenu(boolean animate) {
        if (isMenuHidden()) {
            showMenu(animate);        } else {
            hideMenu(animate);        }
    }

    /**     * Makes the {@link FloatingActionButton} to appear inside the {@link #FloatingActionMenu} and     * sets its visibility to {@link #VISIBLE}     *     * @param animate if true - plays "show animation"     */    public void showMenuButton(boolean animate) {
        if (isMenuButtonHidden()) {
            showMenuButtonWithImage(animate);        }
    }

    /**     * Makes the {@link FloatingActionButton} to disappear inside the {@link #FloatingActionMenu} and     * sets its visibility to {@link #INVISIBLE}     *     * @param animate if true - plays "hide animation"     */    public void hideMenuButton(final boolean animate) {
        if (!isMenuButtonHidden() && !mIsMenuButtonAnimationRunning) {
            mIsMenuButtonAnimationRunning = true;            if (isOpened()) {
                close(animate);                mUiHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        hideMenuButtonWithImage(animate);                    }
                }, mAnimationDelayPerItem * mButtonsCount);            } else {
                hideMenuButtonWithImage(animate);            }
        }
    }

    public void toggleMenuButton(boolean animate) {
        if (isMenuButtonHidden()) {
            showMenuButton(animate);        } else {
            hideMenuButton(animate);        }
    }

    public void setClosedOnTouchOutside(boolean close) {
        mIsSetClosedOnTouchOutside = close;    }

    public void setMenuButtonColorNormal(int color) {
        mMenuColorNormal = color;        mMenuButton.setColorNormal(color);    }

    public void setMenuButtonColorNormalResId(int colorResId) {
        mMenuColorNormal = getResources().getColor(colorResId);        mMenuButton.setColorNormalResId(colorResId);    }

    public int getMenuButtonColorNormal() {
        return mMenuColorNormal;    }

    public void setMenuButtonColorPressed(int color) {
        mMenuColorPressed = color;        mMenuButton.setColorPressed(color);    }

    public void setMenuButtonColorPressedResId(int colorResId) {
        mMenuColorPressed = getResources().getColor(colorResId);        mMenuButton.setColorPressedResId(colorResId);    }

    public int getMenuButtonColorPressed() {
        return mMenuColorPressed;    }

    public void setMenuButtonColorRipple(int color) {
        mMenuColorRipple = color;        mMenuButton.setColorRipple(color);    }

    public void setMenuButtonColorRippleResId(int colorResId) {
        mMenuColorRipple = getResources().getColor(colorResId);        mMenuButton.setColorRippleResId(colorResId);    }

    public int getMenuButtonColorRipple() {
        return mMenuColorRipple;    }

    public void addMenuButton(FloatingActionButton fab) {
        addView(fab, mButtonsCount - 2);        mButtonsCount++;        addLabel(fab);    }

    public void removeMenuButton(FloatingActionButton fab) {
        removeView(fab.getLabelView());        removeView(fab);        mButtonsCount--;    }

    public void addMenuButton(FloatingActionButton fab, int index) {
        int size = mButtonsCount - 2;        if (index < 0) {
            index = 0;        } else if (index > size) {
            index = size;        }

        addView(fab, index);        mButtonsCount++;        addLabel(fab);    }

    public void removeAllMenuButtons() {
        close(true);                List<FloatingActionButton> viewsToRemove = new ArrayList<>();        for (int i = 0; i < getChildCount(); i++) {
            View v = getChildAt(i);            if (v != mMenuButton && v != mImageToggle && v instanceof FloatingActionButton) {
                viewsToRemove.add((FloatingActionButton) v);            }
        }
        for (FloatingActionButton v : viewsToRemove) {
            removeMenuButton(v);        }
    }

    public void setMenuButtonLabelText(String text) {
        mMenuButton.setLabelText(text);    }

    public String getMenuButtonLabelText() {
        return mMenuLabelText;    }

    public void setOnMenuButtonClickListener(OnClickListener clickListener) {
        mMenuButton.setOnClickListener(clickListener);    }

    public void setOnMenuButtonLongClickListener(OnLongClickListener longClickListener) {
        mMenuButton.setOnLongClickListener(longClickListener);    }
}
3)Label.java
=======================
package com.eppico.fabmenu;
import android.annotation.TargetApi;import android.content.Context;import android.content.res.ColorStateList;import android.graphics.Canvas;import android.graphics.ColorFilter;import android.graphics.Outline;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.RectF;import android.graphics.Xfermode;import android.graphics.drawable.Drawable;import android.graphics.drawable.LayerDrawable;import android.graphics.drawable.RippleDrawable;import android.graphics.drawable.ShapeDrawable;import android.graphics.drawable.StateListDrawable;import android.graphics.drawable.shapes.RoundRectShape;import android.os.Build;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewOutlineProvider;import android.view.animation.Animation;import android.widget.TextView;
public class Label extends TextView {

    private static final Xfermode PORTER_DUFF_CLEAR = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
    private int mShadowRadius;    private int mShadowXOffset;    private int mShadowYOffset;    private int mShadowColor;    private Drawable mBackgroundDrawable;    private boolean mShowShadow = true;    private int mRawWidth;    private int mRawHeight;    private int mColorNormal;    private int mColorPressed;    private int mColorRipple;    private int mCornerRadius;    private FloatingActionButton mFab;    private Animation mShowAnimation;    private Animation mHideAnimation;    private boolean mUsingStyle;    private boolean mHandleVisibilityChanges = true;
    public Label(Context context) {
        super(context);    }

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

    public Label(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(calculateMeasuredWidth(), calculateMeasuredHeight());    }

    private int calculateMeasuredWidth() {
        if (mRawWidth == 0) {
            mRawWidth = getMeasuredWidth();        }
        return getMeasuredWidth() + calculateShadowWidth();    }

    private int calculateMeasuredHeight() {
        if (mRawHeight == 0) {
            mRawHeight = getMeasuredHeight();        }
        return getMeasuredHeight() + calculateShadowHeight();    }

    int calculateShadowWidth() {
        return mShowShadow ? (mShadowRadius + Math.abs(mShadowXOffset)) : 0;    }

    int calculateShadowHeight() {
        return mShowShadow ? (mShadowRadius + Math.abs(mShadowYOffset)) : 0;    }

    void updateBackground() {
        LayerDrawable layerDrawable;        if (mShowShadow) {
            layerDrawable = new LayerDrawable(new Drawable[]{
                    new Shadow(),                    createFillDrawable()
            });
            int leftInset = mShadowRadius + Math.abs(mShadowXOffset);            int topInset = mShadowRadius + Math.abs(mShadowYOffset);            int rightInset = (mShadowRadius + Math.abs(mShadowXOffset));            int bottomInset = (mShadowRadius + Math.abs(mShadowYOffset));
            layerDrawable.setLayerInset(
                    1,                    leftInset,                    topInset,                    rightInset,                    bottomInset
            );        } else {
            layerDrawable = new LayerDrawable(new Drawable[]{
                    createFillDrawable()
            });        }

        setBackgroundCompat(layerDrawable);    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private Drawable createFillDrawable() {
        StateListDrawable drawable = new StateListDrawable();        drawable.addState(new int[]{android.R.attr.state_pressed}, createRectDrawable(mColorPressed));        drawable.addState(new int[]{}, createRectDrawable(mColorNormal));
        if (Util.hasLollipop()) {
            RippleDrawable ripple = new RippleDrawable(new ColorStateList(new int[][]{{}},                    new int[]{mColorRipple}), drawable, null);            setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    outline.setOval(0, 0, view.getWidth(), view.getHeight());                }
            });            setClipToOutline(true);            mBackgroundDrawable = ripple;            return ripple;        }

        mBackgroundDrawable = drawable;        return drawable;    }

    private Drawable createRectDrawable(int color) {
        RoundRectShape shape = new RoundRectShape(
                new float[]{
                        mCornerRadius,                        mCornerRadius,                        mCornerRadius,                        mCornerRadius,                        mCornerRadius,                        mCornerRadius,                        mCornerRadius,                        mCornerRadius
                },                null,                null);        ShapeDrawable shapeDrawable = new ShapeDrawable(shape);        shapeDrawable.getPaint().setColor(color);        return shapeDrawable;    }

    private void setShadow(FloatingActionButton fab) {
        mShadowColor = fab.getShadowColor();        mShadowRadius = fab.getShadowRadius();        mShadowXOffset = fab.getShadowXOffset();        mShadowYOffset = fab.getShadowYOffset();        mShowShadow = fab.hasShadow();    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void setBackgroundCompat(Drawable drawable) {
        if (Util.hasJellyBean()) {
            setBackground(drawable);        } else {
            setBackgroundDrawable(drawable);        }
    }

    private void playShowAnimation() {
        if (mShowAnimation != null) {
            mHideAnimation.cancel();            startAnimation(mShowAnimation);        }
    }

    private void playHideAnimation() {
        if (mHideAnimation != null) {
            mShowAnimation.cancel();            startAnimation(mHideAnimation);        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    void onActionDown() {
        if (mUsingStyle) {
            mBackgroundDrawable = getBackground();        }

        if (mBackgroundDrawable instanceof StateListDrawable) {
            StateListDrawable drawable = (StateListDrawable) mBackgroundDrawable;            drawable.setState(new int[]{android.R.attr.state_pressed});        } else if (Util.hasLollipop() && mBackgroundDrawable instanceof RippleDrawable) {
            RippleDrawable ripple = (RippleDrawable) mBackgroundDrawable;            ripple.setState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed});            ripple.setHotspot(getMeasuredWidth() / 2, getMeasuredHeight() / 2);            ripple.setVisible(true, true);        }
//        setPressed(true);    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    void onActionUp() {
        if (mUsingStyle) {
            mBackgroundDrawable = getBackground();        }

        if (mBackgroundDrawable instanceof StateListDrawable) {
            StateListDrawable drawable = (StateListDrawable) mBackgroundDrawable;            drawable.setState(new int[]{});        } else if (Util.hasLollipop() && mBackgroundDrawable instanceof RippleDrawable) {
            RippleDrawable ripple = (RippleDrawable) mBackgroundDrawable;            ripple.setState(new int[]{});            ripple.setHotspot(getMeasuredWidth() / 2, getMeasuredHeight() / 2);            ripple.setVisible(true, true);        }
//        setPressed(false);    }

    void setFab(FloatingActionButton fab) {
        mFab = fab;        setShadow(fab);    }

    void setShowShadow(boolean show) {
        mShowShadow = show;    }

    void setCornerRadius(int cornerRadius) {
        mCornerRadius = cornerRadius;    }

    void setColors(int colorNormal, int colorPressed, int colorRipple) {
        mColorNormal = colorNormal;        mColorPressed = colorPressed;        mColorRipple = colorRipple;    }

    void show(boolean animate) {
        if (animate) {
            playShowAnimation();        }
        setVisibility(VISIBLE);    }

    void hide(boolean animate) {
        if (animate) {
            playHideAnimation();        }
        setVisibility(INVISIBLE);    }

    void setShowAnimation(Animation showAnimation) {
        mShowAnimation = showAnimation;    }

    void setHideAnimation(Animation hideAnimation) {
        mHideAnimation = hideAnimation;    }

    void setUsingStyle(boolean usingStyle) {
        mUsingStyle = usingStyle;    }

    void setHandleVisibilityChanges(boolean handle) {
        mHandleVisibilityChanges = handle;    }

    boolean isHandleVisibilityChanges() {
        return mHandleVisibilityChanges;    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mFab == null || mFab.getOnClickListener() == null || !mFab.isEnabled()) {
            return super.onTouchEvent(event);        }

        int action = event.getAction();        switch (action) {
            case MotionEvent.ACTION_UP:
                onActionUp();                mFab.onActionUp();                break;
            case MotionEvent.ACTION_CANCEL:
                onActionUp();                mFab.onActionUp();                break;        }

        mGestureDetector.onTouchEvent(event);        return super.onTouchEvent(event);    }

    GestureDetector mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent e) {
            onActionDown();            if (mFab != null) {
                mFab.onActionDown();            }
            return super.onDown(e);        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            onActionUp();            if (mFab != null) {
                mFab.onActionUp();            }
            return super.onSingleTapUp(e);        }
    });
    private class Shadow extends Drawable {

        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        private Paint mErase = new Paint(Paint.ANTI_ALIAS_FLAG);
        private Shadow() {
            this.init();        }

        private void init() {
            setLayerType(LAYER_TYPE_SOFTWARE, null);            mPaint.setStyle(Paint.Style.FILL);            mPaint.setColor(mColorNormal);
            mErase.setXfermode(PORTER_DUFF_CLEAR);
            if (!isInEditMode()) {
                mPaint.setShadowLayer(mShadowRadius, mShadowXOffset, mShadowYOffset, mShadowColor);            }
        }

        @Override
        public void draw(Canvas canvas) {
            RectF shadowRect = new RectF(
                    mShadowRadius + Math.abs(mShadowXOffset),                    mShadowRadius + Math.abs(mShadowYOffset),                    mRawWidth,                    mRawHeight
            );
            canvas.drawRoundRect(shadowRect, mCornerRadius, mCornerRadius, mPaint);            canvas.drawRoundRect(shadowRect, mCornerRadius, mCornerRadius, mErase);        }

        @Override
        public void setAlpha(int alpha) {

        }

        @Override
        public void setColorFilter(ColorFilter cf) {

        }

        @Override
        public int getOpacity() {
            return 0;        }
    }
}
4)Util.java
==============
package com.eppico.fabmenu;
import android.content.Context;import android.os.Build;
final class Util {

    private Util() {
    }

    static int dpToPx(Context context, float dp) {
        final float scale = context.getResources().getDisplayMetrics().density;        return Math.round(dp * scale);    }

    static boolean hasJellyBean() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;    }

    static boolean hasLollipop() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;    }
}

No comments:

Post a Comment