Interview on local 7 TV Murcia

In this post I want to share the live interview that I did on the 7 TV Región de Murcia.

Since I was visiting my city (Murcia, Spain), I went to my former university, Universidad de Murcia, to give a talk to the students of the Computer Science school.

Related to that meet-up with the students, I also went to the local TV, 7 Televisión Región de Murcia for a quick live interview on the news program.

Note: The interview is in Spanish

Share Button

Read More

My F8 experience

F8 is the annual Facebook’s developer conference. During this conference, the company announces all their new products and technologies. This year 2018, the conference was hosted in the McEnery Convention Center San José.

I had the opportunity to attend this year and I want to show you here my experience.

Keynote

The F8 starts with the keynote, which is live broadcasted and watched by thousands of people from all over the world. This year the main spotlight was the issues that the company has recently encountered regarding users’ data privacy. During the first minutes of the keynote, Mark Zuckerberg focused on talking about the solutions Facebook is developing to solve these problems. Here you can watch the complete video of the keynote.

 

F8 Keynote

 

Let me highlight two different moments. The first is the one that made everyone laugh, when Mark Zuckerberg played the video when he testified before Congress. The second one, the moment with the loudest applause, was when Mark Zuckerberg said that all the audience would get the Oculus Go for free.

After the keynote was finished, the Festival Hall was opened. This hall was distributed in different areas, where all the new products could be enjoyed, like the Oculus Go or the AR experience in messenger.

 

F8 Festival Hall

 

Sessions

Since F8 is a conference after all, let me tell you about the sessions. I attended around 10-12 sessions. From all of them, only 2 of them had some code-related content. I mean by this, that the technical level of the sessions was low. Even more considering that this is a conference for developers. Most of the sessions seem to be more focused on product and management areas, than on engineering.

An interesting session was “How React Native Helps Companies Build Better Mobile Apps”. Although it was in the form of a panel, the discussion was about how React Native has been used by different companies (Microsoft, TaskRabbit, Vogue.com and Postlight), and how this affected to the distribution of the engineering teams and to the way the company works internally. Again, no technical details, but it provided a good overview of this technology.

 

The conference is a good source of inspiration for future trends.

 

F8 Session
 

Networking events

As any other conference similar to this one, there were several networking events to meet people and hang out, with catering, bar and music. The main social event was the After Party music concert. This year performer was Logic.

 

F8 After Party

 

PD: Now is the moment to try my new Oculus Go!

Share Button

Read More

Some issues with the One Plus 2

I have been using my new One Plus 2 for 4 days now and I have found a couple of issues that I’m sharing in this post. I have also posted them in the One Plus forum.

These are the versions of the software related to these issues:

Oxygen version: 2.0.1
Android version: 5.1.1
Google Camera version: 2.5.052

1. Multiple camera apps + fingerprint

There are some gestures that can be used to launch some actions when the One Plus 2 is locked. In the settings menu you can enable and disable these gestures. One of these gestures is to open the camera as the following screenshot shows: the camera app opens when you draw an O on the screen.
OnePlus2 gesture settings

When you have more than one app for the same action in Android, like the camera, and you have not selected a default app for that, a dialog is displayed . This dialog lets you decide which app you want to use. The following screenshot shows this scenario when I have to select one of the camera apps that I have installed.

Camera picker

When you use the O gesture on the One Plus 2 to launch the camera app, since there is no default app, the dialog to choose one is displayed. If you unlock the phone using your fingerprint, then right after that, the camera app selector closes and no camera app is launched. If you unlock your phone using other security mechanism then there is no issue.

You can watch this in the next video and notice how the selector appears and then disappears immediately.

2. Google Camera

The One Plus 2 has the One Plus camera app installed, but the Google Camera has some features, like the photo sphere, that I also like to have.
When I tried to take a panorama, it just does not work. It takes one photo, sometimes 2 or 3 photos, and then the app stops taking more. If you try to finish the panorama, it does nothing. When you try to discard the panorama, the app freezes and closes.
Here is the video:

 

Share Button

Read More

Apple Watch battery life

One of the key factors to the adoption of wearables is their battery life.

We already use laptops, smartphones and tablets that we need to charge almost everyday. Having a wearable device like a smartwatch implies one more device to charge. If our smartphone has a low battery level, we can find a place to charge it while we do some other things. With a smartwatch we need to take it off. We can’t check the time while it is charging, at least not just by looking at our wrist.

Battery life is an important feature that we should consider when choosing a smartwatch, so I have measured the battery drain of the Apple Watch. In this post I want to show the results.

These are the specifications of the Apple Watch that I have used for the tests:

Apple Watch Sport
Height: 42.0mm
Width: 35.9mm
Depth: 10.5mm
Case: 30g
White color.

Battery drain

I analyzed the battery drain of the Apple Watch doing a very basic use of it.

This means that I checked the time once in a while and I read some notifications. Nothing more. I didn’t spend time exploring apps from the watch, I didn’t use the maps nor I monitored any type of exercise.
The results indicate that the battery life of the Apple Watch is around 50 hours: a little more than 2 days.
Therefore if you do more actions with the Apple Watch than just simply checking the time or reading notifications, the battery life will be less than 2 days, which means you need to charge it everyday.

The following chart shows the battery drain over time.

Battery chart

Power reserve

When the battery level of the Apple Watch is very low, around 10%, the power reserve mode is started automatically. You can also start this mode in any moment from the Power glance or from the power off menu.

While in the power reserve mode, you can only see the time on the screen along with an icon showing the red battery level icon. The watch doesn’t react to your finger touch and you need to press the physical side button to see the time.

Low power
Apple Watch no battery

When the Apple Watch is in power reserve, the battery drain is much lower. This can be observed in the next chart, where the power reserve mode was enabled during some hours.

Battery level with power reserve

More results

Apple Watch charging
Charging time 
It takes around 120 minutes to charge the Apple Watch completely, that is around 2 hours.

Boot time 
It takes around 1 minute and 10 seconds to boot the Apple Watch.

Share Button

Read More

First look at Apple Watch

In this post I want to show you the first look at Apple Watch. This post includes: pairing the watch with your iPhone, the charger and what happens when the watch is disconnected from the paired iPhone.

My experience is that the Apple Watch is a cool gadget to wear, but I ended up using the phone for everything and the watch only to see the time. The Apple Watch is not really good to check the time, since the screen turns on automatically when you do the movement with your wrist. There are sometimes that I don’t do this movement, or that the watch does not detect it. In these cases, you have to touch the screen with your finger. Anyway the wrist movement detection works really good.

These are the specifications of the Apple Watch that I have used for this post:

Apple Watch Sport
Height: 42.0mm
Width: 35.9mm
Depth: 10.5mm
Case: 30g
White color.

The following image shows the box containing the Apple Watch. Two watch bands with different sizes are included.
Apple Watch in box

 

Pairing the Apple Watch

You need your Apple Watch (of course) and the companion Apple Watch app on your iPhone.
The companion Apple Watch app is available since iOS version 8.2. First make sure that you have updated your device to iOS 8.2 or later. You should see the following Apple Watch icon on your device.

Apple Watch app icon

Once you turn on your Apple Watch, it will ask you to set it up and pair it with your iPhone.
Open the Apple Watch app on your iPhone and follow the steps of the setup assistant. Finally press the “Start Pairing” button on your watch.

Apple Watch start pairing

Both the watch and the phone display a screen indicating the syncing process.

Apple Watch pairing

When the syncing is finished, you’re ready to go!

Apple Watch ready
Apple Watch apps

 

Charging the Apple Watch

The charger is a magnetic charging cable. You only need to place your watch on the charger.
Apple Watch charger

When the battery level of the Apple Watch is very low, around 10%, the power reserve mode is started automatically. You can also start this mode in any moment from the Power glance or from the power off menu.
While in the power reserve mode, you can only see the time on the screen along with an icon showing the red battery level icon. The watch doesn’t react to your finger touch and you need to press the physical side button to see the time.
The following left image shows the watch with low power level. The right image shows the watch while charging.

Apple Watch no battery
Apple Watch charging

 

Disconnected from your iPhone

The Apple Watch needs your iPhone to support most of its features. If the watch can’t communicate with your phone, a red icon is displayed on the top part of the screen as shown in the following image.

Apple Watch out of range

When the phone is out of range, some apps won’t work on the watch.
As shown in the next left image, a red message warns the user that the data was last updated some days ago. The red icon indicating that the phone is not in range is displayed on the top right corner of the watch screen. The right image shows an application with no data at all.

Apple Watch weather
Apple Watch stock

 

This post has explained the first steps when using your Apple Watch. If you want to learn more, check my future posts and here is the link to the Apple Watch User Guide.

Share Button

Read More

iBeacon Sample Project

In this post I want to show you how we can create the simplest iOS app that monitors and ranges devices that follow the iBeacon protocol. An iBeacon device is a BLE (Bluetooth Low Energy) device that transmits its identification information: UUID, major and minor.
You can learn more about iBeacon in this previous post here.

The complete xcode project that is explained in this post can be downloaded from my public github repository here.


Project setup

  1. Create a new empty project in XCode. You can select the Single View Application template.
  2. Enable the permissions needed to use the Core Location services. To do this, add the following two properties in the .plist file of your app:

    NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription.

    Here is an example of these two properties:

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Location is needed to monitor Beacons in range</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Location is needed to monitor Beacons in range</string>
    

My Location Manager

  1. Create the class that will manage all the beacon events: MyLocationManager.
  2. Import the CoreLocation library in the .h file of your new class:
    #import <CoreLocation/CoreLocation.h>
  3. The MyLocationManager class is going to implement the CLLocationManagerDelegate protocol to receive the beacon events:
    @interface MyLocationManager : NSObject <CLLocationManagerDelegate>
  4. The MyLocationManager class also needs two methods so the app can start/stop monitoring iBeacons. Add these methods to the interface:
    
    - (void)startMonitoringUUID:(NSString *)uuid;
    
    - (void)stop;
    
    

Monitoring iBeacons

  1. Open the implementation .m file of our MyLocationManager class and add a private property to keep an instance of the iOS system CLLocationManager class.
    @interface MyLocationManager ()
    @property (strong,nonatomic) CLLocationManager *locationManager;
    @end
    
  2. Implement the start method.
    - (void)startMonitoringUUID:(NSString *)uuid
    {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
    
        // Request permission (mandatory iOS8 + info.plist)
        if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
            [self.locationManager requestAlwaysAuthorization];
    
        CLBeaconRegion *region = [[CLBeaconRegion alloc]
           initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:uuid]
           identifier: uuid];
    
        [self.locationManager startMonitoringForRegion:region];
    }
    

    Line 3. Create an object of the CLLocationManager class.
    Line 4. Set our MyLocationManager object as its delegate.
    Line 7-8. Request permission.
    Line 10-12. Create a region with the UUID received as parameter.
    Line 14. Start monitoring for the recently created region.

  3. Implement the delegate method to receive the iBeacon events. For this small sample app, iBeacon events are just printed to the app log:
    - (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
    {
        switch (state) {
            case CLRegionStateInside:
                NSLog(@"locationManager didDetermineState INSIDE for %@", region.identifier);
                break;
    
            case CLRegionStateOutside:
                NSLog(@"locationManager didDetermineState OUTSIDE for %@", region.identifier);
                break;
    
            default:
                NSLog(@"locationManager didDetermineState OTHER for %@", region.identifier);
        }
    }
    
  4. Finally implement the stop method:
    - (void)stop
    {
        for(id region in self.locationManager.monitoredRegions) {
            [self.locationManager stopMonitoringForRegion:region];
        }
    }
    

Ranging iBeacons

  1. Add the code to start ranging. A good approach is to start ranging once it has been detected that the user is inside a region. This code is added in the locationManager:didDetermineState:forRegion method:
    - (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
    {
        switch (state) {
            case CLRegionStateInside:
                NSLog(@"locationManager didDetermineState INSIDE for %@", region.identifier);
                [self.locationManager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
                break;
    
            case CLRegionStateOutside:
                NSLog(@"locationManager didDetermineState OUTSIDE for %@", region.identifier);
                break;
    
            default:
                NSLog(@"locationManager didDetermineState OTHER for %@", region.identifier);
        }
    }
    
  2. Add the code to stop ranging. A good approach is to stop ranging when it is detected that the user is outside a region. This code is added in the locationManager:didDetermineState:forRegion method:
    - (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
    {
        switch (state) {
            case CLRegionStateInside:
                NSLog(@"locationManager didDetermineState INSIDE for %@", region.identifier);
                [self.locationManager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
                break;
    
            case CLRegionStateOutside:
                NSLog(@"locationManager didDetermineState OUTSIDE for %@", region.identifier);
                [self.locationManager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
                break;
    
            default:
                NSLog(@"locationManager didDetermineState OTHER for %@", region.identifier);
        }
    }
    
  3. Finally implement the delegate method to receive the iBeacon ranging events. These ranging events are just printed to the app log:
    - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
    {
        if(beacons != nil && (0 < beacons.count)) {
            for(CLBeacon *b in beacons) {
                NSLog(@"%@/%@ %ld", b.major, b.minor, b.proximity);
            }
        }
    }
    

The complete xcode project that has been explained in this post can be downloaded from my public github repository here.

Share Button

Read More

Introduction to iBeacon

The iBeacon standard is an extension of iOS Location Services. An iBeacon device is a BLE (Bluetooth Low Energy) device that transmits its identification information: UUID, major and minor. This information is hierarchical and the UUID is the beacon’s principal identifier.
The iBeacon functionality provided by iOS allows two types of actions:

  • Region Monitoring. Notifies when the user has entered the specified region.
  • Beacon Ranging. Determines the estimated proximity to the beacons in range: Immediate, Near, Far or Unknown.

A Region in iBeacon terms is a network of iBeacons defined by a shared identifier. A region can be specified by its UUID, major and minor. Major and minor identifiers are optional for a region, but the UUID is necessary.

iOS limits to 20 the number of regions that may be simultaneously monitored by a single app.

For example, if only the UUID is specified for a region, all the iBeacons with that UUID will be considered part of that region.

Beacons inside a UUID region

If we specify the UUID and also a major value for the region, then only the iBeacons with that UUID and major are considered as part of that region.

Beacons inside a UUID+major region

Once a region has been detected, the details of the iBeacons in range inside that region are obtained by ranging, not by monitoring.

Background detection

While the app is running in the foreground it can range to determine the signal strength between the iBeacons and the device. This ranging process is not allowed while the app is not running in the foreground. Only monitoring is allowed while the app is in the background/not running.
Region monitoring is capable of waking the app up from running in the background/not running when the app enters or exits the region. These are the only triggers that will wake the app from running the background/not running: entering or exiting a region. Once the app is awoken it can run for ~10 seconds if closed completely and ~2 minutes if it is running in the background.

Core Location Framework

iBeacon APIs are available in the Core Location Framework. The central point of this framework is the CLLocationManager class. An instance of this class is necessary to start/stop the location services, to configure them, and to receive the related events.
The CLLocationManager reference can be found here.

Share Button

Read More

Refresh data in a custom Android Adapter

An Adapter is an object that provides data to certain components like a ListView object or a Spinner object. There are distinct classes that implement the Adapter class, such as ArrayAdapter, which loads an array of objects. We can create a custom adapter that extends the ArrayAdapter class to create custom items.
Let’s say that we want to display Event objects in a ListView. This is our custom adapter:

public class MyCustomAdapter extends ArrayAdapter<MyEvent> {
    private final Context context;
    private List<MyEvent> events;

    public MyCustomAdapter(Context context, int layoutResourceId, List<MyEvent> events) {
        super(context, layoutResourceId, data);
        this.context = context;
        this.events = events;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Custom view
    }
}

In the constructor method, the adapter saves the list of objects that will be displayed in the view. If we want to refresh/change this data after creating the adapter, add a new method to the adapter:

public void refreshEvents(List<MyEvent> events) {
    this.events.clear();
    this.events.addAll(events);
    notifyDataSetChanged();
}

This refresh method clears all the data from the list and updates it with new data. Alternatively you can create different methods to add or remove items. In any case, the most important part is to invoke the notifyDataSetChanged method. The notifyDataSetChanged method notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.

Finally, from the activity or fragment that contains the list, invoke the previous method with the new data:

mAdapter.refreshEvents(newListOfEvents);

Consider the case in which the refresh method is not called from the UI thread. For example, if the data is updated after a server request:

getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        mAdapter.refreshEvents(newListOfEvents);
});
Share Button

Read More

Custom color in Action Bar + Drawer

A navigation drawer is a common structure for the top-level of our Android app. A drawer provides a safe start point of return with which users can easily understand the application structure.

Using Android Studio, we can create a project from the template of an activity with a navigation drawer:

Create navigation drawer activity

A navigation drawer can be opened by a button placed in the top action bar or by swipe gestures. The default action bar for the drawer contains the icon button that opens/closes it, which is known as the toggle button. The action bar, the title and the button have their own default colors.

Default Action Bar

To change the default action bar with our custom colors, we need to change the styles xml file of our app, which initially only contains the base app theme:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
 
</style>

Under the style of our custom app theme, we need to add an item for the action bar and an item for the drawer toggle icon (arrow):

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:actionBarStyle">@style/MyActionBar</item>
    <item name="drawerArrowStyle">@style/MyDrawerArrowToggle</item>

    <!-- Support library compatibility -->
    <item name="actionBarStyle">@style/MyActionBar</item>
</style>

We also need to add the new colors that we are going to use. These color tags are placed outside the style tag.

<color name="background">#ff82B548</color>
<color name="foreground">@android:color/white</color>

Let’s define each one of these items. Firstly, the custom color for the toggle button:

<style name="MyDrawerArrowToggle" parent="Widget.AppCompat.DrawerArrowToggle">
    <item name="color">@color/foreground</item>
</style>

Secondly, the custom background color of the action bar and also the title text style:

<style name="MyActionBar" parent="@style/Widget.AppCompat.ActionBar">
    <item name="android:titleTextStyle">@style/MyTitleTextStyle</item>
    <item name="android:background">@color/background</item>

    <!-- Support library compatibility -->
    <item name="titleTextStyle">@style/TitleTextStyle</item>
    <item name="background">@color/background</item>
</style>

Finally, the title text style is defined as follows:

<style name="MyTitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
    <item name="android:textColor">@color/foreground</item>
</style>

And here it is the result:

Custom Action Bar

Share Button

Read More

Swipe gestures in a UITableView

When we have a UITableView, sometimes we want to add some actions when the user swipes over a row of the table. We can capture swipes to the left, right, down or up directions.
To capture both left and right swipe gestures, add the following code to your UITableViewController in the viewDidLoad method.

UISwipeGestureRecognizer *gestureLeft = [[UISwipeGestureRecognizer alloc] 
     initWithTarget:self 
     action:@selector(handleSwipeLeft:)];
[gestureLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.tableView addGestureRecognizer:gestureLeft];
    
UISwipeGestureRecognizer *gestureRight = [[UISwipeGestureRecognizer alloc] 
     initWithTarget:self 
     action:@selector(handleSwipeRight:)];
[gestureRight setDelegate:self];
[gestureRight setDirection:UISwipeGestureRecognizerDirectionRight];
[self.tableView addGestureRecognizer:gestureRight];

The action parameter indicates the method that will be executed when the gesture is recognized. We have to include these methods in our controller too.


- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
    
    // Action...
}

- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
    
    // Action...
}

The method locationInView returns the location of the gesture, represented as a point in the local coordinate system of the view. Using the indexPathForRowAtPoint method of the UITableView object, we can obtain the row of the gesture.

We could use also the same action method to handle all the swipe gestures. Change the action methods from handleSwipeLeft and handleSwipeRight to handleSwipe, and add the following method instead.

- (void)handleSwipe:(UISwipeGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];

    switch ([gestureRecognizer direction]) {
        case UISwipeGestureRecognizerDirectionLeft:
            // Action
            break;
        case UISwipeGestureRecognizerDirectionRight:
            // Action
            break;
        default:
            break;
    }
}
Share Button

Read More