Android
Entorno
Compilación AOSP
Documentación clave
Tips varios
Librerías
Tutoriales
Snippets
Estructuras de datos
Sobre Diseño
Mapas
Tu clave es:
Esta clave es válida para todas las aplicaciones firmadas con el certificado cuya huella dactilar sea:
Incluimos un diseño xml de ejemplo para que puedas iniciarte por los senderos de la creación de mapas:
| <com.google.android.maps.MapView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:apiKey="0V21y2J7NRVSVKA...5C9Ag"
/>
|
Depurar
Añadir el atributo siguiente al bloque "application":
| android:debuggable="true"
|
Solicitar el permiso siguiente:
| <uses-permission android:name="android.permission.SET_DEBUG_APP" />
|
Logcat filtrado
Ejemplo de una expresión de filtrado que suprime (silencia) todos los mensajes de log excepto los que tienen el tag "ActivityManager" con una prioridad Info o superior, y los que tienen el tag "MyApp" con una prioridad Debug o superior:
| $ adb logcat ActivityManager:I MyApp:D *:S
|
Las prioridades de log son:
- V — Verbose (lowest priority)
- D — Debug
- I — Info
- W — Warning
- E — Error
- F — Fatal
- S — Silent (highest priority, on which nothing is ever printed)
Dumpsys y Dumpstate
Hace un volcado de los datos del sistema. Viene bien para encontrar componentes instalados (Aplicaciones, ContentProvider's, etc.):
Buscar CallerID
| import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode("+34976010101"));
Cursor c = getContentResolver().query(uri, new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
|
La API de Contacts de Android es muy potente y compleja. Los conceptos básicos se describen aquí.
Se manejan dos tipos de URI's:
- URI's de tipo tabla: Apuntan por ejemplo a una tabla completa como puede ser la de RawContacts.
- URI's de tipo item: Apuntan a un registro concreto de una tabla, por ejemplo un RawContact.
| import android.net.Uri;
import android.provider.ContactsContract;
Uri contactsUri = ContactsContract.Contacts.CONTENT_URI;
|
| import android.net.Uri;
import android.provider.ContactsContract;
Uri rawContactsUri = ContactsContract.RawContacts.CONTENT_URI;
|
URI de la subtabla Data
| import android.net.Uri;
import android.provider.ContactsContract;
Uri datasUri = ContactsContract.Data.CONTENT_URI;
|
| import android.net.Uri;
import android.provider.ContactsContract;
// Tenemos en rawContactUri el URI de un RawContact. Será del tipo content://com.android.contacts/raw_contacts/_id
Uri datasUri = Uri.withAppendedPath(rawContactUri, RawContacts.Entity.CONTENT_DIRECTORY);
|
Obtener ID a partir de una URI de tipo item
Por ejemplo el método para insertar un RawContact devuelve una URI de tipo item (no tabla). Para obtener el ID de dicho elemento podemos usar algunas funciones que hay en la clase ''android.content.ContentUris''.
| import android.content.ContentUris;
long rawContactId = ContentUris.parseId(rawContactUri);
|
Obtener la URI de tipo item de un elemento concreto a partir de la tabla
Por ejemplo tenemos el ID de un elemento y queremos una URI para él.
| import android.net.Uri;
import android.provider.ContactsContract;
import android.content.ContentUris;
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
|
Resumiendo:
| Significado |
URI (string) |
URI (constant) |
| URI de toda la tabla RawContacts |
content://com.android.contacts/raw_contacts |
Uri rawContactsUri = android.provider.ContactsContract.RawContacts.CONTENT_URI |
| URI de un registro concreto de RawContacts |
content://com.android.contacts/raw_contacts/<_id> |
Uri rawContactUri = ContentUris.withAppendedId(android.provider.ContactsContract.RawContacts.CONTENT_URI, rawContactId); |
| URI de una subtabla (subdirectorio lo llaman en la documentación) con los Datas asociados a un RawContact concreto |
content://com.android.contacts/raw_contacts/<_id>/entity |
Uri datasUri = Uri.withAppendedPath(rawContactUri, RawContacts.Entity.CONTENT_DIRECTORY); |
Obtener el ID de un recurso en el ContentProvider de audio externo
| String outText = "";
Uri externalMediaUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] projection = new String[] {android.provider.BaseColumns._ID};
String where = android.provider.MediaStore.MediaColumns.TITLE + "=?";
String[] whereArgs = new String[] { "Space Oddity" };
Cursor c = managedQuery(externalMediaUri, projection, where, whereArgs, null);
while (c.moveToNext()) {
for (int i = 0; i < c.getColumnCount(); i++) {
outText += c.getColumnName(i) + "= " + c.getString(i) + "\n";
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
builder.withValue(RawContacts.ACCOUNT_NAME, "vnd.sec.contact.phone");
builder.withValue(RawContacts.ACCOUNT_TYPE, "vnd.sec.contact.phone");
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "Felipito");
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
builder.withValue(CommonDataKinds.Phone.TYPE, CommonDataKinds.Phone.TYPE_MAIN);
builder.withValue(CommonDataKinds.Phone.NUMBER, "976010101");
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
builder.withValue(CommonDataKinds.Photo.PHOTO, stream.toByteArray());
builder.withValue(RawContacts.Data.IS_SUPER_PRIMARY, 1);
operationList.add(builder.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | Uri rawContactsUri = ContactsContract.RawContacts.CONTENT_URI;
String[] projection = new String[] { ContactsContract.RawContacts._ID };
String where = ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND "
+ ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND "
+ ContactsContract.RawContacts.DELETED + "=?";
String[] whereArgs = new String[] { "vnd.sec.contact.phone", "vnd.sec.contact.phone", "0" };
String sortOrder = "display_name ASC";
Cursor c = managedQuery(rawContactsUri, projection, where, whereArgs, sortOrder);
outText += rawContactsUri.toString() + "\n";
outText += c.getCount() + "\n";
while (c.moveToNext()) {
int colPos = c.getColumnIndex(ContactsContract.RawContacts._ID);
long rawContactId = Long.parseLong(c.getString(colPos));
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
rawContactId);
Uri datasUri = Uri.withAppendedPath(rawContactUri, RawContacts.Entity.CONTENT_DIRECTORY);
String name = "";
String number = "";
Bitmap bitmap = null;
String[] projection1 = new String[] { CommonDataKinds.StructuredName.DISPLAY_NAME };
String where1 = Data.MIMETYPE + "=?";
String[] whereArgs1 = new String[] { CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
Cursor c1 = managedQuery(datasUri, projection1, where1, whereArgs1, null);
if (c1.moveToNext()) {
name = c1.getString(c1.getColumnIndex(CommonDataKinds.StructuredName.DISPLAY_NAME));
c1.close();
}
String[] projection2 = new String[] { CommonDataKinds.Phone.NUMBER };
String where2 = Data.MIMETYPE + "=?";
String[] whereArgs2 = new String[] { CommonDataKinds.Phone.CONTENT_ITEM_TYPE };
Cursor c2 = managedQuery(datasUri, projection2, where2, whereArgs2, null);
if (c2.moveToNext()) {
number = c2.getString(c2.getColumnIndex(CommonDataKinds.Phone.NUMBER));
c2.close();
}
String[] projection3 = new String[] { CommonDataKinds.Photo.PHOTO };
String where3 = Data.MIMETYPE + "=?";
String[] whereArgs3 = new String[] { CommonDataKinds.Photo.CONTENT_ITEM_TYPE };
Cursor c3 = managedQuery(datasUri, projection3, where3, whereArgs3, null);
if (c3.moveToNext()) {
byte[] photo = c3.getBlob(c3.getColumnIndex(CommonDataKinds.Photo.PHOTO));
bitmap = BitmapFactory.decodeByteArray(photo, 0, photo.length);
c3.close();
}
outText += "ID= " + rawContactId + "; Nombre= " + name + "; Número= " + number;
if (bitmap != null) {
outText += "; Ancho foto= " + bitmap.getWidth() + "; Alto foto= " + bitmap.getHeight();
}
outText += "\n";
}
c.close();
|
| Uri rawContacts = ContactsContract.RawContacts.CONTENT_URI;
String where = ContactsContract.RawContacts.ACCOUNT_TYPE + "=?";
String[] whereArgs = new String[] { "es.eduardofilo.app" };
getContentResolver().delete(rawContacts, where, whereArgs);
|
| Uri rawContacts = ContactsContract.RawContacts.CONTENT_URI;
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 13);
getContentResolver().delete(rawContactUri, null, null);
|
| long rawContactId = 14;
Uri data = ContactsContract.Data.CONTENT_URI;
ContentValues values = new ContentValues();
values.put(CommonDataKinds.StructuredName.DISPLAY_NAME, "Jorgito");
String where = Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + "=?";
String[] whereArgs = new String[] { CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, Long.toString(rawContactId) };
getContentResolver().update(data, values, where, whereArgs);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | ContentValues values = new ContentValues();
values.put(RawContacts.ACCOUNT_TYPE, "vnd.sec.contact.phone");
values.put(RawContacts.ACCOUNT_NAME, "vnd.sec.contact.phone");
Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
values.put(CommonDataKinds.StructuredName.DISPLAY_NAME, "Pepito");
Uri data1Uri = getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(CommonDataKinds.Phone.TYPE, CommonDataKinds.Phone.TYPE_MAIN);
values.put(CommonDataKinds.Phone.NUMBER, "976010101");
Uri data2Uri = getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
|
Igual que antes pero hecho con el sistema de operaciones por lotes de los ContentProvider's.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
builder.withValue(RawContacts.ACCOUNT_NAME, "vnd.sec.contact.phone");
builder.withValue(RawContacts.ACCOUNT_TYPE, "vnd.sec.contact.phone");
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "Debianito");
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
builder.withValue(CommonDataKinds.Phone.TYPE, CommonDataKinds.Phone.TYPE_MAIN);
builder.withValue(CommonDataKinds.Phone.NUMBER, "976010101");
operationList.add(builder.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
|
Localizar un Launcher que no sea el nuestro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | PackageManager pm = getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
List<ResolveInfo> launchers = pm.queryIntentActivities(intent, 0);
String packageName = null;
String name = null;
for (ResolveInfo ri : launchers) {
if (!ri.activityInfo.name.equals("es.eduardofilo.app.mobile.IdentificarTerminal")) {
name = ri.activityInfo.name;
packageName = ri.activityInfo.packageName;
break;
}
}
Intent myIntent = new Intent();
myIntent.setClassName(packageName, name);
startActivity(myIntent);
|
Obtener un authToken de un Account
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | mAccountManager = AccountManager.get(this);
Account[] accounts = mAccountManager.getAccountsByType(ACCOUNT_TYPE);
for (Account account : accounts) {
outText += account.toString() + "\n";
AccountManagerFuture<Bundle> accountManagerFuture = mAccountManager.getAuthToken(account,
"es.eduardofilo.app", true, null, null);
Bundle authTokenBundle;
String token = null;
try {
authTokenBundle = accountManagerFuture.getResult();
token = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (!TextUtils.isEmpty(token)) {
outText += token + "\n";
}
}
|