Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Wednesday, May 11, 2016

How to define build strategies in your android app over BuildConfig

Hi there!

Today i'm gonna show you, how your could define your build strategies in android studio in an elegant, enhanceable way using the strategy design pattern.

Most of the times, Google defines its product making usage of best practises and good, enhanceable design pattern. I saw recently, in a big project we got, that they were not taking advantage of this and instead of that, they were using enumerations, resulting in a bunch of switch cases and later on another bunch of if-else cases and a lot of repeated code that breaks the DRY-principle and even more important the open-close-principle.

What does it mean to be programming respecting the open-close-principle? It means that every time a new component is created, that i don't have to change running code. i.e. I don't have to create another enum type, another switch-case to identify this type and later on another if-else case to know, depending on the comparation result, what kind of environment i want to set.

That's the code we got. This code has a lot of problems. It is fragile. Every new environment forces you to change a chain of steps in the code. Further it forces you to hold 4 variables in a static way to be able to share it over the application instead of hold only one object responsible for that. We define new enum types and define a new if statement running the risk of breaking existing logic. All of this can be avoided using the strategy pattern.

Let's take a look at the actual code, before enhancing it to visualize the problems:

    // somewhere in code this method was called passing the enum defined in BuildConfig
    setEnvironmentKeys(BuildConfig.ENVIRONMENT);
    // later in the class who defined this method over if-statements we identify the environment
    public static void setEnvironmentKeys(ENV env){
        try{
         if (MainApplication.isProduction()) {
                CONTENT_SERVER_URL = "https://content.mycompany.com/";
                PROFILE_SERVER_URL = "https://profile.mycompany.com/";
                IMAGE_SERVER_URL = "https://image.mycompany.com/log";
                Utils.GOOGLE_DEVELOPER_KEY = Utils.getStringRes(R.string.key_production);
            } else if (env == MainApplication.ENV.STAGING) {
                CONTENT_SERVER_URL = "http://content-staging.mycompany.com/";
                PROFILE_SERVER_URL = "http://profile-staging.mycompany.com/";
                IMAGE_SERVER_URL = "http://image.staging.maycompany.com/";
                Utils.GOOGLE_DEVELOPER_KEY = Utils.getStringRes(R.string.key_staging);
            }  else if (env == MainApplication.ENV.STAGING_TWO) {
                Utils.GOOGLE_DEVELOPER_KEY = Utils.getStringRes(R.string.key_staging);
                CONTENT_SERVER_URL = "http://content-staging2.mycompany.com/";
                PROFILE_SERVER_URL = "http://profile-staging2.mycompany.com/";
                IMAGE_SERVER_URL = "http://image.staging2.mycompany.com/";
            }else if (MainApplication.isDev()) {
                Utils.GOOGLE_DEVELOPER_KEY = Utils.getStringRes(R.string.key_development);
                CONTENT_SERVER_URL = "https://content.dev.mycompany.com/";
                PROFILE_SERVER_URL = "https://profile.dev.mycompany.com/";
                IMAGE_SERVER_URL = "https://image.dev.mycompany.com/";
            }
        }catch(Exception e){
            Log.wtf(TAG, "Couldn't set ENV variables. Setting to Production as default.");
        }
    }
    
    // and somewhere was defined the enum with the build types
    public enum ENV {
        DEVELOPMENT("DEVELOPMENT"),
        STAGING("STAGING"),
        STAGING_TWO("STAGING_TWO"),
        OPS_PREVIEW("OPS_PREVIEW"),
        PRODUCTION("PRODUCTION"), ;

        private final String name;

        private ENV(String s) {
            name = s;
        }

        public boolean equalsName(String otherName){
            return (otherName == null)? false:name.equals(otherName);
        }

        public String toString(){
            return name;
        }

    }

The code above is functional but when it comes to enhancement, maintainability and so on, then we can see some problems on that. We will discuss this later on. Let's now see how we could do it better by using the strategy pattern. First have a look at the uml diagram of it.



And now the little code of if:

   
  // this method is called somewhere in code
  setEnvironment(BuildConfig.ENVIRONMENT);
  
  // then we set the environment and use it without any change in code
  private Environment environment;
  public void setEnvironment(final Environment env){
   environment = env;
  }
  /**
   * In your android studio look for the tab: "Build Variants" (bottom left side)
   * and select "Build Variant > debug" while developing the application.
   * This will automatically instantiate this class and assign this value to BuildConfig.ENVIRONMENT
   * @author Ricardo Ferreira
   */
  public class DeveloperEnvironment extends Environment{
   private final static String CONTENT_SERVER_URL = "https://content.dev.mycompany.com/";
   private final static String PROFILE_SERVER_URL = "https://profile.dev.mycompany.com/";
   private final static String S3_AMAZON_SERVER_URL = "https://s3.amazon.dev.mycompany.com";
   private final static String GOOGLE_DEVELOPER_KEY = "123456";
   public DeveloperEnvironment() {
    super(CONTENT_SERVER_URL, PROFILE_SERVER_URL, S3_AMAZON_SERVER_URL, GOOGLE_DEVELOPER_KEY);
   }
  }
  /**
   * Build environment strategy - Every environment phase should extend from this strategy.
   * This way, you can access your app's environment configuration over the system class 
   * BuildConfig.ENVIRONMENT everywhere without the necessity of enumerations, switch cases 
   * or a bunch of if-else statements. If you create new environments, no change in your code
   * will be needed. 
   * @author Ricardo Ferreira
   */
  public abstract class Environment{
   private final String CONTENT_SERVER_URL;
   private final String PROFILE_SERVER_URL;
   private final String S3_AMAZON_SERVER_URL;
   private final String GOOGLE_DEVELOPER_KEY;
   // ... other environment variables ...
 public Environment(
   final String contentServerUrl, 
   final String profileServerUrl,
   final String s3amazonServerUrl, 
   final String googleDeveloperKey) {
  super();
  this.CONTENT_SERVER_URL = contentServerUrl;
  this.PROFILE_SERVER_URL = profileServerUrl;
  this.S3_AMAZON_SERVER_URL = s3amazonServerUrl;
  this.GOOGLE_DEVELOPER_KEY = googleDeveloperKey;
 }
 public String getContentServerUrl() {
  return CONTENT_SERVER_URL;
 }
 public String getProfileServerUrl() {
  return PROFILE_SERVER_URL;
 }
 public String getS3AmazonServerUrl() {
  return S3_AMAZON_SERVER_URL;
 }
 public String getGoogleDeveloperKey() {
  return GOOGLE_DEVELOPER_KEY;
 }
  }

Coming back to our initial discussion. Imagine now you need to add a new enviromnet. lets say staging. with the approach above you just have to say to someone: create a class who extends from environment, analogical DeveloperEnvironment, define it in your build.gradle, like you would do for the other approach also and done! It would work just fine without touching already written, functional code.The other way around you would have to change the enum, change the if-else statements.

Here is how you could define the strategies in your build.gradle. This will automatically assign the right value to the variable ENVIRONMENT depending on which environment you choose over Android Studio by selecting the tab Build Variants on the bottom left side of your IDE:

buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            debuggable true
            setApplicationIdSuffix("dev")
            versionNameSuffix " Dev"
            buildConfigField "com.treslines.learn.environment.Environment", "ENVIRONMENT", "new com.treslines.learn.environment.DeveloperEnvironment()"
            buildConfigField "boolean", "DEBUGLOG", "true"
            manifestPlaceholders = [
                    appName         : "MyApp Debug"
            ]
        }
        Staging {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.debug
            debuggable true
            setApplicationIdSuffix("staging")
            versionNameSuffix " Staging"
            buildConfigField "com.treslines.learn.environment.Environment", "ENVIRONMENT", "new com.treslines.learn.environment.StagingEnrivornment()"
            buildConfigField "boolean", "DEBUGLOG", "true"
            manifestPlaceholders = [
                    appName         : "MyApp Stg"
            ]
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            zipAlignEnabled true

            buildConfigField "com.treslines.learn.environment.Environment", "ENVIRONMENT", "new com.treslines.learn.environment.ProductionEnrivornment()"
            buildConfigField "boolean", "DEBUGLOG", "false"
        }
    } 

That's all! hope you like it! :)

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Tuesday, March 15, 2016

Fast CPF formatter to be used in Android's EditText View combined with a TextWatcher

Hi there! Today i'm gonna show to you, how i solved a common problem, while dealing with brazilian cpf in edittext view in android studio.

Problem/Chalange: Mask a CPF editText field such a way, that as soon as the user starts typing digits in it, the text field inserts or updates its needed signs for the user automatically.

The first solution was very elegant and well thought and well done with a mask like ###.###.###-## but as soon as the user starts typing very fast in the text field, the mask algorithm was very slow and swallowed some digits in some cases.

For this reason, i took the chalange to myself and decided to create my own, fast cpf formatter. Bellow the solution that solved the problem and that you may use in your apps as you may need.

Solution:


public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new CpfWatcher((EditText) findViewById(R.id.inputCpf));

    }

    public class CpfWatcher implements TextWatcher {

        private EditText inputField;
        private int flag = 0;
        private int signsBeforeChange = 0;
        private int dots = 0;
        private int dash = 0;
        private String txtBeforeChange;

        public CpfWatcher(final EditText inputField) {
            this.inputField = inputField;
            this.inputField.setInputType(InputType.TYPE_CLASS_NUMBER);
            this.inputField.setHint("###.###.###-##");
            this.inputField.addTextChangedListener(this);
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            final String input = s.toString();
            inputField.removeTextChangedListener(this);
            final String formattedCpf = formatCpf(input);
            inputField.setText(formattedCpf);
            inputField.addTextChangedListener(this);
            placeCursorDependingOnUserAction(start, formattedCpf, findOutIfUserWasTypingOrDeleting(input));
        }

        private void placeCursorDependingOnUserAction(int start, String formattedCpf, Action action) {
            switch (action){
                case TYPING:{
                    dots = formattedCpf.length() - formattedCpf.replace(".", "").length();
                    dash = formattedCpf.length() - formattedCpf.replace("-", "").length();
                    signsBeforeChange = dots+dash;
                    inputField.setSelection(formattedCpf.length());
                    break;
                }
                case DELETING:{

                    if(start-1 < 0){
                        inputField.setSelection(0);
                    }else if(txtBeforeChange.equalsIgnoreCase(formattedCpf)){
                        inputField.setSelection( start );
                        flag++;
                    }
                    else{
                        dots = formattedCpf.length() - formattedCpf.replace(".", "").length();
                        dash = formattedCpf.length() - formattedCpf.replace("-", "").length();
                        int sigsAfterChange = dots+dash;
                        if(signsBeforeChange > sigsAfterChange){
                            inputField.setSelection( start-1 );
                            signsBeforeChange = sigsAfterChange;
                        }else{
                            inputField.setSelection( start );
                        }
                    }
                    break;
                }
            }
        }

        private Action findOutIfUserWasTypingOrDeleting(String input) {
            Action action = Action.TYPING;
            if(flag <=input.length()){
                flag = input.length();
                action = Action.TYPING;
            }else{
                flag = input.length();
                action = Action.DELETING;
            }
            return action;
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            txtBeforeChange = s.toString();
        }

        @Override
        public void afterTextChanged(Editable s) { /* NOP*/ }

        public  Editable getCpf(){
           return inputField.getText();
        }

    }

    public enum Action {
        TYPING, DELETING
    }

    private String formatCpf(String cpf) {
        String[] sign = new String[]{".", ".", "-"};
        String[] signRegEx = new String[]{"\\.", "\\.", "-"};
        int[] signPos = new int[]{4, 8, 12};
        return formatCpfDependingOnLentgh(sign, signPos, removeAllSigns(cpf, signRegEx));
    }

    private String removeAllSigns(String cpf, String[] signRegEx) {
        String empty = "";
        String tmp = cpf;
        for (String sign : signRegEx) {
            tmp = tmp.replaceAll(sign, empty);
        }
        return tmp;
    }

    private String formatCpfDependingOnLentgh(String[] sign, int[] signPos, String cpfWithoutAnySign) {
        String tmp = cpfWithoutAnySign;
        int aLentgh = tmp.length();
        if (aLentgh <= signPos[0] - 1) {
            // nothing to format
        }else if(aLentgh == signPos[0]-1) {
            tmp = create1Punctuation(tmp, sign);
        }
        else if (aLentgh > signPos[0] - 1 && aLentgh < signPos[1] - 1) {
            tmp = create2Punctuations(tmp, sign);
        }
        else if (aLentgh == signPos[1] - 1) {
            tmp = create3Punctuations(tmp, sign);
        }
        else if (aLentgh > signPos[1] - 1 && aLentgh < signPos[2] - 2) {
            tmp = create3Punctuations(tmp, sign);
        }
        else if (aLentgh == signPos[2] - 2) {
            tmp = create4Punctuations(tmp, sign);
        }
        else if (aLentgh > signPos[2] - 2 && aLentgh < signPos[2]) {
            tmp = create4Punctuations(tmp, sign);
        } else {
            tmp = trunk4Punctuations(tmp, sign);
        }
        return tmp;
    }

    private String create1Punctuation(String tmp, String[] punc) {
        return tmp + punc[0];
    }

    private String create2Punctuations(String tmp, String[] punc) {
        String s1 = tmp.substring(0, 3);
        String s2 = tmp.substring(3, tmp.length());
        return s1 + punc[0] + s2;
    }

    private String create3Punctuations(String tmp, String[] punc) {
        String s1 = tmp.substring(0, 3);
        String s2 = tmp.substring(3, 6);
        String s3 = tmp.substring(6, tmp.length());
        return s1 + punc[0] + s2 + punc[1] + s3;
    }

    private String create4Punctuations(String tmp, String[] punc) {
        String s1 = tmp.substring(0, 3);
        String s2 = tmp.substring(3, 6);
        String s3 = tmp.substring(6, 9);
        String s4 = tmp.substring(9, tmp.length());
        return s1 + punc[0] + s2 + punc[1] + s3 + punc[2] + s4;
    }

    private String trunk4Punctuations(String tmp, String[] punc) {
        String s1 = tmp.substring(0, 3);
        String s2 = tmp.substring(3, 6);
        String s3 = tmp.substring(6, 9);
        String s4 = tmp.substring(9, 11);
        return s1 + punc[0] + s2 + punc[1] + s3 + punc[2] + s4;
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Thursday, August 20, 2015

How to run/install pagseguro on android without thirdpart apps

Hi there!

Today i'm gonna show to you, how to run PagSeguro on Android Apps without any third part app from PagSeguro.

Everybody knows how important it is to offer payment methods in our apps. PagSeguro is a very common payment method in Brazil, but very tricky to get it run correctly on android apps. In fact almost every payment method is very annoying to implement! :)

For this reason I decided to implement my own PagSeguro solution and share a complete sample with the world.

First Step - Get a PagSeguro Account

To do so, register yourself on pagseguro, log in and go to: Vender > Ferramentas para desenvolvedores > Sandbox



There you'll find a automatic created test buyer (comprador de teste) and a test seller (vendedor de teste) like in the images bellow. kepp it open, then you'll need those values in the app we will see here.




Second Step - Fork or just download the sample from Github

The sample was developed using android studio and tested on my pagseguro sandbox account. It is available from here: https://github.com/treslines/pagseguro_android. The image bellow shows some transactions i made using my sandbox account:


What you'll get?

The pictures bellow show how the app looks like. It addresses already navigations issues e user notifications.
















Go download it!

Go now to github: https://github.com/treslines/pagseguro_android. download it and test it. Any feedback or contribution to make it better is welcome!

That's all! Hope you like it!

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Thursday, August 13, 2015

Android AlertDialog utilities, redirect to google play store, check if third part app is istalled

Hi there!

Today i'm gonna share some utility methods i use very often while developing. Creating a popup dialog, a confirm dialog, ok-cancel-dialog, check if a third part app is installed, redirect to google play store if some app is missing and so on are common tasks in our daily business.

/**
 * Use this class to create alert dialogs on the fly, redirect to google play store and so on...< br / >
 * < br / >Author: Ricardo Ferreira, 8/13/15
 */
public final class AppUtil {

    /**
     * Shows a confirm dialog with a custom message and custom quit button text.
     * If you pass null to btnTxt, "ok" will be shown per default.
     *
     * @param context the apps context This value can't be null.
     * @param msg     the message to be shown. his value can't be null or empty.
     * @param btnTxt  the text to be shown in the quit button. For example "close"
     */
    public static void showConfirmDialog(@NonNull final Context context, @NonNull final String msg, final String btnTxt) {
        if (msg.isEmpty()) {
            throw new IllegalArgumentException("This value can't be empty!");
        }
        final AlertDialog dialog = new AlertDialog.Builder(context).setMessage(msg)
                .setPositiveButton((btnTxt == null ? "Ok" : btnTxt), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).create();
        dialog.show();
    }

    /**
     * Shows a confirm dialog with a custom message, custom buttons and custom actions.
     *
     * @param ctx                the apps context. This value can't be null.
     * @param msg                the message to be shown This value can't be null or empty.
     * @param okBtn              the text to be shown in the ok button. If you pass null, ok will be shown per default
     * @param cancelBtn          the text to be shown in the cancel button. If you pass null, cancel will be shown per default
     * @param okAction           the action to be performed as soon as the user presses the ok button. if you pass null, nothing happens.
     * @param cancelAction       the action to be performed as soon as the user presses the cancel button. if you pass null, nothing happens.
     * @param backPressendAction the action to be performed as soon as the user presses the system back button. if you pass null, nothing happens.
     */
    public static void showOkCancelDialog(@NonNull final Context ctx, @NonNull final String msg, final String okBtn, final String cancelBtn, final AlertAction okAction, final AlertAction cancelAction, final AlertAction backPressendAction) {
        if (msg.isEmpty()) {
            throw new IllegalArgumentException("This value can't be empty!");
        }
        final AlertDialog dialog = new AlertDialog.Builder(ctx).setMessage(msg)
                .setPositiveButton((okBtn == null ? "Ok" : okBtn), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        if (okAction != null) {
                            okAction.perform();
                        }
                    }
                }).setNegativeButton((cancelBtn == null ? "Cancel" : cancelBtn), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        if (cancelAction != null) {
                            cancelAction.perform();
                        }
                    }
                }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        dialog.dismiss();
                        if (backPressendAction != null) {
                            backPressendAction.perform();
                        }
                    }
                }).create();
        dialog.show();
    }

    public interface AlertAction {
        void perform();
    }

    /**
     * Use this method to check if a third part app is istalled or not
     * @param ctx the app's context
     * @param packageName the third part app's package name. something like: com.example.package
     * @return true if the app is installed.
     */
    public static boolean isAppInstalled(final Context ctx, final String packageName) {
        PackageManager pm = ctx.getPackageManager();
        boolean installed = false;
        try {
            pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
            installed = true;
        } catch (PackageManager.NameNotFoundException e) {
            installed = false;
        }
        return installed;
    }

    /**
     *  Use this method to open the google play store
     * @param activity the app which wants to redirect to the google play store
     * @param googlePlayStoreId the third part app's package name. something like: com.example.package
     * @param requestCode the request code to be used in the method onActivityForResult in the app which called this method.
     */
    public static void navigateToGooglePlayStore(final Activity activity, final String googlePlayStoreId, final int requestCode) {
        try {
            activity.startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + googlePlayStoreId)), requestCode);
        } catch (android.content.ActivityNotFoundException anfe) {
            // last chance: try again a second time with a different approach
            activity.startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + googlePlayStoreId)), requestCode);
        }
    }
}

Usage Example:

//... 
// check if app is istalled
return AppUtil.isAppInstalled(context,packageName);
//... 
// redirect to google play store
AppUtil.navigateToGooglePlayStore(activity ,googlePlayStoreId, requestCode);
//... 
// create a Ok-Cancel-Dialog
final String msg = "The app will no work without PagSeguro.";
        AppUtil.showOkCancelDialog(context, msg, "Install", "Cancel",
        new AppUtil.AlertAction() {
            @Override
            public void perform() {
                navigateToGooglePlayStore(PAG_SEGURO_PACKAGE_NAME);
            }
        }, new AppUtil.AlertAction() {
            @Override
            public void perform() {
                finish();
            }
        }, new AppUtil.AlertAction() {
            @Override
            public void perform() {
                finish();
            }
        });
//... code omitted

That's all! hope you like it! :)

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Wednesday, September 24, 2014

How to run junit tests inside the android project

Hi there!

Today i'm gonna show you how to create and run junit tests inside your android project without creating a separated test project. With those tests we will rapidly be able to automate and test the app's logic and some simple UI behaviors. The example below is very straightforward and much more intuitive than other approaches i saw out there.

Defining the TestInstrumentation 

First of all, define in your manifest file the following entries. IMPORTANT: While the definition of the test instrumentation will be placed outside your application tag, the test runner must be defined  inside your application tag.




< manifest >
...
< instrumentation 
  android:name="android.test.InstrumentationTestRunner"
  android:targetPackage="com.treslines.ponto" 
/ >
< / manifest >
< application >
...
< uses-library android:name="android.test.runner" / >
...
< / application >

Creating the test packages

Android works with some conventions while testing. So it is extremelly important to follow those conventions. Otherwise you'll get compile or run errors while trying to run it. One convention is that all tests for a specific class must be placed in the same package structure but with a futher sub-folder called test as you can see below. Because i want to test the activities in the package com.treslines.ponto.activity i must create a test package called com.treslines.ponto.activity.test



Creating the test itself

That's the cool part of it. Here you can write your junit tests as usual. Again android  gives us some conventions to follow. All test classes must have the same name as the class under test with the suffix Test on it. And all test methods must start with the prefix test on it. If you follow those conventions everything will work just fine.

// IMPORTANT: All test cases MUST have a suffix "Test" at the end
//
// THAN:
// Define this in your manifest outside your application tag:
//  < instrumentation 
//    android:name="android.test.InstrumentationTestRunner"
//    android:targetPackage="com.treslines.ponto" 
//  / >
//
// AND:
// Define this inside your application tag:
//  < uses-library android:name="android.test.runner" / >
//
// The activity you want to test will be the "T" type of ActivityInstrumentationTestCase2
public class AlertaActivityTest extends ActivityInstrumentationTestCase2 < AlertaActivity > {

 private AlertaActivity alertaActivity;
 private AlertaController alertaController;

 public AlertaActivityTest() {
  // create a default constructor and pass the activity class
  // you want to test to the super() constructor
  super(AlertaActivity.class);
 }

 @Override
 // here is the place to setup the var types you want to test
 protected void setUp() throws Exception {
  super.setUp();
  
  // because i want to test the UI in the method testAlertasOff()
  // i must set this attribute to true
  setActivityInitialTouchMode(true);

  // init variables
  alertaActivity = getActivity();
  alertaController = alertaActivity.getAlertaController();
 }

 // usually we test some pre-conditions. This method is provided
 // by the test framework and is called after setUp()
 public void testPreconditions() {
  assertNotNull("alertaActivity is null", alertaActivity);
  assertNotNull("alertaController is null", alertaController);
 }

 // test methods MUST start with the prefix "test"
 public void testVibrarSomAlertas() {
  assertEquals(true, alertaController.getView().getVibrar().isChecked());
  assertEquals(true, alertaController.getView().getSom().isChecked());
  assertEquals(true, alertaController.getView().getAlertas().isChecked());
 }

 // test methods MUST start with the prefix "test"
 public void testAlertasOff() {
  Switch alertas = alertaController.getView().getAlertas();
  // because i want to simulate a click on a view, i must use the TouchUtils
  TouchUtils.clickView(this, alertas);
  // wait a little (1.5sec) because the UI needs its time
  // to change the switch's state and than check new state of the switches
  new Handler().postDelayed(new Runnable() {
   @Override
   public void run() {
    assertEquals(false, alertaController.getView().getVibrar().isChecked());
    assertEquals(false, alertaController.getView().getSom().isChecked());
   }
  }, 1500);
 }
}

Running the JUnit tests

The only difference while running junit test in android is that you'll be calling Run As > Android JUnit Test instead of just JUnit Test like you are used to in java.


That's all! Hope you like it! :)

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Monday, September 8, 2014

how to import/parse or create json/gson as arraylist from strings.xml in android?

Hi there!

Today i'm gonna show to you, how we can profit from the existing Gson library while dealing with array lists in the string.xml file. The benefits of it is that can define as many strings.xml entries as we need and import/parse the whole list structures almost without any effort.

Gson library

download the Gson library from here Gson 2.2.4. Don't worry about the "deprecated" tag. It is not really deprecated. Only parts of it acc. to its developer. We can continue using it. Than unzip it and cut/paste the following jar (gson-2.2.4.jar) in the libs folder from your project.

Json sample

Open your strings.xml file and copy/paste this line sample entry in it(It is a representation of an array list of Points with x and y coordinates):

 < string name="point_array" > {\"points\":[{\"x\": 255,\"y\": 689},{\"x\": 199,\"y\": 658}< / string > 

Defining a Data Container

You'll need a data container to hold the read points. So lets define a structure for it.
           
public class PointContainer {
    private List < Point > points;
    public List < Point > getPoints() {return points;}
    public void setPoints(List < Point > points) {this.points = points;}
}

Usage of the Gson lib

With the Gson lib, import/parse the array into a json structure. The benefits of it is that can define as many strings.xml entries as you need and import the whole list structure almost without any effort.
           
    String pointArray = getResources().getString(R.string.point_array);
    PointContainer pointContainer = new Gson().fromJson(pointArray, PointContainer.class);
    List < Point > points = pointContainer.getPoints();
    // do something with the data here...

Reading List of Lists

Here it gets more tricky. Offen we will need to read a list of list from json format into java code. To do so, lets see how it works by writing a simple example.We will do the same way as the code above. the only difference is to note that if we have list of list we will need to create a class that holds the sublists and so on...
 
< string name="string_points" >{"items":[{"points":[{"x": 644,"y": 420},{"x": 644,"y": 421},{"points":[{"x": 752,"y": 348},{"x": 752,"y": 349}]}]} < / string >

public class ItemContainer {
 private List < Item > items ;
 public List < Item > getItems() {
  return items 
 }
 public void setItems(List < Item > items ) {
  this.items  = items 
 }
}

public class Item {
 private List < Point > points;
 public List < Point > getPoints() {
  return points;
 }
 public void setPoints(List < Point > points) {
  this.points = points;
 }
}

String string = cxt.getResources().getString(R.string.string_points);
List < ItemContainer > l =  new ArrayList < ItemContainer >();
Gson gson = new Gson();
l.add(gson.fromJson(string, ItemContainer.class));

That's all! Hope you like it!

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Wednesday, August 27, 2014

How to make intellij works like eclipse incl. appearance and shortcuts in 1 min.

Hi there!

Since a few days I'm thinking about to move to AndroidStudio's IntelliJ IDEA. One of biggest problem and resistance i had, was the fact that IntelliJ IDEA has totally different shortcuts than eclipse. We don't want to learn or invent the wheel again for the same thing, right? For this reason, i'll show to you, how to use eclipse's shortcuts in IntelliJ.

Another thing i don't like very much, is the color schema. I've been programming with eclipse since years and although I like the black look and feel, I still prefer the traditional white appearance. So i will also show, how we can override the color schema of IntelliJ with a few clicks


Changing the shortcut list

Once you´ve downloaded and installed your AndroidStudio, start it and follow the sequences bellow:





Changing the color Schema

Now let's change also the color schema. To do so, copy this eclipse.xml file and save it in your desktop with the extension .xml

 
< ?xml version="1.0" encoding="UTF-8"? >
< scheme name="eclipse" version="1" parent_scheme="Default" >
  < option name="LINE_SPACING" value="1.2" /  >
  < option name="EDITOR_FONT_SIZE" value="12" /  >
  < option name="EDITOR_FONT_NAME" value="Courier New" /  >
  < colors >
    < option name="CARET_ROW_COLOR" value="e8f2fe" /  >
  < / colors >
  < attributes >
    < option name="ANNOTATION_NAME_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="646464" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="1" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.FUNCTION" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.IDENT" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.KEYWORD" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="1" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.PROPERTY_NAME" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.PROPERTY_VALUE" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.STRING" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.TAG_NAME" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CSS.URL" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_KEYWORD1_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_KEYWORD2_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="660e7a" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_KEYWORD3_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="6666" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_KEYWORD4_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="660000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_LINE_COMMENT_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="8080" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_MULTI_LINE_COMMENT_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="8080" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="CUSTOM_STRING_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.BOUNDS" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.BRACKETS" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.IDENT" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.KEYWORD" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.NUMBER" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.PARENTHS" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL.STRING" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="EL_BACKGROUND" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" value="edffed" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="HTML_ATTRIBUTE_NAME" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="HTML_ATTRIBUTE_VALUE" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="HTML_ENTITY_REFERENCE" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="HTML_TAG_NAME" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="INSTANCE_FIELD_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="c0" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_BLOCK_COMMENT" >
      < value >
        < option name="FOREGROUND" value="3f7f5f" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_DOC_COMMENT" >
      < value >
        < option name="FOREGROUND" value="3f5fbf" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_DOC_MARKUP" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="1" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_INVALID_STRING_ESCAPE" >
      < value >
        < option name="FOREGROUND" value="c0" /  >
        < option name="BACKGROUND" value="ffcccc" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_KEYWORD" >
      < value >
        < option name="FOREGROUND" value="7f0055" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_LINE_COMMENT" >
      < value >
        < option name="FOREGROUND" value="3f7f5f" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_NUMBER" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_STRING" >
      < value >
        < option name="FOREGROUND" value="2a00ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JAVA_VALID_STRING_ESCAPE" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.BADCHARACTER" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" value="ffcccc" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.BLOCK_COMMENT" >
      < value >
        < option name="FOREGROUND" value="808080" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.BRACES" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.BRACKETS" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.COMMA" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.DOC_COMMENT" >
      < value >
        < option name="FOREGROUND" value="808080" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.DOC_MARKUP" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" value="e2ffe2" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.DOC_TAG" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="1" /  >
        < option name="EFFECT_COLOR" value="808080" /  >
        < option name="EFFECT_TYPE" value="1" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.DOT" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.INVALID_STRING_ESCAPE" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" value="ffcccc" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.KEYWORD" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.LINE_COMMENT" >
      < value >
        < option name="FOREGROUND" value="808080" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.NUMBER" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.OPERATION_SIGN" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.PARENTHS" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.REGEXP" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="-1" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.SEMICOLON" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.STRING" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JS.VALID_STRING_ESCAPE" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="JSP_DIRECTIVE_NAME" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="PROPERTIES.KEY" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="1" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="PROPERTIES.VALID_STRING_ESCAPE" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="PROPERTIES.VALUE" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="SCOPE_KEY_Problems" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="SCOPE_KEY_Production" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="SCOPE_KEY_Tests" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="STATIC_FIELD_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" value="c0" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="2" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="TEXT" >
      < value >
        < option name="FOREGROUND" value="323232" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="WARNING_ATTRIBUTES" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" value="f4c82d" /  >
        < option name="EFFECT_TYPE" value="2" /  >
        < option name="ERROR_STRIPE_COLOR" value="f4c82d" /  >
      < / value >
    < / option >
    < option name="XML_ATTRIBUTE_NAME" >
      < value >
        < option name="FOREGROUND" value="ff" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="XML_ATTRIBUTE_VALUE" >
      < value >
        < option name="FOREGROUND" value="8000" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="XML_ENTITY_REFERENCE" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="XML_TAG_DATA" >
      < value >
        < option name="FOREGROUND" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
    < option name="XML_TAG_NAME" >
      < value >
        < option name="FOREGROUND" value="80" /  >
        < option name="BACKGROUND" /  >
        < option name="FONT_TYPE" value="0" /  >
        < option name="EFFECT_COLOR" /  >
        < option name="EFFECT_TYPE" value="0" /  >
        < option name="ERROR_STRIPE_COLOR" /  >
      < / value >
    < / option >
  < / attributes >
< / scheme >

Setting the color Schema

Now cut this saved file from your desktop using Ctrl+X and put it in your user's directory by pressing Ctrl+V like that: (Note, your user's color config directory may not be equal to my presented here in this example)


Now you should see this file by looking at:



Done! That's all! Hope you like it.

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Wednesday, August 6, 2014

How to send email with attachment over android and how to import files from download folder

Hi there!

Today i'm gonna show how to attach a file as attachment and send it over your smartphone using Android. This is specially good if you want users to send you feedbacks or you are trying to backup something.

I had specially problems with attachments because out there was a lot of content but no one completed. Just code snippets and fragments. Here you'll find a complete and working example!


Preparing Attachments

Before you can send attachments, you must create a file in an external directory of your choice before trying to send it. I tryed several approaches and no one has worked for me. Only this one! So, first of all save your data, for example, like this bellow:

    private static final String DATABASE_NAME = "yourDatabaseName.db";
    private static final String SEPARATOR = File.separator;
    public static final String BACKUP = SEPARATOR+DATABASE_NAME;
    public final String packageName = context.getPackageName();
    public static final String DB_FILEPATH = "/data/data/" + packageName + "/databases/"+DATABASE_NAME;
 
    public void backupDatabase() throws IOException {

        if (isSDCardWriteable()) {
            // Open your local db as the input stream
            String inFileName = DB_FILEPATH;
            File dbFile = new File(inFileName);
            FileInputStream fis = new FileInputStream(dbFile);

            String outFileName = Environment.getExternalStorageDirectory()+ BACKUP;
            // Open the empty db as the output stream
            OutputStream output = new FileOutputStream(outFileName);
            // transfer bytes from the inputfile to the outputfile
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
            // Close the streams
            output.flush();
            output.close();
            fis.close();
        }
    }
    

    private boolean isSDCardWriteable() {
        boolean rc = false;
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            rc = true;
        }
        return rc;
    }

Email Intent

Das is the method responsible for sending emails.

    public void backupOverEmail(String[] toEmails) throws IOException {
        backupDatabase();
        String fileName = BACKUP;
        File file = new File(Environment.getExternalStorageDirectory() + fileName);
        Uri path = Uri.fromFile(file);
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("application/octet-stream");
        intent.putExtra(Intent.EXTRA_SUBJECT, "Backup");
        intent.putExtra(Intent.EXTRA_EMAIL, toEmails);
        intent.putExtra(Intent.EXTRA_TEXT, "Backup database\n");
        intent.putExtra(Intent.EXTRA_STREAM, path);
        context.startActivity(Intent.createChooser(intent, "Send mail..."));
    }

Importing Files 

To import your files, you may use this:

    public void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
        FileChannel fromChannel = null;
        FileChannel toChannel = null;
        try {
            fromChannel = fromFile.getChannel();
            toChannel = toFile.getChannel();
            fromChannel.transferTo(0, fromChannel.size(), toChannel);
        } finally {
            try {
                if (fromChannel != null) {
                    fromChannel.close();
                }
            } finally {
                if (toChannel != null) {
                    toChannel.close();
                }
            }
        }
    }
    public boolean importDatabase() throws IOException {

        // import backup from download folder
        String dbPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + BACKUP;
        // Close the SQLiteOpenHelper so it will
        // commit the created empty database to internal storage.
        close();
        File newDb = new File(dbPath);
        File oldDb = new File(DB_FILEPATH);
        if (newDb.exists()) {
            copyFile(new FileInputStream(newDb), new FileOutputStream(oldDb));
            // Access the copied database so SQLiteHelper
            // will cache it and mark it as created.
            getWritableDatabase().close();
            return true;
        }
        return false;
    }

That's alll. Hope you like it.

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†