Oggi si è tenuto al FabLab di Padova un Workshop sull’Internet of Things, durante il quale ho avuto il piacere di anticipare l’intervento di Intel con un intervento dal titolo #Google, #Android, #IoT.

Durante questo intervento ho fornito agli attendenti una panoramica sui servizi che Google mette a disposizione per l’universo dell’Internet of Things e mostrato come è possibile far comunicare una app Android con una scheda Arduino, sia a corto raggio tramite Bluetooth che da remoto appoggiandosi su un server Firebase.

Le slide sono liberamente consultabili a questo indirizzo.

Di seguito i riferimenti ai servizi, prodotti e librerie citati nell’intervento:

Grazie a OfficineDigitali ZIP per aver ospitato il mio intervento!

When you run your Android tests (like espresso tests), you may want to be able to force the locale of your device to some specific value at runtime (during test execution). This could be really helpful if you want to test some features of your app against multiple locales.

You can do this by using Junit4 rules. The rule implementation looks like this:

public class ForceLocaleRule implements TestRule {

    private final Locale mTestLocale;
    private Locale mDeviceLocale;

    public ForceLocaleRule(Locale testLocale) {
        mTestLocale = testLocale;
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            public void evaluate() throws Throwable {
                try {
                    if (mTestLocale != null) {
                        mDeviceLocale = Locale.getDefault();
                        setLocale(mTestLocale);
                    }

                    base.evaluate();
                } finally {
                    if (mDeviceLocale != null) {
                        setLocale(mDeviceLocale);
                    }
                }
            }
        };
    }


    public void setLocale(Locale locale) {
        Resources resources = InstrumentationRegistry.getTargetContext().getResources();
        Locale.setDefault(locale);
        Configuration config = resources.getConfiguration();
        config.locale = locale;
        resources.updateConfiguration(config, resources.getDisplayMetrics());
    }
}

The test locale is passed in as a parameter to the constructor. Before test execution we set the test locale. When test is executed, the previous device’s locale will be automatically restored.

And here’s an example of a test where locale il setted to Locale.UK before test execution:

@RunWith(AndroidJUnit4.class)
public class MyActivityTest {

    @ClassRule
    public static final ForceLocaleRule localeTestRule = new ForceLocaleRule(Locale.UK);

    @Rule
    public ActivityTestRule<MyActivity> mMyActivityRule = new ActivityTestRule<>(MyActivity.class);

    private Context mContext;

    @Before
    public void setUp() {
    	// ...
    }

    @Test
    public void testSomeMethod() {
    	// ...
    }
}

Sometimes some fetaures of your app must behave differently for different flavors o build type. Think about when you need to enable logging for a specific flavor only, or you have to disable crash reporting for your “dev build”. All this behaviours can be configured at compile time, insted of using many if/else blocks that are evaluated at runtime.

In the following example I’ll use Gradle and Dagger.

Use case: enable crash reporting only for production flavor.

First step: create an interface CrashReporter and two implementations: CrashReporterRealImpl and CrashReporterNullImpl.

// the interface
public interface CrashReporter {
  
  void init(Application application);

  void logException(Exception e);
}

// this implementation will report crashes
public class CrashReporterRealImpl implements CrashReporter {
  
  public void init(Application application) {
    Fabric.with(application, new Crashlytics()); 
  }

  public void logException(Throwable t) {
    Crashlytics.logException(t);
  }
}

// this implementation will do nothing
public class CrashReporterNullImpl implements CrashReporter {
  
  public void init(Application application) {
    // do nothing
  }

  public void logException(Throwable t) {
    // do nothing
  }
}

Second step: configure the build.gradle file for our app.

android {
  // constants
  def BOOLEAN = "boolean"
  def TRUE = "true"
  def FALSE = "false"

  // app features
  def FEATURE_CRASH_REPORTING_ENABLED = "FEATURE_CRASH_REPORTING_ENABLED"
  ...

  defaultConfig {
      ...

      // default features
      buildConfigField BOOLEAN, FEATURE_CRASH_REPORTING_ENABLED, FALSE
      
  }

  productFlavors {
      developer {
        ...
      }
      qateam {
        ...
      }
      playstore {
        ...
        buildConfigField BOOLEAN, FEATURE_CRASH_REPORTING_ENABLED, TRUE
        
      }
  }   
}

Third step: use dagger to provide the right instance of CrashReporter.

@Module
public class ApplicationModule {

  @Provides
  @Singleton
  CrashReporter provideCrashReporter() {
    if (BuildConfig.FEATURE_CRASH_REPORTING_ENABLED) {
          return new CrashReporterRealImpl();
      } else {
          return new CrashReporterNullImpl();
      }
  }
}

Final step: inject and use!

public class MyApp extends Application {

  @Inject
  CrashReporter mCrashReporter;

  @Override
  public void onCreate() {
    super.onCreate();

    component = DaggerMyApp_ApplicationComponent.builder()
            .applicationModule(new ApplicationModule(this))
            .build();

    component.inject(this);

    mCrashReporter.init(this);
  }
}

It could seem a lot of code for just enabling/disabling a feature, but with this approach the code is modular (for example you could easily replace CrashReporterRealImpl with another one that uses another service, or you can temporarly enable crash reporting for another flavor for testing purposes) and there’s no logic that needs to be tested.

With this approach you could also develop new functions directly in the master branch without using a “feature branch”.

Use case: develop a new feture in master branch.

Suppose that we have to work on our new feature called “Experimental Feature”. We just need to create an interface and two implementations as done before:

// the interface
public interface ExperimentalFeatureController {
  
  void doSomething(Context context);

}

// this implementation will do the real work
public class ExperimentalFeatureControllerRealImpl implements ExperimentalFeatureController {
  
  public void doSomething(Context context) {
    // implementation logic here!
  }

}

// this implementation will do nothing
public class ExperimentalFeatureControllerNullImpl implements ExperimentalFeatureController {
  
  public void doSomething(Context context) {
    // do nothing
  }

}

Then create the definitions in build.gradle and add provide method to the dagger module:

@Module
public class ApplicationModule {

  @Provides
  @Singleton
  ExperimentalFeatureController provideExperimentalFeatureController() {
    if (BuildConfig.FEATURE_EXPERIMENTAL_ENABLED) {
          return new ExperimentalFeatureControllerRealImpl();
      } else {
          return new ExperimentalFeatureControllerNullImpl();
      }
  }
}

Now we can continue to develop in the master branch and commit even when our ExperimentalFeatureControllerRealImpl does not work correctly: FEATURE_EXPERIMENTAL_ENABLED will be TRUE only for our “dev build”, and in FALSE for production build.

When ExperimentalFeatureControllerRealImpl will be ready for production, we will just have to set FEATURE_EXPERIMENTAL_ENABLED to TRUE also for production build!

Have you ever got a OutOfMemoryError while compiling an Android project, just like this?

:app:dexDebug
Unknown source file : Uncaught translation error: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space
Unknown source file : 1 error; aborting

:app:dexDebug FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:dexDebug'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

The quick solution is: add javaMaxHeapSize to dexOptions in your build.gradle, adjusting the value on your needs.

android {
	...

    dexOptions {
        javaMaxHeapSize "2g"
    }

    ...
}

E’ da tempo che mi chiedo come mai non esista un Google Developer Group nel Veneto. Basta dare un’occhiata alla directory dei GDG a questo link per vedere che, in Italia, il Nord-Est è abbastanza scoperto. Così, invece di attendere che su quella mappa compaia un nuovo marker più vicino alle mie zone, ho deciso di prendere contatti con Google e attivarmi per creare un GDG nella zona di Venezia-Treviso-Padova.

Perché? Per costruire una community reale di sviluppatori, designer e esperti di social media marketing con il supporto di Google! Sarà la prima community di questo tipo nel Veneto.

Cos’è un GDG (Google Developer Group)? I GDG sono gruppi di sviluppatori (ma non solo) interessati nelle tecnologie Google come Android, Chrome, Drive, Google Cloud, Cast API, Maps API, YouTube API… (ma non solo). Un GDG può attuarsi in diversi modi, da un gruppo ristretto di persone che consultano gli ultimi video tecnici, a eventi più grandi come demo, talk tecnici e hackaton. Il focus di ogni evento è comunque su contenuti tecnici e di sviluppo.

Chi può partecipare? Sviluppatori, UI/UX designer, esperti di social media marketing. Il focus è sulle tecnologie made in Google, ma questo non è un limite: sono benvenute tutte le tecnologie!

Cosa non si vuole fare: l’ennesimo evento in cui una persona parla e molte persone si annoiano.

Cosa si vuole fare: creare un punto di ritrovo sia virtuale che fisico nel quale le persone scambiano idee, materiale, informazioni e instaurano nuovi rapporti di collaborazione. Il tutto in modo informale, magari di fronte ad uno spritz o un caffè!

Vuoi saperne di più, solo per curiosità o per contribuire attivamente? Contattami tramite l’apposita sezione in questo sito o su Twitter!