lunes, 15 de octubre de 2012

Obtener los contactos del teléfono

En algunas ocasiones es posible que tengamos que facilitar el acceso a cierta información al usuario. Por ejemplo, podemos mostrarle información sobre sus contactos. Para ello podemos usar la siguiente función donde se muestra: nombre, teléfono (si tiene) y el correo:


private void GetContacts(ArrayList<String> contactList) {

Cursor cursor = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while (cursor.moveToNext()) {
String information = "";
String contactName = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY));
String contactId = cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
information = contactName;

String hasPhone = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
if (Boolean.parseBoolean(hasPhone)) {
Cursor phones = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = " + contactId, null, null);
while (phones.moveToNext()) {
String phoneNumber = phones
.getString(phones
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
information += " " + phoneNumber;
}
phones.close();
}

Cursor emails = getContentResolver().query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = "
+ contactId, null, null);
while (emails.moveToNext()) {
String emailAddress = emails
.getString(emails
.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
information += "\n" + emailAddress;
}
emails.close();

contactList.add(information);
}
cursor.close();
}

It works!
Roger Sala

Spinner: Estáticos, dinámicos y personalizados

En algunas situaciones nuestra aplicación puede requerir de un selector de elementos. En Android, este selector se puede crear de 3 formas distintas:

  • Estáticos: creando un array en el fichero res/values/strings.xml
  • Dinámicos: rellenando el selector dentro de nuestra activity/Fragment.
  • Personalizado: Con estática o dinámica información pero con nuestro propio layout.
En el ejemplo de este post, vamos a ver los tres tipos. A continuación les dejo el código para que lo puedan incorporar a sus proyectos si lo consideran oportuno.

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="XXXXXX"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

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

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

</manifest>

strings.xml
<resources>

    <string name="app_name">BlogSpinner</string>
    <string name="title_activity_spinner">BlogSpinner</string>
    <string name="my_prompt">Escoge tu opción</string>

    <string-array name="os_arrays">
        <item>Android</item>
        <item>iOS</item>
        <item>Symbian</item>
        <item>Windows Phone</item>
    </string-array>

</resources>


//Vista principal de la aplicación que contiene los 3 Spinners
activity_spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Spinner
        android:id="@+id/spinner_static"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dip"
        android:entries="@array/os_arrays"
        android:prompt="@string/my_prompt" />

    <Spinner
        android:id="@+id/spinner_dynamic"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dip" />

    <Spinner
        android:id="@+id/spinner_custom"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dip" />

</LinearLayout>

//Spinner personalizado
custom_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/textview_spinner_custom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="15dip"
        android:textColor="@android:color/darker_gray"
        android:textSize="14sp"
        android:textStyle="bold" />
</LinearLayout>


SpinnerActivity.java

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

public class SpinnerActivity extends Activity {

private Spinner mSpinnerDynamic, mSpinnerStatic, mSpinnerCustom;
private final int N_ITEMS = 10;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spinner);

mSpinnerDynamic = (Spinner) findViewById(R.id.spinner_dynamic);
mSpinnerCustom = (Spinner) findViewById(R.id.spinner_custom);
mSpinnerStatic = (Spinner) findViewById(R.id.spinner_static);

addItemsOnSpinnerDynamic();
addItemsOnSpinnerCustom();

mSpinnerDynamic.setOnItemSelectedListener(myItemSelectedListener);
mSpinnerStatic.setOnItemSelectedListener(myItemSelectedListener);
mSpinnerCustom.setOnItemSelectedListener(myItemSelectedListener);
}

public void addItemsOnSpinnerDynamic() {

List<String> dynamicList = new ArrayList<String>();
for (int i = 0; i < N_ITEMS; i++) {
dynamicList.add("item dynamic " + i);
}

ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, dynamicList);
dataAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinnerDynamic.setAdapter(dataAdapter);
}

private void addItemsOnSpinnerCustom() {
List<String> customList = new ArrayList<String>();
for (int i = 0; i < N_ITEMS/2; i++) {
customList.add("item custom " + i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.custom_row, R.id.textview_spinner_custom, customList);
mSpinnerCustom.setAdapter(adapter);
}

private OnItemSelectedListener myItemSelectedListener = new Spinner.OnItemSelectedListener() {

public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
Toast.makeText(
parent.getContext(),
"Item selected : "
+ parent.getItemAtPosition(pos).toString(),
Toast.LENGTH_SHORT).show();
}

@Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
};

}


A continuación les dejo las tres capturas de pantalla (estático, dinámico y personalizado):





It works!
Roger Sala,

miércoles, 26 de septiembre de 2012

Añadir accesos directos

Dependiendo de las funcionalidades que ofrezca nuestra aplicación, nos puede interesar que el usuario pueda añadir accesos directos a ellas. Así pues para llegar a esa opción no será necesario abrir y navegar por la aplicación.
Para crear accesos directos podemos hacerlo de dos formas: Podemos permitir que el usuario tenga la opción de añadirla manualmente (por ejemplo, usando un botón en la app que cree el acceso) o bien, navegando por el sistema (dónde se encuentran el resto de accesos de las otras aplicaciones).

Así pues, en este ejemplo vamos a mostrar com permitir al usuario añadir un acceso directo a partir de la aplicación, ya que, la segunda opción es obvia.

En la aplicación veremos 2 activities, la primera que contendrá el botón que añadirá el acceso a la segunda activity. Sólo ser accesible a partir del acceso directo.

strings.xml

<resources>

    <string name="app_name">BlogShortCut</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">BlogShortCut</string>
    
    <string name="addShortcut">Add shortcut to HomeScreen</string>

    <string name="shortcut">ShortcutExample</string>
    <string name="activityShortcut">I\'m shortCut Activity!</string>

</resources>


AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.blogshortcut"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <application
        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>
        <activity android:name=".ShortCutActivity" >
            <intent-filter>
                <action android:name="android.intent.action.CREATE_SHORTCUT" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button_add_shortcut"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="50dip"
        android:gravity="center"
        android:text="@string/addShortcut" >
    </Button>

</LinearLayout>

activity_shortcut.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textview_intent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:padding="@dimen/padding_medium"
        android:text="@string/activityShortcut" />

</RelativeLayout>

MainActivity.java
package com.example.blogshortcut;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// allow install shortcuts from homescreen

((Button) findViewById(R.id.button_add_shortcut))
.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// comprobamos que el dispositivo puede crear el acceso directo
if (getPackageManager()
.queryBroadcastReceivers(
new Intent(
"com.android.launcher.action.INSTALL_SHORTCUT"),
0).size() > 0) {
createShortCut();
} else {
Toast.makeText(MainActivity.this,
"cannot add shortcut", Toast.LENGTH_SHORT)
.show();
}

}
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

private void createShortCut() {

Intent shortcutIntent = new Intent(this, ShortCutActivity.class);
shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
shortcutIntent.putExtra("myParameter", "Parameter from Intent");
shortcutIntent.putExtra("shortcut", "no");

Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra("duplicate", false); //evitamos duplicados
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getResources()
.getString(R.string.activityShortcut));
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this,
R.drawable.YOUR_ICON));
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
sendBroadcast(addIntent);
}
}

ShortCutActivity.java
package com.example.blogshortcut;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;

public class ShortCutActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shortcut);

Bundle extras = getIntent().getExtras();
if (extras != null) {
String intentText = extras.getString("myParameter");
if (!"".equals(intentText)) {
((TextView) findViewById(R.id.textview_intent))
.setText(intentText);
}
}
if (extras == null) {
createShortCut();
}

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

private void createShortCut() {
Intent shortcutIntent = new Intent(this, ShortCutActivity.class);
shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
shortcutIntent.putExtra("myParameter", "Parameter from Intent");
shortcutIntent.putExtra("shortcut", "no");

Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra("duplicate", false);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getResources()
.getString(R.string.activityShortcut));
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this,
R.drawable.ic_shortcut));
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
sendBroadcast(addIntent);
}
}


A continuación la imagen del shortcut creado:


It works!
Roger Sala,






miércoles, 19 de septiembre de 2012

Crear Widget

Cuando creamos una app nos puede interesar darle al usuario la posibilidad de añadir un widget en el escritorio como, por ejemplo, Twitter o Foursquare.

Para ello podemos usar el siguiente código. En ello podemos ver, cómo:

1.- Se crea la clase Widget que usa AppWidgetProvider.
2.- Se implementa el método onUpdate que se llama al añadir el Widget en el escritorio. El método onReceive para capturar los eventos que se producen (por ejemplo, pulsado de un botón).
3.- Se gestiona el AndroidManifest.xml
4.- Se crea la interfaz gestora del widget (el gestor). widgetproviderinfo.xml
5.- En widgetproviderinfo.xml podemos ver los campos android:minResizeWidth,
    android:minResizeHeight y android:resizeMode que nos permiten cambiar el tamaño de los widgets. 

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.blogwidgetexample"
    android:installLocation="internalOnly"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name=".BlogWidgetExample" >
            <intent-filter>
             <!-- Se usa para gestionar los eventos de los botones-->
                <action android:name="com.example.blogwidgetexample.ACTION_WIDGET_SHOW" />
                <action android:name="com.example.blogwidgetexample.ACTION_WIDGET_HIDDEN" />
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widgetproviderinfo" />
        </receiver>
    </application>
</manifest>

Creamos en res/xml
widgetproviderinfo.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/activity_blog_widget_example"
    android:minHeight="130dp"
    android:minWidth="170dp"
    android:minResizeWidth="30dp"
    android:minResizeHeight="30dp"
    android:resizeMode="horizontal|vertical" />

BlogWidgetExample.java
package com.example.blogwidgetexample;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

public class BlogWidgetExample extends AppWidgetProvider {
public static final String WIDGETTAG = "WidgetMood";
// our actions for our buttons
public static String ACTION_WIDGET_HIDDEN = "ActionReceiverHidden";
public static String ACTION_WIDGET_SHOW = "ActionReceiverShow";

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);

RemoteViews remoteViews;

remoteViews = new RemoteViews(context.getPackageName(),
R.layout.activity_blog_widget_example);
remoteViews.setTextViewText(R.id.clicked, "Button not clicked");

// Button hidden
Intent active = new Intent(context, BlogWidgetExample.class);
active.setAction(ACTION_WIDGET_HIDDEN);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context,
0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.button_hidden,
actionPendingIntent);

// Button show
active = new Intent(context, BlogWidgetExample.class);
active.setAction(ACTION_WIDGET_SHOW);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.button_show,
actionPendingIntent);

appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}

@Override
public void onReceive(Context context, Intent intent) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.activity_blog_widget_example);

if (intent.getAction().equals(ACTION_WIDGET_HIDDEN)) {
Log.i("onReceive", ACTION_WIDGET_HIDDEN);
Toast.makeText(context, ACTION_WIDGET_HIDDEN, Toast.LENGTH_SHORT)
.show();
remoteViews.setTextViewText(R.id.clicked, ACTION_WIDGET_HIDDEN);

} else if (intent.getAction().equals(ACTION_WIDGET_SHOW)) {
Log.i("onReceive", ACTION_WIDGET_SHOW);
Toast.makeText(context, ACTION_WIDGET_SHOW, Toast.LENGTH_SHORT)
.show();
remoteViews.setTextViewText(R.id.clicked, ACTION_WIDGET_SHOW);

}
ComponentName cn = new ComponentName(context, BlogWidgetExample.class);
AppWidgetManager.getInstance(context).updateAppWidget(cn, remoteViews);
super.onReceive(context, intent);

}
}

activity_blog_widget_example.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/white" >
    <TextView
        android:id="@+id/clicked"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dip"
        android:padding="@dimen/padding_medium"
        android:text="@string/hello_world"
        android:textColor="@android:color/black"
        tools:context=".BlogWidgetExample" />
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/clicked" >
        <Button
            android:id="@+id/button_hidden"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hidden"
            android:textColor="@android:color/black" />
        <Button
            android:id="@+id/button_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Show"
            android:textColor="@android:color/black" />
    </LinearLayout>
</RelativeLayout>


A continuación podemos ver una imagen de nuestro Widget:




It works!
Roger Sala,