dimanche 6 octobre 2013

Joyn or RCS

RCS (Rich Communication Services) is a GSMA standard that aims to bring a set of rich communication (that goes beyond SMS and phone calls) yet inter-operable services  across different domains managed by different telecom operators. This telcos standard is marketed under the name of Joyn.
Many operators has already deployed on their networks offering users VoIP and presence services that can be accessed by installing an application from the market store (Google Play, AppStore). In addition, some smarphone manufacturers who have joined the movement already embed the RCS stack into their devices.

The next step of commercializing Joyn is to build an ecosystem by providing APIs and empowering the developers community to create communication-based applications that relies on the platform. Orange through Orange Partner and Deutsch Telekom through the Developer Garden programs are leading these efforts in Europe. For instance, they jointly sponsored the Joyn Hackathon (press release) were the Joyn API  was introduced.

The remaining of this post explains how to use the Android Joyn SDK to build conversational applications. The overall interaction between an application and the Joyn SDK (and behind the RCS platform) is explained in the following figure.
Joyn API call flow

  1. Instantiate Joyn service and establish a connection
   private ChatService mService;
   private JoynServiceListener mListener = new JoynServiceListener() {
      @Override public void onServiceDisconnected(int error) {
         Log.i(TAG, "ChatService disconnected!");
      }
      @Override public void onServiceConnected() {
         Log.i(TAG, "ChatService connected!");
      }
   };
   ...
   // Instanciate API
   mService = new ChatService(getApplicationContext(), mListener); 
   // Connect API
   mService.connect();
  1. When the the connection is successfully established then start calling API methods
   private Chat mChat;
   private ChatListener mChatListener = new ChatListener() {
      @Override public void onReportMessageFailed(String arg0) {}
      @Override public void onReportMessageDisplayed(String arg0) {}
      @Override public void onReportMessageDelivered(String arg0) {}
      @Override public void onNewMessage(ChatMessage arg0) {}
      @Override public void onComposingEvent(boolean arg0) {}
   };
   ...
   @Override public void onServiceConnected() {
      Log.i(TAG, "ChatService connected!");
      if (mService != null && mService.isServiceRegistered()) {
         // Get remote contact
         String contact = getIntent().getStringExtra("contact");
         // Call API Methods
         mChat = mService.openSingleChat(contact, mChatListener); 
         mChat.sendMessage("hello world!");
      }
   }
The API doc of the ChatService can be found on this link.

dimanche 9 juin 2013

Adding search capabilities to an Android application

To set up a search assistant in an application, you need to go through the following steps :
  • Define a searchable configuration: An XML file that configures some settings for the search dialog or widget. It includes settings for features such as hint text, search suggestion, voice search, etc.
  • A searchable activity that will receive the search query, to perform the search on the application data data, then to display the results.
  • A search interface, provided by either: a search dialog that will appear at the top of the screen when the user presses the device SEARCH button (if available), it can also called programmatically from the code, or a SearchView widget.
First, the XML searchable configuration res/xml/searchable.xml:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.fontself.sms.provider.ContactProvider"    
    android:searchSuggestIntentAction="android.intent.action.VIEW">
</searchable> 

Second, the ContentProvider that will be called by the Android system to perform search:
public class MyContentProvider extends ContentProvider {
   public static String AUTHORITY = "com.app.package.MyContentProvider";
   private static final int SEARCH_SUGGEST = 0;
   private static final int SHORTCUT_REFRESH = 1;
   private static final UriMatcher sURIMatcher = buildUriMatcher();

   private static final String[] COLUMNS = {
      "_id",  // must include this column
      SearchManager.SUGGEST_COLUMN_TEXT_1,
      SearchManager.SUGGEST_COLUMN_TEXT_2,
      SearchManager.SUGGEST_COLUMN_INTENT_DATA,     
   };
   private static UriMatcher buildUriMatcher() {
      UriMatcher matcher =  new UriMatcher(UriMatcher.NO_MATCH);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, SHORTCUT_REFRESH);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", SHORTCUT_REFRESH);
      return matcher;
   }
   @Override public String getType(Uri uri) {
      switch (sURIMatcher.match(uri)) {  
      case SEARCH_SUGGEST:
         return SearchManager.SUGGEST_MIME_TYPE;
      case SHORTCUT_REFRESH:
         return SearchManager.SHORTCUT_MIME_TYPE;
      default:
         throw new IllegalArgumentException("Unknown URL " + uri);
      }
   }
   @Override public boolean onCreate() {  
      return false;
   }
   @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {  
      if (!TextUtils.isEmpty(selection)) {
         throw new IllegalArgumentException("selection not allowed for " + uri);
      }
      if (selectionArgs != null && selectionArgs.length != 0) {
         throw new IllegalArgumentException("selectionArgs not allowed for " + uri);
      }
      if (!TextUtils.isEmpty(sortOrder)) {
         throw new IllegalArgumentException("sortOrder not allowed for " + uri);
      }
      switch (sURIMatcher.match(uri)) {
         case SEARCH_SUGGEST:
            String query = null;
            if (uri.getPathSegments().size() > 1) {
               query = uri.getLastPathSegment().toLowerCase();
            }
            return getSuggestions(query, projection);
         case SHORTCUT_REFRESH:
            String shortcutId = null;
            if (uri.getPathSegments().size() > 1) {
               shortcutId = uri.getLastPathSegment();
            }
            return refreshShortcut(shortcutId, projection);
         default:
            throw new IllegalArgumentException("Unknown URL " + uri);
      }  
   }
   private Cursor getSuggestions(String query, String[] projection) {
      String processedQuery = query == null ? "" : query.toLowerCase();
      List<MyObject> rows = doSearch(processedQuery);
        
      MatrixCursor cursor = new MatrixCursor(COLUMNS);
      for (MyObject row : rows) {
          cursor.addRow(columnValuesOfWord(row));
      }        
      return cursor;
   }
   private Object[] columnValuesOfWord(MyObject obj) {
      return new String[] {
         obj._id,    // _id
         obj.name,   // text1
         obj.phone,  // text2
         obj.phone,  // intent_data (included in the Intent when clicking on item)
      };
   }
   private Cursor refreshShortcut(String shortcutId, String[] projection) {
      return null;
   }
    
   @Override public Uri insert(Uri uri, ContentValues values) {
      throw new UnsupportedOperationException();
   }

   @Override public int delete(Uri uri, String selection, String[] selectionArgs) {
      throw new UnsupportedOperationException();
   }

   @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
      throw new UnsupportedOperationException();
   }
}

Third, define the SearchActivity:
public class MySearchActivity extends ListActivity {
   public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
   //setContentView(R.layout.search);  
        setListAdapter(new MyAdapter.getInstance(MySearchActivity.this));
        handleIntent(getIntent());  
   } 

   @Override protected void onNewIntent(Intent intent) { 
      setIntent(intent); 
      handleIntent(intent);  
   } 

   public void onListItemClick(ListView l, View v, int position, long id) {       
      // call detail activity for clicked entry     
   } 

   private void handleIntent(Intent intent) {    
      if (Intent.ACTION_SEARCH.equals(intent.getAction())) {            
         // Handle the normal search query case
         String query = intent.getStringExtra(SearchManager.QUERY);            
         doSearch(query);       
      } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
         // Handle a suggestions click (because the suggestions all use ACTION_VIEW)
         Uri data = intent.getData();
         showResult(data);
      }
   }    
   
   private void showResult(Uri data) {}

   private void doSearch(String queryStr) {    
      // get a Cursor, prepare the ListAdapter and set it
   } 

}
Finally, update the AndroidManifest.xml file:
<application>
<meta-data android:name="android.app.default_searchable" android:value=".MySearchActivity" />
     <activity android:name=".MySearchActivity" android:label="@string/app_name" android:launchMode="singleTop" > 

<!-- enable the search dialog to send searches to MessageActivity -->       
         <intent-filter >
             <action android:name="android.intent.action.SEARCH" /> 
        </intent-filter> 
        <intent-filter > 
           <action android:name="android.intent.action.VIEW" /> 
        </intent-filter> 
        <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />

     </activity>
<provider android:name=".MyContentProvider" android:authorities="com.app.package.MyContentProvider" />
</application>

Resources

For more details check official documentation on ContentProvider, Search dialogs, how to implement custom suggestions, and how to use recent search suggestions. In case, you are using ActionBarSherlock check this blog post.
You may also have to check the SearchableDitionary sample project that comes with the Android SDK.

dimanche 19 mai 2013

Sample Android OAuth client

OAuth is the Internet protocol that gives you an authorized access to resources on the Internet without grating user credentials. It has been deployed by many services like Twitter, Google, Yahoo or LinkedIn. And there are some libraries / code snippet in most every programming language that implement OAuth, but it is still hard to get it work (at least on Android).
Here is a sample code snippets based on the Signpost library that uses a custom WebView to intercept HTTP calls and handle them.
First the OAuthHelper.java the helper class:
private Context mContext;
private OAuthConsumer mConsumer;
private OAuthProvider mProvider;
private String mCallbackUrl;
private SharedPreferences mSettings;
private OAuthListener mListener;

public OAuthHelper(Context context, String consumerKey, String consumerSecret) {
   if ((consumerKey == null || "".equals(consumerKey)) && (consumerSecret == null || "".equals(consumerSecret))) {
      throw new IllegalArgumentException("You must specify your \"consumer Key\" and your \"consumer Secret\" when instantiating a OAuthHelper object");
   }
   mContext = context;
   mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
   mProvider = new CommonsHttpOAuthProvider(QypeConstants.REQUEST_TOKEN_URL, QypeConstants.ACCESS_TOKEN_URL, QypeConstants.AUTHORIZE_URL);
   mProvider.setOAuth10a(true);
   mCallbackUrl = QypeConstants.REDIRECT_URI;
     
   mSettings = context.getSharedPreferences(QypeConstants.PREFS_NAME, 0);
}

public void authorize(OAuthListener listener) 
   throws OAuthMessageSignerException, OAuthNotAuthorizedException, OAuthExpectationFailedException, OAuthCommunicationException {

   mListener = listener;
   OAuthLoginDialog oauthDialog = new OAuthLoginDialog(mContext, this);
   oauthDialog.loadUrl(getRequestToken());
   oauthDialog.show();
}

public String getRequestToken() 
   throws OAuthMessageSignerException, OAuthNotAuthorizedException,
   OAuthExpectationFailedException, OAuthCommunicationException {
   String authUrl = mProvider.retrieveRequestToken(mConsumer, mCallbackUrl);
   return authUrl;  
}

public String[] getVerifier(String uriString) {       
   return getVerifier(Uri.parse(uriString));
}

public String[] getVerifier(Uri uri) {
   // extract the token if it exists     
   if (uri == null) {
      return null;
   }
   String token = uri.getQueryParameter("oauth_token");
   String verifier = uri.getQueryParameter("oauth_verifier");
   return new String[] { token, verifier };
}

public String[] getAccessToken() {
   String access_token = mSettings.getString(ACCESS_TOKEN, null);
   String secret_token = mSettings.getString(SECRET_TOKEN, null);
   if(access_token==null || secret_token==null)
      return null;
   return new String[] {access_token, secret_token};
}

public void getAccessToken(final String verifier) {
   new Thread(new Runnable() {   
      public void run() {
         try {
            mProvider.retrieveAccessToken(mConsumer, verifier);
            mSettings.edit().putString(ACCESS_TOKEN, mConsumer.getToken()).commit();
            mSettings.edit().putString(SECRET_TOKEN, mConsumer.getTokenSecret()).commit();
            mListener.onOAuthComplete();     
         }catch(Exception e) {            
            e.printStackTrace();
         }
      }
   }).run();
}

public String request(String url) {
   String content = null;
   try {
       String accessToken[] = getAccessToken();
       mConsumer.setTokenWithSecret(accessToken[0], accessToken[1]);   
       HttpGet request = new HttpGet(url);
       // sign the request
       mConsumer.sign(request);
       // send the request
       HttpClient httpClient = new DefaultHttpClient();
       HttpResponse response = httpClient.execute(request);   
       content = EntityUtils.toString(response.getEntity());
   } catch (Exception e) {
       e.printStackTrace(); 
   }
   return content;
}
Second, the OAuthLoginDialog.java that will be used to intercept HTTP call back url
public class OAuthLoginDialog extends Dialog {
   private WebView mWebView;
   private OAuthHelper mHelper;

   public OAuthLoginDialog(Context context, OAuthHelper helper) {
      super(context);
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      setContentView(R.layout.login_dialog);

      LayoutParams params = getWindow().getAttributes();
      params.height = LayoutParams.MATCH_PARENT;
      params.width = LayoutParams.MATCH_PARENT;
      getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);

      mHelper = helper;

      init();
   }
   private void init() {
      mWebView = (WebView) findViewById(R.id.webView);
      mWebView.getSettings().setJavaScriptEnabled(true);

      mWebView.setWebViewClient(new WebViewClient() {
         @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {}
         @Override public void onPageStarted(WebView view, String url, Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
             progressBar.setVisibility(View.VISIBLE);
             if(url.startsWith(REDIRECT_URI)) {
                if(mHelper.getAccessToken() == null) {
                   String[] token = mHelper.getVerifier(url);
                   mHelper.getAccessToken(token[1]);
                }     
                mWebView.clearCache(true);
                dismiss();
             } 
         }

         @Override public void onPageFinished(WebView view, String url) {
             super.onPageFinished(view, url);
             progressBar.setVisibility(View.GONE);
         }

      });

   }
 
   public void loadUrl(String url) {
      mWebView.loadUrl(url);
   }
}
Third, the OAuth listener interface
public interface OAuthListener {
   // Called when the user is logged to the server
   public void onOAuthComplete();
   // Called when the user has canceled the login process
   public void onOAuthCancel();
   // Called when the login process has failed
   public void onOAuthError(int errorCode, String description, String failingUrl);
}
Finally, this is the code used to initiate an OAuth connection
OAuthHelper mHelper = new OAuthHelper(mContext, API_KEY, API_SECRET);
mHelper.authorize(new OAuthListener() {    
   public void onOAuthError(int errorCode, String description, String failingUrl) {}
   public void onOAuthComplete() {
      String testUrl = "http://sample_url_for_oauth_authorization/";
      mHelper.request(testUrl)
   }    
   public void onOAuthCancel() {}
});  
More resources can be found here implementing client side OAuth for android (it uses intent filter instead of a custom dialog) and here a sample OAuth for twitter.

Get the code for a sample project on Github.

jeudi 9 mai 2013

Stuff for Android

Build systems

Buck by facebook: a build system for Android that encourages the creation of small, reusable modules consisting of code and resources. Not yet supported on windows !
It was presented by Simon Stewart at GTAC 2013 (Google Test Automation Conference) How Facebook Tests Facebook on Android.

Gradle Android build, a presentation will be held on Google IO.

Open source libraries

Android Bootstrap A presentation about common libraries.

Testing rocks debuging sucks

AndroidMock a framework by Google for mocking Android interfaces/classes based on EasyMock syntax.
BoundBox provides access to all fields, constructor and methods (public or not) of a Class for Unit-testing without having to modify the latter.

Design patterns

Libraries for the Action bar UI design patter:
Object Pool pattern for better performance: discussion, Pools.java, a sample.

User Interface Design

  • Blur effect for Android design (just like in the Path app).
  • How to make the ChatHead feautre as available on the Facebook Messenger.
  • A blog post describing how to make counters on the navigation drawer.

Random stuff

Sample downloader by commonsguy showing the using of handlers/messanger to communicate between Service and the main thread.
User authentication.
Which IDE: eclipse vs InteliJ.
The dumpsys commands with Android adb

mardi 16 avril 2013

Compte Rendu MARAMMI 2012


Ci-après quelques notes prises sur les différents présentations lors de la conférence MARAMI 2012.


Réseaux dynamiques : de l’analyse à la modélisation
Au début de la journée Alain Barrat parlait sur les réseaux dynamiques qui sont un type de réseaux dont les arcs entre nœuds change dynamiques (ex. sont créé et détruit dynamiquement dans le temps). L’utilisation de ces graphes a été dans le cadre d’une étude des interactions physiques (ex. durée de l’interaction) entre plusieurs personnes dans différentes contexte (ex. hôpital, musée, conférence). Pour capturer des informations sur personnes qui étaient en interaction, un dispositif particulier a été utilisé (aussi il est breveté !). Les capteurs sont en forme de badges à base de RFID afin de détecter le badge de l’autre personne en face, ils disposaient d’émetteur radio pour remonter à chaque intervalle (ex. 20s) les identifiants des badges de personne en face. Une fois les infos agrégés, ils sont analysés pour mesurer la durée des interactions.
Les applications peuvent être par exemple détection d’étudiant d’une même classe.
Plus d’information sur http://www.sociopatterns.org/

En pause, j’ai parlait avec un doctorant qui bossait sur les réseaux sociaux, ils avaient un graphe de Twitter (>20M de nœuds et >1G d’arcs) l’étude est basique en terme d’opération sur les graphes mais la difficulté réside dans la gestion des données (sauvegarde sur une base + parcours). Apparemment, la base graphe par excellence Neo4j (que j’ai utilisé pour l’intégration avec l’ASE) ne peut supporter de tels volumes, du coup ils ont optés pour une base plus performantes Dex Graph DB.

Triclustering pour la détection de structures temporelles dans les graphes
Un thésard d’Orange Labs présentait une méthode clustering basé sur la transformation (synthétisation) de graphes à un graphe image (après regroupement de nœuds).
Dans l’état de l’art, il a présenté la technique de base appelée « Blockmodeling » qui consiste à représenter le graphe en matrice ensuite réorganiser les lignes/colonnes pour faire apparaître des blocs représentant les nœuds à regrouper.
L’expérimentation a été menée sur des stations vélib de Londres, ou différentes stations ont été regroupées selon leur profil (i.e. débit de vélo sortant).

Supervised rank aggregation approach for link prediction in complex networks
Le but de l’étude est de prédire des liens entre nœuds, ce qui peut être utilisé dans des la recommandation.
La présentation était théorique car s’agit d’une proposition d’algo.

Détection de communauté dans les réseaux de téléphonie mobile
Vincent Blondel (UCL) présentait la méthode de Louvain qui l’a développé pour le partitionnement (clustering) de graphe. Cette méthode est devenue très utilisée dans la détection de communauté dans un graphe (ex. LinkedIn InMaps). Elle est implémentée par plusieurs outils (ex. Gephi).
Méthode de Louvain
La méthode construit des communautés en bottom-up, i.e. commence par les nœuds en les considérant tous des communautés ensuite regroupe les nœuds adjacents de façon à améliorer une mesure de modularité du graphe. Cette est répétée jusqu’à ne plus pouvoir améliorer le score de modularité.
A ce niveau les communautés créées sont replacé par des super-nœuds pour créer un graphe de niveau supérieur sur lequel la procédure précédente est répétée.
Ainsi la méthode permet la création de communauté hiérarchique (i.e. l’utilisateur à la possibilité de zoomer sur le graphe !).
Après présentation de la méthode, il a présenté des études ou la méthode a été appliquée :
·         Analyse de réseau de criminalité en Belgique (les nœuds représentent des criminels, un arc entre deux nœuds signifies que les deux criminels sont impliqués dans un même faits), le graphe a été construit par des données sur 5 ans.
·         Analyse d’appels téléphoniques mobile de Belgique (MOBISTAR) sur 6 mois.
·         Analyse d’appels téléphoniques mobile de France è les communautés crées permettaient sont au niveau des régions (au lieu des départements).
Il parlait aussi de challenge proposé par Nokia Research et Orange (D4D : Data for Developpment) qui offrait aux chercheurs des données d’utilisation de mobile principalement en Afrique (ex. côte d’ivoire) si le projet correspondaient aux besoins marketing de l’entreprise.

Détection de communautés chevauchantes dans les graphes bipartis
La présentation portait sur les graphes bipartis où on a deux groupes de nœuds et un nœud ne peut avoir d’arc qu’avec les nœuds d’un autre groupe. L’exemple d’étude porté sur les photos de mariage. L’approche à pour but de détecter des partitions recouvertes.

Une nouvelle mesure pour l’évaluation des méthodes de détection de communauté
L’étude propose une nouvelle mesure d’évaluation de communauté meilleure que celle généralement utilisée « pureté de partition ». Le problème de celle-ci c’est qu’elle affecte potentiellement le même score pour deux partitions bien que sur l’une un nœud important pour la communauté a été mal classé.
La mesure proposée prend en compte l’importance topologique des nœuds qui représente le nombre d’arc sortant d’un nœud, la pureté nodale est égale à 1 pour un nœud bien classé et 0 pour un nœud mal classé.
Pour évaluation de l’approche, l’auteur prenait plusieurs algorithmes de clustering avec utilisation des deux mesures. Le résultat montrait que l’approche pénalise le partitionnement qui classe mal un nœud important (au centre) au profit de nœud moins important au bord de la partition.

Détection de communautés dans des réseaux scientifiques à partir de données relationnelles
L’étude portée sur les graphes dont les nœuds peuvent avoir des attributs, dans ce cas il s’agit de graphes sur la participation de chercheurs à deux conférences ayant deux sessions.

Caractérisation de la structure communautaire d’un grand réseau social
Les auteurs montrent que la plupart des algorithmes de partitionnement (y compris celui de Louvain) donnent de mauvais résultat (des fausses communautés) pour certain type de graphes (ex. graphe grille) à cause de la mesure qui est utilisé pour mesurer la qualité d’un partitionnement.
Pour montrer cela, leur étude portait sur les cœurs de communautés qui sont obtenu en appliquant plusieurs fois (~100 fois) un algorithme de partitionnement, ensuite renforcer (proportionnellement au nombre de co-apparition) les liens entre les nœuds qui apparaissent dans la même communauté souvent.

Apprentissage et ciblage publicitaire
Une personne de Numsight venait présenter l’eco-système de publicité dans le web qui est composé des sites web, des AD server, des marchés des AD. Ainsi que leur approche qui est basé sur l’analyse des sites web afin de les tagger en catégories (ex. mode, sport) et sous-catégorie (ex. club, foot). Aussi, l’approche est basée sur le profiling des utilisateurs en agrégeant plusieurs informations (ex. site web consultés, mot clé utilisé dans des moteurs de recherche donnée par google !) afin de déterminer le projet de l’utilisateur (ex. achat de voiture ou réparation, voyage touristiques ou affaire).

Wolfram Mathematica
Après une personne de wolfram donnait un tutoriel sur l’utilisation de leur produit mathematica !

Here is a link to the conference presentations.

dimanche 14 avril 2013

Playing with the M-Files: a leading Document Management System

M-Files is a rich ECM (Enterprise Content Management) system that can be used to facilitate access to any type of documents including scanned paper (through Optical Character Recognition), emails, etc. It can also be integrated with other enterprise systems like ERP, CRM. You can find more on the corresponding wikipedia page.

In this post we will see: how to administer the system (install it on a local machine, add a license), import data from a CRM database, Model a document management workflow.

M-Files Administration

After installation you will see the "M" driver that allows you to access all documents stored on the M-Files server, there storage is organized into vaults in the M-Files terminology that represents a physical central storage area. In the trail version, you can access directly to a vault content by a double click, however in the pro version a log-in dialog is prompted to check if you have credentials for accessing theis area.

To add a license, launch the M-Files program then right click on the M-file icon (i.e. M) in the Windows Tool bar (see the picture)
Then choose Settings -> M-Files Server Administor. 
On the administrator window choose Local Computer (On the left side) -> License Management (on the right side) -> Install License ... -> enter your Serial number and License code.

You can find more information on the M-Files manual can be fond here: 
Start -> All Programs -> M-Files -> Documentation -> M-Files Help

Import data to M-Files

Imported files to M-Files are enriched with meta-data that should be indicated at the importation time. On the manual you can find how to import data under the section Daily use of M-Files -> Transferring existing files to M-Files. There you will see that you have two options:
  • Create a link between a source and the corresponding M-files document so that modifications in any of these data is propagated to the other copy through this connection.
  • Import an external document to M-Files so that you can modify any copy without altering the other one.
To read more about these options jump to Connections to External Sources / File Sources. You can also check Connection to External Database.

To create a connection to an external source, on the administrator window go to Connections to External Sources then select the source type (e.g. file, email). A new window will show up to allow you edit the source information (location, description, meta-data).

We're going to import a CRM database to retrieve the customers information (i.e. name, address and website).
On the administrator window (previous figure), go to Object Types under Meta Structure of your current vault. Then on the right side select Customer then Connection to External Database as in the following figure:
Check the checkbox then, click on define source to enter the database OLE provider as well as connection information (data source path or DB name, user credentials).

For instance, to import data from an Excel file choose for OLE DB Provider "Microsoft OLE DB Provider for ODBC Drivers". Then, in the next tab edit the DSN (Data Source Name) (e.g. Excel) or enter a connection string. For instance, here is an example of such string for accessing MS Access:
provider=MICROSOFT.JET.OLEDB.4.0;DataSource=C:\mfiles.accdb;User ID=nonDusager;Password=motDePasse;
You can find more information about the connection strings check this page (french).

If you had problems of DSN incompatibility between your pilote and the application then check this thread on Microsoft support.

To be continued.

dimanche 7 avril 2013

Some podcast radios

The following are some cool Podcasts about development on different technologes: Java, Android, etc.

Software Engineering Radio usually performs interviews with authors or professionals from different backgrounds in software engineering (development, databases, Java technology). This radio is sponsored by the IEEE Software magazine.

Android Weekly performs a weekly review of Android news from new Apps to insights from Google

Android Devcast a serie of french podcast by PAUG (Paris Android User Group) on everything concerning Android development.

Java Posse performs good news cast about Java technologies (and even Scala), frameworks and the JVM. Some Googlers are part of the host.

Lostcast is a podcast by two indie game developers that talk about their experience with HTML5 based games development, advanced technics, interviews with industry pioneers.

Talking Big Data is hosted by IBMer David Pittman, it addresses everything related to Big Data, analytics and related technologies.

Hacker Public Radio is hosted by a long list of members and has the particularity of having the content produced by the community of listeners, the radio abords different areas especially on the open source community (conferences or projects news, etc.).

You can find more by visiting this StackOverflow thread. or on Vogel's blog.

All these podcasts can be found on podbay.fm, there you can also find more podcast radios.



dimanche 17 mars 2013

Embedded Android

Some resources from the Embedded Android Workshop:
1. Android Internals

2. Working with the AOSP

3. Native Android user-space

4. Using and Customizing the Android Framework

This is a link to the presentation.

More presentations by

Check also the Embedded Linux Wiki and Porting Android to Devices.


lundi 4 février 2013

Adding headers button to a ListView

Here is an example showing how to add headers button to a ListView

Button btn1 = new Button(MyActivity.this);
btn1.setText("button1");
btn1.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
btn1.setGravity(Gravity.CENTER);
btn1.setOnClickListener(new OnClickListener() {   
 @Override
 public void onClick(View v) {
  // do something
 }
});
Button btn2 = new Button(MyActivity.this);
btn2.setText("button2");
btn2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
btn2.setGravity(Gravity.CENTER);
btn2.setOnClickListener(new OnClickListener() {   
 @Override
 public void onClick(View v) {
  // do something
 }
});
        
LinearLayout layout = new LinearLayout(this);  
layout.setOrientation(LinearLayout.HORIZONTAL);  
layout.setLayoutParams(new ListView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));  
layout.setGravity(Gravity.CENTER);  
layout.addView(btn1);  
layout.addView(btn2);
myList.addHeaderView(layout);//or getListView().addHeaderView(layout);

lundi 14 janvier 2013

Building its own Linux distribution


Preparing for Linux build

Host System Requirements

Before going further you need to check some requirements on the host system. Here at pastebin you can find the version checking file.
After download, run $bash version-check.sh. You can also create it locally directly from the terminal as follow:
$cat > version-check.sh << "EOF"
>Paste here the content from pastebin
>EOF
Here is a possible output, you should have packages with at least similar version or higher than this output.
In my case, I had to install gawkpatch, and makeinfo. You may have trubble to install the last one, it is available in texinfo package. Here are the issued installation commands:
$sudo aptitude install gawk
$sudo aptitude install patch
$sudo aptitude install texinfo

Preparing a new partition

I'm using xubuntu running on a VirtualBox, to create a partition I added a new device to my virtual machine: Configuration->Storage -> select the disk controller -> add new disk. I used GParted to create new partitions.
To create a filesystem on the created partition: $sudo mke2fs -jv /dev/
In my case I used the existing swap partition in the host system.
After setting the filesystem, the partition need to be mounted:
$export LFS=/mnt/lfs
$sudo mkdir -pv $LFS
$sudo mount -v -t ext3 /dev/ $LFS

After that, I created a directory under /mnt/lfs to store downloaded packagaes before installation.

$sudo mkdir -v $LFS/sources
$sudo chmod -v a+wt $LFS/sources


I used wget to download needed packages, here is a complete list of packages to download. I first created a file to store this list as follow:

$cat > wget-list << "EOF"
>Paste here the content of packages list
>EOF


To start downloading, it took a while depending on the available bandwidth: 
$sudo wget -i wget-list -P $LFS/sources 
In the list you man-pages-3.35.tar.gz and zlib-1.2.6.tar.bz2 were missings, I had to download them manually by google the package name.

Changing the owner of from root to lfs.



When I was trying to configure GCC, i get following error error: C compiler cannot create executables. After some search, it seams that the $LFS_TGT variable was not set correctly as a result of creating a directory with user  root instead lfs , and thus I had to restart from scratch.

repeat from section 2.2 building binutils-2.2
5.4. Binutils-2.22

to be continued.