Page Example

Lockscreen Sample Overview

Mobile native

The Lockscreen sample application demonstrates how to implement the screen locking mechanism. The application interface consists of a main window and a simple swipe lock displayed over it. It enables the user to unlock the screen by swiping up or down.

The following figures show the user interface hierarchy and the unlock sequence where the lock is being swiped upwards.

Figure: User interface hierarchy

User interface hierarchy

Figure: Unlock sequence

Screen is locked Lock is swiped Lock is swiped further Screen is unlocked

To make this application work, the user must select it as a default lockscreen through the Settings menu.

Prerequisites

This application requires the following privileges to be set:

  • http://tizen.org/privilege/keymanager
  • http://tizen.org/privilege/display

This application also has a special category attribute set in the tizen-mainfest.xml file:

<ui-application appid="packageName" auto-restart="true" exec="appName" multiple="false" 
                nodisplay="true" on-boot="true" taskmanage="false" type="capp">
   <!--Common application attributes-->
   <category name="http://tizen.org/category/lockapp"/>
</ui-application>

Implementation

The application follows the MVC pattern. Aside from the standard native application module with the main() function, it consists of the following components:

  • controller.c module
  • settings.c module serving as a model
  • main_window.c, lock.c, and swipe_lock.c modules serving as views

The application initialization takes place with the start_application() function. This function creates the main window and sets the current lock type based on user preferences. It also sets the current lockscreen background. But most of all, it registers callbacks for the following events:

  • Successful unlock using swipe gesture
  • Lockscreen background change (using the Settings application)
  • Display state change
bool
start_application(void)
{
   if (!create_main_window())
   {
      // Error handling
   }

   __set_current_lock();
   // Add a controller swipe callback to the main window
   add_main_window_callbacks(__swipe_unlocked_cb);
   // Add a lockscreen background image change callback, the image is selected in Settings application
   __wallpaper_changed_cb(SYSTEM_SETTINGS_KEY_WALLPAPER_LOCK_SCREEN, NULL)
   // Add a callback for the background change (also changed using the Settings application)
   system_settings_set_changed_cb(SYSTEM_SETTINGS_KEY_WALLPAPER_LOCK_SCREEN, __wallpaper_changed_cb, NULL);
   // Add a callback to listen to LCD on/off events
   device_add_callback(DEVICE_CALLBACK_DISPLAY_STATE, __device_cb, NULL);

   return true;
}

Activating the Lock

To activate the lockscreen:

  1. Each time the LCD display is switched on, the currently selected lock type is activated through the __device_cb() callback function:
    static void
    __device_cb(device_callback_e type, void *value, void *user_data)
    {
       switch ((display_state_e)value)
       {
          case DISPLAY_STATE_NORMAL:
             __set_current_lock();
             break;
          case DISPLAY_STATE_SCREEN_DIM:
             break;
          case DISPLAY_STATE_SCREEN_OFF:
             break;
          default:
             __set_current_lock();
             break;
       }
    }
    
  2. The get_lock_type() model function is used to obtain the current lock type.

    With this sample application, you can add other types of lock implementations of your own. To do that, modify the lockscreen_type_t enumeration type.

    static void
    __set_current_lock(void)
    {
       switch (settings_get_lock_type())
       {
          case LOCKSCREEN_NONE:
             deactivate_main_window_swipe_lock();
             break;
          case LOCKSCREEN_SWIPE:
             activate_main_window_swipe_lock();
             break;
          default:
             break;
       }
    }
    
  3. The user interface is created with the create_main_window() function. It consists of a background and a swipe lock view.
    bool
    create_main_window(void)
    {
       s_main_window_data.win = elm_win_add(NULL, PACKAGE, ELM_WIN_DOCK);
    
       // Error handling
    
       // Common window settings
    
       // Default alpha is 0
       elm_win_alpha_set(s_main_window_data.win, EINA_TRUE);
    
       evas_object_smart_callback_add(s_main_window_data.win, "delete,request", __delete_cb, NULL);
    
       if (!__create_background(s_main_window_data.screen_width, s_main_window_data.screen_height) ||
          // Create the swipe lock to cover the entire window
          !__create_swipe(s_main_window_data.screen_width, s_main_window_data.screen_height)
       {
          return false;
       }
    
       // Show the window after the base GUI is set up
       evas_object_show(s_main_window_data.win);
    
       return true;
    }
    

Unlocking the Device

To unlock the device:

  1. The controller module uses the add_main_window_callbacks() function to register its callbacks for the user interface. Consequently, the module is notified whenever the user successfully unlocks the device with a swipe gesture, and the __swipe_unlocked_cb() function is invoked.
    void
    add_main_window_callbacks(swipe_unlock_cb unlock_cb)
    {
       if (!s_main_window_data.swipe_unlock_cb || unlock_cb)
       {
          _add_swipe_lock_callbacks(s_main_window_data.swipe_lock, __swipe_drag_cb, __swipe_drag_end_cb);
          s_main_window_data.swipe_unlock_cb = unlock_cb;
       }
    }
    
    static void
    __swipe_unlocked_cb(void)
    {
       deactivate_main_window_swipe_lock();
    }
    
  2. After a successful swipe, the swipe lock is deactivated using the deactivate_main_window_swipe_lock() function:
    void
    deactivate_main_window_swipe_lock(void)
    {
       // Hide the swipe lock UI object
       evas_object_hide(s_main_window_data.swipe_lock);
       // Hide the main application window
       evas_object_hide(s_main_window_data.win);
    }
    

Creating the Lockscreen View

The swipe lock view is created as the elm_layout in the _create_lock() function (called from the _create_swipe_lock() function). One of its parameters is the layout edj file name.

The _create_lock() function associates the elm_layout with the EDJE.

Evas_Object *_create_lock(Evas_Object *parent, const char *edje_file_name)
{
   char layout_file_full_path[PATH_MAX] = {0,};

   Evas_Object *lock = elm_layout_add(parent);

   // Error handling

   compile_resource_path(edje_file_name, layout_file_full_path);

   if (!elm_layout_file_set(lock, layout_file_full_path, LOCK_MAIN_GROUP))
   {
      // Error handling
   }

   return lock;
}

Evas_Object *
_create_swipe_lock(Evas_Object *parent)
{
   return _create_lock(parent, SWIPE_LOCK_EDJ_FILE_NAME);
}

The following example is the related EDJE file:

#include "edje_definitions.h"

styles
{
   style
   // main_text_style applies to MAIN_TEXT_PART of TEXTBLOCK type
   // Its syntax is very similar to HTML
   {
      name: "main_text_style";
      base: "font="default" font_size=60 align=center color=#ffffffff style=shadow,bottom shadow_color=#000000ff wrap=mixed";
   }
}

collections
{
   group
   {
      name: LOCK_MAIN_GROUP;
      parts
      {
         part
         {
            name: BACKGROUND_PART;
            type: RECT;
            description
            {
               // This is the default state description for the BACKGROUND_PART
               // The BACKGROUND_COLOR constants are defined in "edje_definitions.h"
               state: "default" 0.0;
               color: BACKGROUND_COLOR_R BACKGROUND_COLOR_G BACKGROUND_COLOR_B BACKGROUND_COLOR_A;
               visible: 1;
               // The background spans over the entire layout (which is the size of the main window):
               rel1.relative: 0.0 0.0;
               rel2.relative: 1.0 1.0;
            }
            // The BACKGROUND_PART is given a special attribute and it can be dragged all over the screen
            // x and y axis attribute properties' meanings are: 
            // 1st: enable(1)/disable(0) movement, 2nd: step, 3rd is not used in this application
            // See https://docs.enlightenment.org/stable/efl/edcref.html#sec_collections_group_parts_dragable for more information

            dragable
            {
               x: 0 0 0;
               y: 1 1 0;
            }
         }

         part
         {
            name: MAIN_TEXT_PART;
            type: TEXTBLOCK;
            repeat_events: 1;
            description
            {
               // This is default state description for MAIN_TEXT_PART
               // SWIPE_MAIN_TEXT_PART_REL constants are defined in "edje_definitions.h"
               // MAIN_TEXT_PART is the text you can see in the "Unlock sequence" figure
               // Note that although only the BACKGROUND_PART is draggable, the MAIN_TEXT_PART moves with it too
               // This is because the MAIN_TEXT_PART keeps its relative position to the BACKGROUND_PART all the time
               state: "default" 0.0;
               rel1.relative: SWIPE_MAIN_TEXT_PART_REL1_X SWIPE_MAIN_TEXT_PART_REL1_Y; rel1.to: BACKGROUND_PART;
               rel2.relative: SWIPE_MAIN_TEXT_PART_REL2_X SWIPE_MAIN_TEXT_PART_REL2_Y; rel2.to: BACKGROUND_PART;
               text
               {
                  style: "main_text_style";
                  text: SWIPE_MAIN_TEXT_PART_TEXT;
               }
            }
         }
      }

      programs
      {
         program
         {
            // The EDJE script contains a program to reset a draggable part to its initial position
            // Normally, when the user stops dragging the BACKGROUND_PART, it does not go back to its original position 
            // The program is triggered from the swipe_lock_drag_reset() function (see below)
            name: "reset_initial_position";
            signal: SWIPE_RESET_SIGNAL;
            source: SWIPE_RESET_SIGNAL_SOURCE;
            action: DRAG_VAL_SET 0.0 0.0;
            target: BACKGROUND_PART;
         }
      }
   }
}
void
_reset_swipe_lock_drag(Evas_Object *swipe_lock)
{
   elm_layout_signal_emit(swipe_lock, SWIPE_RESET_SIGNAL, SWIPE_RESET_SIGNAL_SOURCE);
}