Affichage des articles dont le libellé est android. Afficher tous les articles
Affichage des articles dont le libellé est android. Afficher tous les articles

2013-10-02

ADB Lock non-root mode [fr / en]

English version below…

Android réserve ses fonctions les plus sensibles aux applications "système". C'est par exemple le cas de "Paramètres", l'application système que vous utilisez le plus souvent, qui est autorisée à activer ou désactiver ADB sans recourir au root.

Une application Système est une application classique : elle est au format APK, elle doit déclarer ses permissions. LA différence est qu'elle est placée dans /system/ (un dossier spécial et protégé) au lieu de /data/app comme toutes les autres apps.

L'app ADB-Lock est capable de détecter toute seule si elle est Système et dans ce cas cesse d'utiliser le mécanisme ROOT pour permuter l'état de l'ADB.

Il y a au moins 4 manières de passer ADB-Lock en mode Système : avec une app, avec le shell adb, avec un script  ou avec un zip (recovery ou TWRP). Bref vous avez l'embarras du choix.

2013-07-24

MasterKey : du cache-cache au root.

C'est à l'équipe de sécurité BlueBox que l'on doit la paternité du bug MasterKey. Avant que la présentation officielle de la faille à la BlackHat 2013 ne soit faite, les détails donnés ont suffit à d'autres chercheurs chevronnés pour la trouver par leurs propres moyens.

Si dans un premier le temps le buzz était alimenté par les "99%", il est ensuite un peu retombé car la faille ne semblait destinée qu'au cache-cache. Saurik a dévoilé il y a quelques jours comment chainer MasterKey aux outils de développement d'Android pour cette fois-ci passer root. Du coup, doit-on avoir peur de cette faille ?

Si vous avez du contenu professionnel sensible sur votre smartphone, il est temps de l'effacer. Si vous avez encore des smartphones sous scellés, il est temps de dumper les bases sqlite !

2013-06-29

État de l'art de la triche sur Ruzzle… et plus encore !

mise à jour 2/07 : Présentation de Ruzzle+GIF et synthèses des manipulations des vidéos.

Intro

What you must learn is that these rules are no different than the rules of a computer system...some of them can can be bent. Others...can be broken. Understand?  - Morpheus

Cette réplique de Matrix illustre assez bien ma conception de l'informatique en général et dans les jeux vidéos en particulier. Je triche, je cheat, je n'ai acun esprit de fair play, je ne respecte pas les règles du ou des développeurs mais je respecte les miennes : utiliser, comprendre, détourner, retourner. Bref … corrompre !

La première modification que j'ai apporté au Ruzzle concernait l'horloge. Mes manches durent 4 minutes, celles de l'adversaire 2. Malgré cet avantage mes adversaires arrivaient à taper des scores équivalents aux miens. Diable ! MAIS TOUT LE MONDE TRICHE !!!

2013-06-08

Listes des raccourcis Emoji/Unicode pour le clavier Android stock.

Faire un coeur en emoji
La version 4.2 (JellyBean) d'Android apportait à nos smartphones le support des emojis. Ce sont des icônes, colorées, très populaires au Japon et portée à l'attention du très grand public européen par Apple avec iOS.

En réalité nous n'avons pas affaire à des vrais emojis, mais à des caractères Unicode (v5/v6). De ce constat découle quatre conséquences, importantes à comprendre:
  • Les caractères sont monochromes
  • Les caractères doivent être dans la police choisie pour l'interface.
  • Les caractères 24bits comme le picto "feu"  sont affichables, copiables et collables. ⚠ Seuls les caractères unicodes 8 et 16 bits sont gérés par le dictionnaire.
  • Les VRAIS emojis ne sont pas gérés par Android de base (mais certaines ROMs comme CyanogenMod savent les afficher).
 Les images affichées dans le tableau qui suit dépendent de la police choisie pour consulter cette page web. Quelques-un de ces caractères sont par exemple invisibles avec un Android AOSP !


2013-05-23

SMS Revealer ✉ sur le PlayStore

Je vous propose une application illustrant mon dernier billet sur l'extraction des sms envoyés en loucedé :
  • SMS Revealer ✉ : C'est l'application principale qui va extraire directement des journaux Android tous les SMS envoyés par le terminal. Il faut avoir préalablement mis le terminal dans le mode de débogage adéquat.

    L'écran d’accueil prévient si le mode débogage est incomplet et vous rappelle les commandes adb nécessaires (qui vous sont familières) :


    Ensuite l'écran de synthèse des SMS envoyés avec la date et l'heure, le destinataire et le contenu des SMS. Les émojis et les SMS binaires sont supportés, contrairement aux MMS.


    Lien vers l'alpha (gratuit) : https://play.google.com/apps/testing/net.cekage.smsspypoc
    Lien Play Store : https://play.google.com/store/apps/details?id=net.cekage.smsspypoc
L'application est pour l'instant en Anglais-US. La traduction en français est en cours de tests avec l'outil de traduction intégré au PlayStore.  Notez qu'elle est triviale. 

2013-02-17

Lire en loucedé les SMS envoyés par les applications

Eyes on you, probee ! - © NCIS
Et si il était possible de lire les SMS envoyés par les applications sans rooter son appareil ?
Sans décompiler l'application (ça peut mal tourner) !
Sans installer de coûteux logiciels dédiés aux forensics!
Sans jouer du fer à souder!

Et bien, tout cela est possible et c'est même tout à fait simple à faire.

Cet article, limité à l'envoi d'un SMS texte classique, est en fait de portée générale. En d'autres termes cette note de blog s'articule sur sendTextMessage().

2013-01-15

Récupérer les identifiants OMTP/IMAP FreeMobile

(mise à jour pour les Android récents)




Plus de 300 téléchargements, un peu plus de 110 installations actives, vous avez rempli votre partie du contrat. À moi de remplir la mienne en vous donnant le modus operandi ET les sources de ce qui est publié sur le PlayStore.

La récupération est relativement simple:
  1. Envoyer "STATUS:pv=13;ct=free.VVM.10;pt=5499;//VVM" par binarySMS au 2051:5499
  2. Lire les SMS de réponses du 2051
  3. Isoler celui qui match la regexp ".*;u=.*;pw=.*;.*"
  4. Parser les éléments "u", "pw", "srv", "ipt"
That's all folks !

Vous pouvez télécharger mon application exemple sur le PlayStore : https://play.google.com/store/apps/details?id=net.cekage.vvmfreemobile


Le code source est publié sur mon compte github : https://github.com/cekage/net.cekage.vvmfreemobile

Si vous préférez faire le programme par vous-même, voici le code source :

La classe principale MainActivity.java

package net.cekage.vvmfreemobile;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;

import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;

/**
 * inspired by
 * http://code.google.com/p/krvarma-android-samples/source/browse/trunk
 * /SMSDemo/?r=37
 */

public class MainActivity extends Activity {
 public static final String TAG = "cekage_FreeVVM";
 EditText etlp;

 private String FREEMOBILE_ASKING = "isAsking";

 private String FREEMOBILE_DISPLAYED_DATE = "vvminfos";
 ImageButton ibSearch;
 ImageView ivLogo;
 ProgressBar pbAsking;

 private BroadcastReceiver smsreceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
   Bundle bundle = intent.getExtras();
   SmsMessage[] msgs = null;

   if (null != bundle) {
    String info = "";// "Binary SMS from ";
    Object[] pdus = (Object[]) bundle.get("pdus");
    msgs = new SmsMessage[pdus.length];
    byte[] data = null;

    for (int i = 0; i < msgs.length; i++) {
     msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);

     data = msgs[i].getUserData();

     for (int index = 0; index < data.length; ++index) {
      info += Character.toString((char) data[index]);
     }
    }
    updateETLP(info);
    uiAsking(false);
   }
  }

 };

 public void btnClickFetch(View v) {

  SmsManager smsm = SmsManager.getDefault();
  smsm.sendDataMessage("2051", null, (short) 5499,
    "STATUS:pv=13;ct=free.VVM.10;pt=5499;//VVM".getBytes(), null,
    null);
  uiAsking(true);

 }

 public void btnClickShare(View v) {
  Intent sendIntent = new Intent();
  sendIntent.setAction(Intent.ACTION_SEND);
  sendIntent.putExtra(Intent.EXTRA_TEXT, etlp.getText());
  sendIntent.setType("text/plain");
  startActivity(sendIntent);

 }

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  etlp = (EditText) findViewById(R.id.etLoginPass);
  ibSearch = (ImageButton) findViewById(R.id.btnSearch);
  ivLogo = (ImageView) findViewById(R.id.ivLogo);
  pbAsking = (ProgressBar) findViewById(R.id.pbAsking);
  if (savedInstanceState != null) {
   etlp.setText(savedInstanceState
     .getString(FREEMOBILE_DISPLAYED_DATE));
   uiAsking(savedInstanceState.getBoolean(FREEMOBILE_ASKING, false));
  }

  IntentFilter ifDATASMS = new IntentFilter(
    "android.intent.action.DATA_SMS_RECEIVED");
  ifDATASMS.addDataScheme("sms");
  registerReceiver(smsreceiver, ifDATASMS);

 }

 private void uiAsking(Boolean isAsking) {
  ivLogo.setVisibility(isAsking ? View.GONE : View.VISIBLE);
  pbAsking.setVisibility(!isAsking ? View.GONE : View.VISIBLE);
  ibSearch.setEnabled(!isAsking);
 }

 protected void onSaveInstanceState(Bundle bundle) {
  super.onSaveInstanceState(bundle);
  bundle.putString(FREEMOBILE_DISPLAYED_DATE, etlp.getText().toString());
  bundle.putBoolean(FREEMOBILE_ASKING, !ibSearch.isEnabled());
 }

 private void updateETLP(String binarymessage) {

  String FREEMOBILE_LOGIN = "";
  String FREEMOBILE_PASSWORD = "";
  String FREEMOBILE_SERVER = "";
  String FREEMOBILE_PORT = "";

  if (binarymessage.matches(".*;u=.*;pw=.*;.*")) {

   String[] separated = binarymessage.split(";");
   for (String param : separated) {
    if (param.startsWith("u="))
     FREEMOBILE_LOGIN = param.substring(2);
    else if (param.startsWith("pw="))
     FREEMOBILE_PASSWORD = param.substring(3);
    else if (param.startsWith("srv="))
     FREEMOBILE_SERVER = param.substring(4);
    else if (param.startsWith("ipt="))
     FREEMOBILE_PORT = param.substring(4);
   }
   etlp.setText(String.format(
     "Login: %s\nPass: %s\nServer: %s\nPort: %s",
     FREEMOBILE_LOGIN, FREEMOBILE_PASSWORD, FREEMOBILE_SERVER,
     FREEMOBILE_PORT));

  } else {

   etlp.setText(binarymessage);
  }
 }

}

Le layout activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="10dp" >

    <ImageView
        android:id="@+id/ivLogo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/ic_launcher"
        android:visibility="visible" />

    <ProgressBar
        android:id="@+id/pbAsking"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone" />

    <EditText
        android:id="@+id/etLoginPass"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:ems="20"
        android:inputType="textMultiLine"
        android:lines="5"
        android:singleLine="false"
        android:text="@string/et_mask" >

        <requestFocus />
    </EditText>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ImageButton
            android:id="@+id/btnSearch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#0000"
            android:onClick="btnClickFetch"
            android:src="@android:drawable/ic_menu_search"
            android:text="@string/btn_search" />

        <ImageButton
            android:id="@+id/btnShare"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#0000"
            android:onClick="btnClickShare"
            android:src="@android:drawable/ic_menu_share" />
    </LinearLayout>

</LinearLayout>

Le manifest AndroidManifest.xml :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.cekage.vvmfreemobile"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="4"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />

    <application
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

2012-11-18

La Messagerie Visuelle Vocale FreeMobile pour tous.

MISE À JOUR : Vous pouvez récuperer vos identifiants avec l'application net.cekage.vvmfreemobile  depuis le PlayStore  
 
Fin Octobre 2012, FreeMobile a proposé pour ses clients Android la Messagerie Visuelle Vocale (MVV) en téléchargement gratuit sur le PlayStore mais l'a réservée aux dernières générations de téléphones Android et Apple. Cette limite est d'autant plus étonnante que FreeMobile propose encore des terminaux en 2.3 :
Le Galaxy Y en 2.3 (GingerBread)
L'objectif de cet article est de documenter pour les développeurs d'applications mobiles pour Android <4, Symbian, Windows Mobile, Bada,... le fonctionnement de la MVV pour pouvoir l'utiliser sur leur système favori. Pour ma part, j'utilise souvent mon vieux Smartophonus Ginderbreadus et la MVV est un confort.

Comme à mon habitude, je privilégie l'approche candide pour deviner le protocole.  Une fois que je sais reproduire les fonctions ciblées je vérifie avec la documentation si elle est disponible.

2012-10-23

SMATAB 700 : installer le PlayStore

J'ai presque testé pour vous la tablette SMAT@B 700 proposée par Fiducial Office Solution, notre gentil fournituriste.

N'attendez rien d'extraordinaire pour la centaine d'euro (TTC), mais si vous souhaitez l'utiliser dans votre SI, soyez méfiants. Cette tablette est insécurisée et ne se sécurise pas.

Présentation

Ce qui ne va pas, matériellement : l'écran est salissant, la webcam est poussive, les touches physiques sont cheap, la prise USB mini-B.

Ce qui ne va pas logiciellement : pas de PlayStore, pas les Contacts Android, le launcher est peu réactif, ADB activé par défaut. Le fichier /etc/default.prop est a priori ignoré, la tablette ne peut être mise en mode "production builds".

Ce qui est susceptible de vous intéresser matériellement : un cable pour faire de l'USB-Host, une sortie hdmi, 2 modes de recharges.

Et vous intéresser  logiciellement : Android en mode débogage (= adb root), la partition /system/ montée

Activer le play store

Le PlayStore est actif mais masqué par défaut. Il existe 3 moyens d'y accéder
  1. En cherchant le mot "Play" dans la barre de recherche du launcher
  2. Par adb shell
    am start com.android.vending 
  3. Avec une application minimale

Activer les contacts

Le carnet d'adress est actif mais masqué par défaut. Il existe 3 moyens d'y accéder
  1. En cherchant le mot "Cont" dans la barre de recherche du launcher
  2. Par adb shell
    am start com.android.contacts
  3. Avec une application minimale

L'application minimale

package net.cekage.shortcut;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;

public class Shortcut extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Intent intent = new Intent(Intent.ACTION_MAIN);
  intent.setComponent(new ComponentName("com.android.vending",
    "com.android.vending.AssetBrowserActivity"));
  startActivity(intent);
  finish();
 }
}

A acheter ou pas ?

C'est une tablette de niche, rien ne semble correctement fini :
  • hackable mais non évolutive.
  • Ouverte aux GApps mais celles-ci sont cachées. 
  • Interface tablette mais trop faible résolution, le texte est trop aliasé.
  • Autonome mais pas trop : la batterie s'épuise vite.
A mon humble avis, sa meilleure utilisation est un device d'appoint pour tester ses développements ailleurs que sur l'émulateur.

2012-10-08

stat_sys_adb en SVG


Pour le nouveau logo de adb_lock j'ai eu besoin d'utiliser les images utilisée par Android lorsque le téléphone est en mode débogage.

Si vous travaillez avec Inkscape voici un pense-bête pour les effets chez carnivora-publishing. Si vous utilisez Inkscape pour MountainLion et que libxml2 vous fait des misères, voyez chez lrem.net.

Le SVG est fait main, il n'est donc pas exactement identique à l'icône Android :

SVG file :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   sodipodi:docname="logo-debug.svg"
   inkscape:version="0.48.2 r9819"
   version="1.1"
   id="svg2"
   height="744.09448"
   width="1052.3622"
   inkscape:export-xdpi="71.966667"
   inkscape:export-ydpi="71.966667">
  <title
     id="title36756">stat_sys_adb SVG</title>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.16136213"
     inkscape:cx="-1335.2764"
     inkscape:cy="-427.65272"
     inkscape:document-units="px"
     showgrid="false"
     showguides="true"
     inkscape:guide-bbox="true"
     inkscape:window-width="1440"
     inkscape:window-height="821"
     inkscape:window-x="194"
     inkscape:window-y="15"
     inkscape:window-maximized="0"
     inkscape:current-layer="layer4" />
  <defs
     id="defs4" />
  <metadata
     id="metadata7">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title>stat_sys_adb SVG</dc:title>
        <dc:date>2012-10-07</dc:date>
        <dc:creator>
          <cc:Agent>
            <dc:title>CeKaGe</dc:title>
          </cc:Agent>
        </dc:creator>
        <dc:rights>
          <cc:Agent>
            <dc:title>http://sam.zoy.org/wtfpl/COPYINGs</dc:title>
          </cc:Agent>
        </dc:rights>
        <dc:publisher>
          <cc:Agent>
            <dc:title>CeKaGe</dc:title>
          </cc:Agent>
        </dc:publisher>
        <dc:language>fr_FR</dc:language>
        <dc:description>Entirely based on Android SDK icon stat_sys_adb.png</dc:description>
        <cc:license
           rdf:resource="http://sam.zoy.org/wtfpl/COPYING" />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="ronds"
     id="layer4"
     inkscape:groupmode="layer"
     transform="translate(0,-308.2677)">
    <path
       inkscape:connector-curvature="0"
       id="stat_sys_adb_ICS"
       d="m 129.8507,642.21771 c -1.56864,0.0448 -3.2899,0.50893 -5.2016,1.42102 -9.03946,8.14097 5.74203,15.8443 8.88078,28.31903 -4.65862,7.40003 -39.088256,21.29558 -41.003826,68.41228 l 187.714306,-0.12688 c -3.76065,-34.15455 -14.14904,-49.52154 -40.52173,-68.00627 2.70742,-13.78943 14.50986,-14.54933 8.17032,-28.87729 -14.79482,-5.29954 -15.44999,10.49324 -23.01391,20.12275 l -76.60307,0.81202 c -5.88875,-10.99361 -9.9506,-22.3189 -18.42127,-22.07666 z m 16.97498,46.53862 c 6.60523,0 11.95099,5.11722 11.95099,11.44434 0,6.32711 -5.34576,11.46971 -11.95099,11.46971 -6.60525,0 -11.97637,-5.1426 -11.97637,-11.46971 0,-6.32712 5.37112,-11.44434 11.97637,-11.44434 z m 47.42336,0.76126 c 6.30715,0 11.41815,4.93475 11.41815,11.03833 0,6.10359 -5.111,11.06371 -11.41815,11.06371 -6.30716,0 -11.41815,-4.96012 -11.41815,-11.06371 0,-6.10358 5.11099,-11.03833 11.41815,-11.03833 z M 50.278914,749.80972 c -9.76592,0 -17.63469,7.86933 -17.63469,17.63595 l 0,96.70596 c 0,9.76659 7.86877,17.6105 17.63469,17.6105 l 9.08377,0 c 9.76592,8e-5 17.60932,-7.84391 17.60932,-17.6105 l 0,-96.70596 c 0,-9.76662 -7.8434,-17.63595 -17.60932,-17.63595 l -9.08377,0 z m 262.820336,0 c -9.76592,0 -17.63469,7.86933 -17.63469,17.63595 l 0,96.70596 c 0,9.76659 7.86877,17.6105 17.63469,17.6105 l 9.05839,0 c 9.76592,8e-5 17.63469,-7.84391 17.63469,-17.6105 l 0,-96.70596 c 0,-9.76662 -7.86877,-17.63595 -17.63469,-17.63595 l -9.05839,0 z m -187.51133,4.28845 c -18.64403,0 -33.645456,14.05482 -33.645456,31.51634 l 0,173.08606 c 0,17.46181 15.001426,31.51625 33.645456,31.51645 l 92.41086,0 c 0.0114,-9.51019 2.16996,-16.34988 2.23288,-25.85768 0.72073,-8.80054 7.65517,-17.57534 16.46751,-17.40758 5.16247,0.0138 11.91344,-1.59877 17.07647,-1.59861 0.0115,-8.97699 -1.55644,-15.81684 -1.49705,-24.79188 0.72073,-8.80054 7.65517,-17.601 16.46751,-17.43291 2.63471,0.008 5.71079,-0.17597 9.08376,-0.45684 l 0,-117.05701 c 0,-17.46152 -15.00144,-31.51634 -33.64546,-31.51634 l -118.59648,0 z m 2.10602,14.41327 69.52382,0 c 10.92892,0 19.89022,12.28426 19.71533,27.53239 l -1.0657,93.15335 c -32.68796,-0.87381 -31.83327,22.79221 -29.05283,42.07254 -23.12641,0.0674 -34.62109,8.71097 -34.33056,42.90997 l -27.4543,0.53284 c -10.92687,0.21259 -17.05109,-12.25794 -17.05109,-27.50701 l 0,-151.16169 c 0,-15.24914 8.7864,-27.53239 19.71533,-27.53239 z m 58.10567,33.82551 0,15.68204 15.96003,0 0,-15.68204 -15.96003,0 z m -62.36845,0.0253 0,15.68205 15.7063,0 0,-15.68205 -15.7063,0 z m 31.28572,31.33872 0,15.93582 15.85854,0 0,-15.93582 -15.85854,0 z m 31.2096,31.23719 0,15.68204 15.83316,0 0,-15.68204 -15.83316,0 z m -62.67293,0.0503 0,15.68205 15.70629,0 0,-15.68205 -15.70629,0 z m 31.36184,31.36409 0,15.52979 15.73167,0 0,-15.52979 -15.73167,0 z m -31.26035,31.33875 0,15.75813 15.78242,0 0,-15.75813 -15.78242,0 z"
       style="color:#000000;fill:#33b5e5;fill-opacity:1;stroke:#33b5e5;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
       inkscape:label="#path5309"
       inkscape:export-xdpi="72"
       inkscape:export-ydpi="72" />
    <path
       style="fill:#33b5e5;fill-opacity:1;fill-rule:nonzero;stroke:none"
       d="m 926.06018,714.17829 c -27.22353,-12.00453 -30.55244,42.51128 -35.0691,41.25189 -34.67205,-9.66763 -80.71112,-7.81977 -122.07702,0.004 -22.48447,4.25265 -58.38589,14.8761 -78.22496,24.33748 -12.49865,-4.28099 -28.95334,-49.73487 -48.87993,-33.00071 -11.57241,15.98748 24.68234,50.79657 18.2805,60.47016 -25.23911,38.13797 -41.05442,21.97111 -42.4231,98.3444 -0.91334,50.967 32.22027,108.49709 134.71262,86.42742 19.67802,-4.23735 35.50576,-9.52521 56.73124,-9.60298 39.57385,-0.14536 96.83676,7.89129 121.02155,-5.93925 44.38563,-25.38236 59.22363,-62.1197 59.55063,-97.34376 0.5,-53.86529 -37.73872,-93.1189 -71.35197,-110.15389 17.36884,-34.1089 21.90616,-48.65518 7.72954,-54.79446 z m -61.41404,109.33792 c 8.51986,0 15.42657,6.38378 15.42657,14.23102 0,7.84725 -6.90671,14.19246 -15.42657,14.19246 -8.51987,0 -15.42659,-6.34521 -15.42659,-14.19246 0,-7.84724 6.90672,-14.23102 15.42659,-14.23102 z m -134.78976,8.94742 c 8.96828,0 16.23648,5.98373 16.23648,13.38256 0,7.39884 -7.2682,13.38256 -16.23648,13.38256 -8.96828,0 -16.23647,-5.98372 -16.23647,-13.38256 0,-7.39883 7.26819,-13.38256 16.23647,-13.38256 z"
       id="stat_sys_adb_JB"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cssccssscssccssssssssss"
       inkscape:label="#path4733"
       inkscape:export-xdpi="72"
       inkscape:export-ydpi="72" />
    <path
       sodipodi:nodetypes="cccccccccccccscccsssssssssssssssssscccccccccccccccccccccccccccccsssscccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
       inkscape:connector-curvature="0"
       id="stat_sys_adb_GB"
       d="m 451.07406,339.14504 c -0.86677,-0.019 -1.73909,0.2364 -2.48694,0.75793 l -2.65279,1.84748 c -1.99436,1.39066 -2.38174,4.23619 -0.8764,6.3951 l 21.19861,30.43591 c -28.23061,17.45288 -48.75443,48.92262 -48.55539,93.32118 l 208.45656,-0.30795 c 0.25588,-45.60482 -19.65614,-76.72416 -47.20527,-93.70008 l 20.74855,-29.74906 c 1.50534,-2.15891 1.11796,-5.00444 -0.8764,-6.3951 l -2.65279,-1.84748 c -1.99436,-1.39066 -4.81866,-0.78514 -6.324,1.37377 l -21.53021,30.90961 c -14.49958,-6.66462 -30.50231,-9.86084 -46.47107,-9.63998 -15.42556,0.21336 -30.85702,3.68714 -44.93147,10.27953 l -22.00393,-31.54916 c -0.94082,-1.34928 -2.39243,-2.10033 -3.83706,-2.1317 z m 26.52783,55.40048 12.60072,0 c 2.43131,0 4.40551,2.1289 4.40551,4.76084 l 0,25.53303 c 0,2.63194 -1.9742,4.73712 -4.40551,4.73712 l -12.60072,0 c -2.43131,0 -4.38179,-2.10518 -4.38179,-4.73712 l 0,-25.53303 c 0,-2.63194 1.95048,-4.76084 4.38179,-4.76084 z m 75.79379,0 12.60072,0 c 2.43131,0 4.40552,2.1289 4.40552,4.76084 l 0,25.53303 c 0,2.63194 -1.97421,4.73712 -4.40552,4.73712 l -12.60072,0 c -2.43131,0 -4.38179,-2.10518 -4.38179,-4.73712 l 0,-25.53303 c 0,-2.63194 1.95048,-4.76084 4.38179,-4.76084 z m -167.81215,86.92609 c -2.52629,-0.008 -5.01801,0.61809 -7.55573,0.5921 -4.81321,0.23374 -9.63241,0.22571 -14.4482,0.37897 -6.19591,0.10959 -11.13138,5.0778 -13.33493,10.54011 -1.92455,4.95092 -2.68818,10.66388 -0.92377,15.77458 1.15994,3.3294 4.16775,6.32984 7.91097,6.15825 4.53672,0 8.14094,-3.09709 11.96125,-5.06871 7.5555,-3.03979 16.32197,-0.42498 22.40654,4.57135 3.49424,1.85331 7.59204,-0.15273 10.01895,-2.84227 2.41131,-2.45276 3.82251,-5.82763 3.64758,-9.28474 -0.10179,-10.12188 -8.36468,-19.85441 -18.59313,-20.77227 -0.36244,-0.0303 -0.72868,-0.0462 -1.08953,-0.047 z m 286.23994,0 c -2.52621,-0.008 -5.01793,0.61809 -7.55566,0.5921 -4.81321,0.23374 -9.63248,0.22571 -14.44819,0.37897 -6.19591,0.10959 -11.1551,5.07788 -13.35865,10.54011 -1.92456,4.95092 -2.66454,10.66388 -0.90006,15.77458 1.15988,3.32947 4.16775,6.32977 7.91098,6.15825 4.53671,0 8.14094,-3.09701 11.96117,-5.06871 7.55558,-3.03971 16.29832,-0.42498 22.38289,4.57135 3.49425,1.85331 7.61569,-0.1528 10.04268,-2.84227 2.41131,-2.45284 3.82243,-5.82771 3.64758,-9.28474 -0.10179,-10.12196 -8.36468,-19.85441 -18.5932,-20.77227 -0.36245,-0.0303 -0.72861,-0.0462 -1.08954,-0.047 z m -254.14605,1.94221 0,21.17489 0,29.22798 -0.41989,100.61763 c -0.0493,11.72007 22.47195,34.13191 34.19209,34.16845 l 134.89135,0.41989 c 11.72022,0.0364 37.75447,-21.61002 37.94766,-33.32865 l 1.67959,-101.87732 0,-29.22798 0,-21.17489 -21.15116,0 -165.96475,0 z m -32.09389,48.53175 c -2.52629,-0.008 -5.01801,0.6181 -7.55573,0.5921 -4.81321,0.23375 -9.63241,0.22572 -14.4482,0.37897 -6.19591,0.1096 -11.13138,5.07781 -13.33493,10.54011 -1.92455,4.95093 -2.68818,10.66389 -0.92377,15.77459 1.15994,3.32939 4.16775,6.32977 7.91097,6.15817 4.53672,0 8.14094,-3.09701 11.96125,-5.06864 7.5555,-3.03978 16.32197,-0.42505 22.40654,4.5712 3.49424,1.85331 7.59204,-0.15272 10.01895,-2.84219 2.41131,-2.45269 3.82251,-5.82763 3.64758,-9.28474 -0.10179,-10.12188 -8.36468,-19.85433 -18.59313,-20.7722 -0.36244,-0.0303 -0.72868,-0.047 -1.08953,-0.047 z m 286.23994,0 c -2.52621,-0.008 -5.01793,0.6181 -7.55566,0.5921 -4.81321,0.23375 -9.63248,0.22572 -14.44819,0.37897 -6.19591,0.10952 -11.1551,5.07781 -13.35865,10.54011 -1.92456,4.95093 -2.66454,10.66389 -0.90006,15.77459 1.15988,3.32939 4.16775,6.32977 7.91098,6.15817 4.53671,0 8.14094,-3.09701 11.96117,-5.06864 7.55558,-3.03978 16.29832,-0.42505 22.38289,4.5712 3.49425,1.85331 7.61569,-0.15272 10.04268,-2.84219 2.41131,-2.45269 3.82243,-5.82763 3.64758,-9.28474 -0.10179,-10.12196 -8.36468,-19.85441 -18.5932,-20.7722 -0.36245,-0.0303 -0.72861,-0.047 -1.08954,-0.047 z m -286.23994,50.47382 c -2.52629,-0.008 -5.01801,0.61817 -7.55573,0.59217 -4.81321,0.23375 -9.63241,0.22572 -14.4482,0.37897 -6.19591,0.1096 -11.13138,5.07781 -13.33493,10.54012 -1.92455,4.95085 -2.68818,10.6638 -0.92377,15.7745 1.15994,3.32947 4.16775,6.35357 7.91097,6.18197 4.53672,0 8.14094,-3.12081 11.96125,-5.09236 7.5555,-3.03986 16.32197,-0.42505 22.40654,4.57128 3.49424,1.85331 7.59204,-0.15272 10.01895,-2.84227 2.41131,-2.45276 3.82251,-5.82763 3.64758,-9.28474 -0.10179,-10.12188 -8.36468,-19.85441 -18.59313,-20.7722 -0.36244,-0.0303 -0.72868,-0.047 -1.08953,-0.0478 z m 286.23994,0 c -2.52621,-0.008 -5.01793,0.61817 -7.55566,0.59217 -4.81321,0.23375 -9.63248,0.22572 -14.44819,0.37897 -6.19591,0.1096 -11.1551,5.07781 -13.35865,10.54012 -1.92456,4.95085 -2.66454,10.6638 -0.90006,15.7745 1.15988,3.32947 4.16775,6.35357 7.91098,6.18197 4.53671,0 8.14094,-3.12081 11.96117,-5.09236 7.55558,-3.03986 16.29832,-0.42505 22.38289,4.57128 3.49425,1.85331 7.61569,-0.15272 10.04268,-2.84227 2.41131,-2.45276 3.82243,-5.82763 3.64758,-9.28474 -0.10179,-10.12188 -8.36468,-19.85441 -18.5932,-20.7722 -0.36245,-0.0303 -0.72861,-0.047 -1.08954,-0.0478 z"
       style="opacity:0.91588780999999997;fill:#99cc00;fill-opacity:1;fill-rule:nonzero;stroke:#99cc00;stroke-width:0;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:50"
       inkscape:label="#rect4314"
       inkscape:export-xdpi="72"
       inkscape:export-ydpi="72" />
  </g>
</svg>

2012-09-13

Achat in-app : attention aux signatures

APK avec signature de test vs signature développeur. 

 Le plug-in ADT pour Eclipse simplifie considérablement le travail de signature d'une application. En effet ADT signe avec une clef de test votre APK pour une future installation sur un terminal (ou émulateur).

Si pratique qu'elle soit, la clef de test sera refusée par le PlayStore : chaque développeur doit créer sa propre clef pour une signature unique.

Dans ce monde manichéen nous avons donc des APK signés avec la clef développeur sur le PlayStore et des APK signées par ADT. Et lorsqu'on essaye de faire un achat in-app :


Erreur liée à l'application
Cette version de l'application n'est pas configurée pour la facturation via Google Play. Pour plus d'informations, veuillez consulter le centre d'aide.


Ne cherchez pas trop longtemps le centre d'aide. Cette erreur est causée par la signature de l'APK.

Comment automatiser la signature avec sa clef de développement ?

Utilisons encore la documentation Android sur la signature avec jarsigner :
$ jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my.keystore \
-storepass PA55W0RDST0RE -keypass PA55W0RDKEY my.apk myDevNickName

Il y a de très fortes chances que vous obteniez ce message :

jarsigner: unable to sign jar: java.util.zip.ZipException: invalid entry compressed size (expected 765 but got 771 bytes)

Ce message, comme son code erreur ne l'indique pas, est causé par la présence d'une signature dans l'APK : vous avez utilisé l'APK créée par ADT et stockée dans workspace/MyAndroidApp/bin/ qui est en fait signée avec la clef temporaire.

Pour supprimer la précédente signature, une simple commande zip (manpage):
zip my.apk -d "META-INF/*"

En un script : signandup.sh

#!/bin/sh
zip my.apk -d "META-INF/*"
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my.keystore \
-storepass PA55W0RDST0RE -keypass PA55W0RDKEY my.apk myDevNickName
adb install -r my.apk

2012-06-28

Les détails sympas de JellyBean Android 4.1

Vous avez-vu les vidéos avec du JellyBean ? C'était rapide ? Oui ... 60 fps ça pardonne pas !

Prenons quelques minutes, statiques, et regardons vers où JellyBean nous mène.


Le nouveau logo de debug Android : une droidgibus !!

Le feedback du déplacement du doigt sur le lock-screen

Pour réduire le clavier on utilise une flèche vers le bas. Logique non ?

Les "receivers" sont affichés sur 2 colonnes ET le texte desactivé est "limite" visible.

Feedback de la position du doigt. On ne retrouve pas le même que le lockscreen mais les deux bleus holo combinés

En revanche sur la home, le feedback du lock-screen. La boule "Google" est pour "Google Now".

Application "Photo". A gauche l'application et a droite la "Galerie" avec un slide du doigt (en rouge).

Redimensionnement des widgets.

La date est complète mais compacte, L'icone pour les parametres et l'escalier pour chasser toutes les notifications.

LongClick sur une notification : on va pouvoir trouver l'application qui notifie ! Yeah !

Future option ?

Vous remarquez ? Les "switchers" sont à angles droits !

Le popup à les coins légèrement arrondis et il y a 3 gris.
Freenaute, il n'y a pas d'EAP-SIM :(


L'icône plus, très moche, n'a pas été mise à la poubelle. Pire, on lui adjoint un "refresh" "réussi".

Amélioration du menu Application : réinitialiser les associations par défaut.

Précision pertinente.

Nouveautés pertinente pour les tablettes !

Voila voila, on va pouvoir limiter les gros vilains qui fouinent sur la SD :)

Il va falloir patcher :)

C'est qui qui publie avec les options de débogage ? Hein ?

Pour faire apparaitre l'easter egg : comme pour toutes les autres versions.

Tadaaaaaaaaaaaaaaa !

Tiens ... un nouveau feedback ?

Voila, votre prochain achat sera un Nexus.

2012-06-25

Maîtrisez vos versions beta avec Zubhium

[Billet non sponsorisé]

Google Play Store

Distribuer des versions instables de ses applications via le Play Store est périlleux pour la distribution et surtout pour son image de marque.

Le principal avantage est que l'utilisateur n'a pas besoin de changer les paramètres de son terminal pour installer l'application, on bénéficie des serveurs de google et on est tiré vers le haut par les exigences (capture d'écran, bannière, description, ...).

Comme inconvénients, il y a justement la lourdeur des informations obligatoires, l'absence de kill-switch et la suppression des versions anciennes (juste désactivées). Le principal inconvénient est (de très loin) la horde de crétins insidieusement infiltrée dans le reste des utilisateurs :

Jusqu'à présent j'utilisais l'auto hébergement avec un réducteur d'URL efficace et prévenais mes volontaires par sms/mail. C'est au détour d'une lecture de StackOverFlow que j'ai découvert Zubhium ...

La solution zubhium.com


Zubhium est un service en beta et gratuit qui se propose pour l'hébergement de vos apk, la notification des nouvelles versions, le recueil des crashlogs (optionnel) et des feedback (anonymes) des utilisateurs. Il faut préalablement s'inscrire et le système est prêt à fonctionner.

Déclarer un apk

Tout commence par la déclaration de votre beta. Plus simple que Google : un nom, une icône et une description.

L'étape suivante est l'envoi de l'apk, phase très simple qui fonctionne même si on utilise l'apk signée par Eclipse (disponible dans bin/ !).

La dernière étape est la déclaration des adresses e-mail des vos cobayes. Vos cobayes n'ont pas besoin de s'inscrire, l'adresse ne sert qu'à les prévenir.

Les règles de confidentialité sont précisées ici, à vous de juger de l'opportunité de déclarer telle ou telle adresse e-mail.

Vous pouvez également distribuer un lien direct vers votre beta en le copiant/collant dans un tweet par exemple.

Déclarer une nouvelle version


Les nouvelles versions sont nommées "push". Il n'y a que deux contraintes pour faire un nouveau push ce qui rend l'opération largement plus simple que sur le Play Store. Votre apk doit avoir une version supérieure aux "push" existants et vous devez déclarer les modifications apportées.

Ces modifications seront transmises à vos volontaires dans le corps de l'email de notification. Notez que jusqu'à présent il n'est pas nécessaire d’intégrer le SDK de Zubhium à l'application.

Bloquer une ancienne version

Plusieurs raisons peuvent vous emmener à clôturer une version : cesser de recevoir des crash-logs dus à un bug résolu, orienter vers une nouvelle beta ou tout simplement passer à la version officielle sur le site marchand de Google ou Amazon.

Pour pouvoir interagir avec une ancienne beta, il faut nécessairement intégrer le SDK. La documentation est suffisamment bien rédigée pour ne pas l'aborder dans ce billet. Si vous avez des soucis on peut en causer sur twitter.

Le blocage se fait dans l'onglet "Manage" et en cliquant sur "LIVE" :

L'interface vous propose de
  • Envoyer un message qui sera affiché à chaque démarrage de l'application dont la version beta a expiré.
  • Proposer aux utilisateurs un lien vers une beta plus récente OU un store (Google ou Amazon)
  • Forcer l'utilisateur à passer à la version officielle (Google ou Amazon) en bloquant complètement l'application (Kill-switch)

Les crashlogs


Comme précisé dans la documentation, Zubhium peut servir de back-end à ACRA et ainsi agréger les informations obtenues :

En savoir plus sur le terminal:

L'état du réseau :

La pile :

Les logs (que je n'active JAMAIS) :

Et le dump :

Limite plus pratique que DDMS non ?

Bilan

Ça marche et ça marche excellemment bien ! C'est un outil bien pensé et gratuit.

Le SDK permet, sans effort de développement de garder la main sur sa beta et de récupérer les crash de manière textuelle ET graphique. J'adooooore la possibilité d'uploader un apk non signé !

Il est dommage que la fenêtre de feedback ne soit pas (encore) internationalisée, ça peut freiner les cobayes anglophobes. Il y aurait également la possibilité de faire pointer la fin d'une beta vers la toute dernière version.

Bref, je souhaite à Zubhium un bon développement et de perdurer dans la philosophie KISS et surtout de perdurer dans le temps.

Nice works guys.

2012-06-16

Appliquer un gradient XML pour le contour d'un shape


Pour l'instant (SDK API LEVEL 15) il n'est pas possible de mettre un gradient comme contour d'une forme géométrique dans un drawable.

Le contour se définit par l'élément <stroke> dans le drawable et n'accepte comme paramètre de couleur android:color qui est soit une ressource "color" soit une couleur littérale.

Je vais détailler comment faire ce contour en dégradé uniquement avec les drawables XML, donc sans utiliser de bitmap (png).

Stroke par l'exemple

Prenons le drawable XML (res/drawable/radiogroup2.xml) suivant :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#000" />
    <stroke
        android:width="3dip"
        android:color="#0af" />
    <corners android:radius="5dip" />
</shape>
que j'applique à un widget de l'interface :
<RadioGroup
            android:id="@+id/rgModeGPS"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:background="@drawable/radiogroup2" >
(...)
</RadioGroup>
Qui donne ceci :

Gradient par l'exemple

On peut s'approcher de notre objectif en utilisant un gradient (res/drawable/radiogroup3.xml) :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#000" />
    <gradient
        android:angle="270"
        android:endColor="#0048ff"
        android:startColor="#00fffc"  />
    <corners android:radius="5dip" />
</shape>
que j'applique à un widget de l'interface :
<RadioGroup
            android:id="@+id/rgModeGPS"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:background="@drawable/radiogroup3" >
(...)
</RadioGroup>
Qui donne ceci :

Solution

La solution passe par l'utilisation simultanée du dégradé et d'un rectangle noir. Pour cela il faut utiliser plusieurs couches (layer)

Le drawable XML (res/drawable/radiogroup3.xml) doit comprendre un item avec le gradient et un item avec solid noir  :
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- Définition du gradient -->
    <item
        android:bottom="0dip"
        android:left="0dip"
        android:right="0dip"
        android:top="0dip">
        <shape>
            <solid android:color="#112233" />

            <gradient
                android:angle="270"
                android:endColor="#0048ff"
                android:startColor="#00fffc" />

            <corners android:radius="5dip" />
        </shape>
    </item>
    
    <!-- Définition du fond noir -->
    <item
        android:bottom="5dip"
        android:left="5dip"
        android:right="5dip"
        android:top="5dip">
        <shape>
            <!-- Le padding aère le contenu -->
            <padding
                android:bottom="10dip"
                android:left="10dip"
                android:right="10dip"
                android:top="10dip" />

            <solid android:color="#000" />

            <corners android:radius="5dip" />
        </shape>
    </item>

</layer-list>
      Tadaaaaaaaaaaaaaa!