Accediendo a la lista de contactos Android



Esta unidad nos muestra cómo se accede a nuestros contactos del móvil Android. Inicialmente en la "Contact list" nos muestra el nombre y pulsando sobre cualquiera de ellos veremos la información de detalle en la caja  inferior. Probado en Rad Studio XE10. Tener en cuenta que en vuestra app tendréis que activar el permiso "Read contacts" para que funcione correctamente.
  





unit ContactsManager;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Helpers.Android,Androidapi.JNI.provider, Androidapi.JNI.JavaTypes,
  Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Net, Androidapi.Jni.App,
  Androidapi.JNIBridge, Androidapi.Helpers;

Type
  // Record for contact data
  TContactData = Record
    LookupID : string;
    Display_Name : String;  // Display name : in almost smartphone it's last name + space + First name
    FamilyName   : String;
    FirstName   : String;
    Email : String;
    Phone : string;
  End;
  PContactData = ^TContactData;   // Pointer to record

  // This class manage contact data
  TContactsManager = class
    private
      fContactsList : TList;           // List of contacts
      procedure ClearList;             // procedure to clear contacts list
      function GetContactsCount : integer;    // Retrieveing contacts number
      function GetContact(AIndex : Integer) : PContactData;   //Access a contact record

      procedure GetContactExtendedData(AContact : PContactData); // Retrieve extended data for a contact (Email, Phone, ....)
    public
      constructor Create;
      Destructor Destroy;override;

      procedure ExtractContactsList;          //Retrieve all contacts

      property Contacts[AIndex : Integer] : PContactData read GetContact;
      property ContactsCount : Integer read GetContactsCount;
  end;


implementation



{ TContactManager }

{-------------------------------------------------------------------------------
  Procedure: TContactsManager.ClearList : Clear contacts list
  DateTime:  2014.01.02
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
procedure TContactsManager.ClearList;
var i : integer;
    wContact : PContactData;
begin
  for i := fContactsList.Count -1 downto 0 do   // for all contacts
  begin
    wContact := fContactsList[i];
    Dispose(wContact);                         // free contact memory
    fContactsList.Delete(i);                   // Delete contact entry
  end;
end;


{-------------------------------------------------------------------------------
  Procedure: TContactsManager.Create
  DateTime:  2014.01.02
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
constructor TContactsManager.Create;
begin
  fContactsList := TList.Create;  // Create contact ilst object
end;



{-------------------------------------------------------------------------------
  Procedure: TContactsManager.Destroy
  DateTime:  2014.01.02
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
destructor TContactsManager.Destroy;
begin
  ClearList;          // clear contacts list
  fContactsList.Free; // destroy contacts list
  inherited;
end;


{-------------------------------------------------------------------------------
  Procedure: TContactsManager.GetContact
  DateTime:  2014.01.02
  Arguments: AIndex: Integer
  Result:    PContactData
-------------------------------------------------------------------------------}
function TContactsManager.GetContact(AIndex: Integer): PContactData;
begin
  try
    if AIndex > fContactsList.Count -1 then
      raise Exception.Create('Index out of bounds');
    Result := fContactsList[AIndex]                // return contact data from index
  except
    On E:Exception do
      Raise Exception.create('[TContactManager.GetContact] : '+E.message);
  end;
end;


{-------------------------------------------------------------------------------
  Procedure: TContactsManager.ExtractContactsList : Retrieve all contacts
  DateTime:  2014.01.02
  Arguments: None
  Result:    None
-------------------------------------------------------------------------------}
procedure TContactsManager.ExtractContactsList;
var
  wUri : JNet_URI;
  wCursor : JCursor;
  wLookup_Idx : Integer;
  wDisplayNameIdx : integer;
  wContact : PContactData;
begin
  try
    ClearList;
    wUri :=  TJContactsContract_Contacts.JavaClass.CONTENT_URI;   // Contact  URI
    with  SharedActivity.getContentResolver do
      wCursor :=query(wUri,nil, nil,nil, StringToJString('display_name ASC')); // Query to get all contact sorted by displayname
    try
      wLookup_Idx := wCursor.getColumnIndex(StringToJString('lookup')); //Getting id column index
      wDisplayNameIdx := wCursor.getColumnIndex(StringToJString('display_name'));  // getting displayname column index
      while (wCursor.moveToNext) do  // for each row
      begin
        New(wContact);      // Create a new contact record
        wContact.LookupID      := JStringToString(wCursor.getString(wLookup_Idx));    // Set contact ID
        wContact.Display_Name  := JStringToString(wCursor.getString(wDisplayNameIdx));  //Set contact displayname
        GetContactExtendedData(wContact);   // Extract extended data (to get first name, last name, Email, Phone..)
        fContactsList.Add(wContact);        // Add contact to list
      end;
    finally
      wCursor.close;    // Close table cursor
      wCursor := nil;
    end;
  except
    On E:Exception do
      Raise Exception.create('[GetContactsList] : '+E.message);
  end;

end;


{-------------------------------------------------------------------------------
  Procedure: TContactsManager.GetContactExtendedData  : get additional data for a contact
  DateTime:  2014.01.02
  Arguments: AContact : PContactData
  Result:    None
-------------------------------------------------------------------------------}
procedure TContactsManager.GetContactExtendedData(AContact : PContactData);
var
  wSubCursor : JCursor;
  wfilter : TJavaObjectArray;
  wJQueryParams : TJavaObjectArray;
  wDataUri : JNet_URI;
begin
  try
    // Filter to extract only familyname, first name1 and first name 2 (http://developer.android.com/reference/android/provider/ContactsContract.DataColumns.html)
    wfilter := TJavaObjectArray.Create(3);
    wfilter[0] := TJCommonDataKinds_StructuredName.JavaClass.FAMILY_NAME;
    wfilter[1] := TJCommonDataKinds_StructuredName.JavaClass.GIVEN_NAME;
    wfilter[2] := TJCommonDataKinds_StructuredName.JavaClass.MIDDLE_NAME;

    // Qurey condition (Exrtact only data for specific ID)
    wJQueryParams := TJavaObjectArray.Create(2);
    wJQueryParams[0] := TJCommonDataKinds_StructuredName.JavaClass.CONTENT_ITEM_TYPE;
    wJQueryParams[1] := StringToJString(AContact.LookupID);

    wDataUri := TJContactsContract_Data.JavaClass.CONTENT_URI;  // Contacts data uri

    with SharedActivity.getContentResolver do
      wSubCursor := Query(wDataUri,wfilter,StringToJString('mimetype = ? AND lookup = ?') , wJQueryParams,nil); // Exec query
    Try
      if wSubCursor.getCount > 0 then // if query return some data
      begin
        // Getting only first row, as we retrieving only names, a contact can have only one first name, one familyname,
        // for phone number for example, we need to loop on each row (while (wSubCursor.moveToNext) do) because a contact can have many phone number
        wSubCursor.moveToNext;
        AContact.FamilyName := JStringToString(wSubCursor.getString(0));
        AContact.FirstName := JStringToString(wSubCursor.getString(1)) + ' ' + JStringToString(wSubCursor.getString(2));
      end;
    Finally
      wSubCursor.close;
      wSubCursor := nil;
    End;

    // ------------- EMAIL -----------------------------
    // Filter to extract Email only
    wfilter := TJavaObjectArray.Create(1);
    wfilter[0] := TJCommonDataKinds_Email.JavaClass.ADDRESS;

    // Qurey condition (Exrtact only data for specific ID)
    wJQueryParams := TJavaObjectArray.Create(2);
    wJQueryParams[0] := TJCommonDataKinds_Email.JavaClass.CONTENT_ITEM_TYPE;
    wJQueryParams[1] := StringToJString(AContact.LookupID);

    wDataUri := TJContactsContract_Data.JavaClass.CONTENT_URI;  // Contacts data uri
    with SharedActivity.getContentResolver do
      wSubCursor := Query(wDataUri,wfilter,StringToJString('mimetype = ? AND lookup = ?') , wJQueryParams,nil); // Exec query
    Try
      if wSubCursor.getCount > 0 then // if query return some data
      begin
        // Getting only first email , a contact can have many emails, so if needed,
        // we need to loop on each row (while (wSubCursor.moveToNext) do)
        wSubCursor.moveToNext;
        AContact.Email := JStringToString(wSubCursor.getString(0));
      end;
    Finally
      wSubCursor.close;
      wSubCursor := nil;
    End;

    // ------------- PHONE -----------------------------
    // Filter to extract Email only
    wfilter := TJavaObjectArray.Create(1);
    wfilter[0] := TJCommonDataKinds_Phone.JavaClass.NUMBER;

    // Qurey condition (Exrtact only data for specific ID)
    wJQueryParams := TJavaObjectArray.Create(2);
    wJQueryParams[0] := TJCommonDataKinds_Phone.JavaClass.CONTENT_ITEM_TYPE;
    wJQueryParams[1] := StringToJString(AContact.LookupID);

    wDataUri := TJContactsContract_Data.JavaClass.CONTENT_URI;  // Contacts data uri
    with SharedActivity.getContentResolver do
      wSubCursor := Query(wDataUri,wfilter,StringToJString('mimetype = ? AND lookup = ?') , wJQueryParams,nil); // Exec query
    Try
      if wSubCursor.getCount > 0 then // if query return some data
      begin
        // Getting only first phone number , a contact can have multiple phone numbers, so if needed,
        // we need to loop on each row (while (wSubCursor.moveToNext) do)
        wSubCursor.moveToNext;
        AContact.Phone := JStringToString(wSubCursor.getString(0));
      end;
    Finally
      wSubCursor.close;
      wSubCursor := nil;
    End;
  except
    On E:Exception do
      Raise Exception.create('[TContactsManager.GetContactExtendedData] : '+E.message);
  end;
end;


{-------------------------------------------------------------------------------
  Procedure: TContactsManager.GetContactsCount
  DateTime:  2014.01.02
  Arguments: None
  Result:    integer
-------------------------------------------------------------------------------}
function TContactsManager.GetContactsCount: integer;
begin
  Result := fContactsList.Count;
end;
end.

Para ver los contactos tendríamos que poner un ListBox (para mostrar la lista de nuestros contactos) y un tMemo para ver la información de cada uno de ellos.
En el evento OnClic del ListBox tendríamos:



const
  wCRLF = #13#10;
begin
  if LstContacts.ItemIndex <> -1 then
  begin
    with fContactsManager do
    begin
      lbcontactDetails.Text := wCRLF+
        'ID          : ' + Contacts[LstContacts.ItemIndex].LookupID   + wCRLF+
        'Family Name : ' + Contacts[LstContacts.ItemIndex].FamilyName + wCRLF+
        'First Name  : ' + Contacts[LstContacts.ItemIndex].FirstName  + wCRLF+
        'Email       : ' + Contacts[LstContacts.ItemIndex].Email      + wCRLF+
        'Phone       : ' + Contacts[LstContacts.ItemIndex].Phone;
    end;
  end;
end;



Y en el OnCreate del Form lo siguiente:


procedure TForm2.FormCreate(Sender: TObject);
var i : integer;
begin
  fContactsManager := TContactsManager.Create;

  fContactsManager.ExtractContactsList;

  lbContactsList.Text := Format('Contacts list (%d)',[fContactsManager.ContactsCount]);
  LstContacts.BeginUpdate;
  try
    for i := 0 to fContactsManager.ContactsCount -1 do
    begin
      LstContacts.Items.Add(fContactsManager.Contacts[i].Display_Name);
    end;
  finally
    LstContacts.EndUpdate;
  end;
end;

Link de descarga

Fuente: http://www.fmxexpress.com/access-android-contacts-manager-with-firemonkey-in-delphi-xe5/

Launcher para Android


Resultado de imagen de lanzador de apps
La unidad que os muestro a continuación lista los nombres de todas las apps del móvil y las almacena en un tListView, de tal forma que cuando pulsamos sobre un ítem se nos abrirá la app a la que hace referencia.
Incorpora un buscador incremental que utiliza la propiedad OnChange del tEdit lo que hace que a medida que vamos tecleando el nombre de una app nos muestre aquellas que contienen ese texto en su nombre. Es interesante observar que junto con el nombre de la app, obtiene el bitmap de su icono, lo que da un toque más profesional al conjunto. Al compilarlo Rad Studio xe10 me avisa que la propiedad SharedActivity está "depreciated" en su lugar recomienda usar TAndroidHelper.Activity , tenerlo en cuenta por si os da algún problema al iniciarlo.
unit Unitmain;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  System.Generics.Collections, System.Threading, System.IOUtils,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.ListView.Types, FMX.Controls.Presentation, FMX.Edit, FMX.ListView,
  FMX.Layouts,
  FMX.Surfaces,
  Androidapi.JNI.GraphicsContentViewText,
  FMX.Helpers.Android,
  Androidapi.Helpers,
  Androidapi.JNI.JavaTypes,
  Androidapi.Jni,
  Androidapi.JNIBridge,
  Androidapi.JNI.App,
  FMX.StdCtrls, FMX.ListView.Appearances,
  FMX.ListView.Adapters.Base;


type
  TFormMain = class(TForm)
    layFind: TLayout;
    layAppList: TLayout;
    AppListView: TListView;
    txtFind: TEdit;
    ClearEditButton1: TClearEditButton;
    procedure FormCreate(Sender: TObject);
    procedure AppListViewItemClick(const Sender: TObject;
      const AItem: TListViewItem);
    procedure txtFindTyping(Sender: TObject);
    procedure txtFindChange(Sender: TObject);
  private
    { Private declarations }
    MainList : TList;
    dictAppIcons : TDictionary;
    procedure LoadActivityInfoList(var List : TList);
    procedure LoadDictonaryAppIcons(index : Integer; appInfo : JApplicationInfo;
        var dictonaryAppIcons : TDictionary);
    procedure LoadListView(listView : TListView; AppList: TList;
        dictonaryAppIcons : TDictionary);
    procedure OpenApp(PackageName, AppName : JString);
    procedure FilterListView(listView : TListView; filterName : string);
    procedure LoadListViewBitmap(listView: TListView; AppList: TList;
        var dictonaryAppIcons : TDictionary);
    function GetActivityAppList : JList;
    function GetOrSetCashAppIcon(appInfo : JApplicationInfo) : TBitmap;

  public
    { Public declarations }
  end;
const
    DEFAUT_INDEX : Integer = -1;
var
  FormMain: TformMain;

implementation

{$R *.fmx}

{ TformMain }
{------------------------------------------------------------------------------}
procedure TformMain.OpenApp(PackageName, AppName : JString);
var
    Intent : JIntent;
    NativeComponent : JComponentName;
begin
    Intent := TJIntent.Create;
    Intent.setAction(TJIntent.JavaClass.ACTION_MAIN);
    Intent.addCategory(TJIntent.JavaClass.CATEGORY_LAUNCHER);
    NativeComponent := TJComponentName.JavaClass.init(PackageName, AppName);
    Showmessage(JstringtoString(PackageName)+'--'+JstringtoString(AppName));
    Intent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK or TJIntent.JavaClass.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    Intent.setComponent(NativeComponent);
    SharedActivity.startActivity(Intent);
end;
{------------------------------------------------------------------------------}
procedure TformMain.txtFindChange(Sender: TObject);
begin
  if txtFind.Text='' then
   FilterListView(self.AppListView,  txtFind.Text.Trim);
end;

procedure TformMain.txtFindTyping(Sender: TObject);
begin
    FilterListView(self.AppListView,  txtFind.Text.Trim);
end;
{------------------------------------------------------------------------------}
procedure TformMain.AppListViewItemClick(const Sender: TObject;
  const AItem: TListViewItem);
begin
    if not Assigned(MainList) then
        Exit;
    OpenApp(MainList.Items[AItem.Tag].applicationInfo.packageName,
        MainList.Items[AItem.Tag].name);
end;
{------------------------------------------------------------------------------}
procedure TformMain.FilterListView(listView : TListView; filterName : string);
var
    i : integer;
    item : TListViewItem;
    lower : string;
begin
    if not Assigned(listView) then
        exit;
    lower := filterName.ToLower.Trim;
    if lower.IsEmpty then
    begin
        if Assigned(listView.Items.Filter) then
            listView.Items.Filter := nil;
    end
    else
    begin
        listView.ItemIndex := DEFAUT_INDEX;
        listView.Items.Filter :=
            function(sFilter : string) : Boolean
            begin
                Result := (lower.IsEmpty) or sFilter.ToLower.Contains(lower);
            end;
    end;
end;
{------------------------------------------------------------------------------}
procedure TformMain.FormCreate(Sender: TObject);
begin
    LoadActivityInfoList(MainList);
    LoadListView(Self.AppListView, MainList, self.dictAppIcons);
    LoadListViewBitmap(Self.AppListView, MainList, self.dictAppIcons);
    Self.AppListView.show;
end;
{------------------------------------------------------------------------------}
function TformMain.GetActivityAppList: JList;
var
    tempList : JList;
    Intent : JIntent;
    Manager : JPackageManager;
begin
    Intent := TJIntent.Create;
    Intent.setAction(TJIntent.JavaClass.ACTION_MAIN);
    Intent.addCategory(TJIntent.JavaClass.CATEGORY_LAUNCHER);
    Manager := SharedActivity.getPackageManager;
    tempList := nil;
    tempList := Manager.queryIntentActivities(Intent, 0);
    Result := tempList;
end;
{------------------------------------------------------------------------------}
function TformMain.GetOrSetCashAppIcon(appInfo: JApplicationInfo): TBitmap;
var
    Drawable : JDrawable;
    Bitmap : JBitmap;
    itemBitmap : TBitmap;
    Surface : TBitmapSurface;
    saveDir : string;
    pngFileName : string;
    SaveParams: TBitmapCodecSaveParams;
begin
    if not Assigned(appInfo) then
    begin
        Result := itemBitmap;
        exit;
    end;

    saveDir := TPath.GetCachePath;
    pngFileName := saveDir + '/' + JStringToString(appInfo.packageName) + '.png';
    itemBitmap := TBitmap.Create;
    if not TDirectory.Exists(saveDir, False) then
        TDirectory.CreateDirectory(saveDir);
     if TFile.Exists(pngFileName) then
        itemBitmap.LoadFromFile(pngFileName)
    else
    begin
        Drawable := appInfo.loadIcon(SharedActivity.getPackageManager);
        Bitmap := TJBitmapDrawable.Wrap((Drawable as ILocalObject).GetObjectID).getBitmap;
        Surface := TBitmapSurface.Create;
        try
            if JBitmapToSurface(Bitmap, Surface) then
                begin
                        itemBitmap.Assign(Surface);
                        SaveParams.Quality := 100;
                        itemBitmap.SaveToFile(pngFileName, @SaveParams);
                end;
        finally
            Surface.Free;
        end;
    end;
    Result := itemBitmap;
end;
{------------------------------------------------------------------------------}
procedure TformMain.LoadActivityInfoList(var List: TList);
var
    tempList : JList;
    i : Integer;
    ResolveInfo : JResolveInfo;
    Info : JActivityInfo;
    AppInfo : JApplicationInfo;
begin
    if not Assigned(List) then
        List := TList.Create;
    List.Clear;
    tempList := Self.GetActivityAppList;
    for i := 0 to tempList.size - 1 do
    begin
        ResolveInfo := TJResolveInfo.Wrap((tempList.get(i) as ILocalObject).GetObjectID);
        Info := TJActivityInfo.Wrap((ResolveInfo.activityInfo as ILocalObject).GetObjectID);
        AppInfo := TJApplicationInfo.Wrap((Info.applicationInfo as ILocalObject).GetObjectID);
        List.Add(Info);
    end;

end;
{------------------------------------------------------------------------------}
procedure TformMain.LoadDictonaryAppIcons(
  index : Integer; appInfo : JApplicationInfo; var dictonaryAppIcons : TDictionary);
var
    itemBitmap : TBitmap;
begin
    if not Assigned(dictonaryAppIcons) then
        dictonaryAppIcons := TDictionary.Create;
    if not dictonaryAppIcons.ContainsKey(index) then
    begin
        itemBitmap := GetOrSetCashAppIcon(appInfo);
        dictonaryAppIcons.AddOrSetValue(index, itemBitmap);
    end;
end;
{------------------------------------------------------------------------------}
procedure TformMain.LoadListView(listView: TListView; AppList: TList;
    dictonaryAppIcons : TDictionary);
var
    tempItem : TListViewItem;
    tempString, tempSubString, tempSubString2 : string;
    i : integer;
begin
    if (not Assigned(listView)) or (not Assigned(AppList)) then
        exit;
    listView.Items.clear;
    listView.BeginUpdate;
    for I := 0 to AppList.Count - 1 do
    begin
        tempString := JStringToString(AppList.Items[i].applicationInfo.loadLabel(SharedActivity.getPackageManager).toString);
        tempItem := listView.Items.Add;
        tempItem.Text := tempString;
        tempItem.Tag := i;
    end;
    listView.EndUpdate;
end;
{------------------------------------------------------------------------------}
procedure TformMain.LoadListViewBitmap(listView: TListView; AppList: TList;
    var dictonaryAppIcons : TDictionary);
var
    i : integer;
begin
    if (not Assigned(listView)) or (not Assigned(AppList)) then
        exit;
    listView.BeginUpdate;
    for I := 0 to listView.ItemCount - 1 do
    begin
        listView.Items[i].BeginUpdate;
        LoadDictonaryAppIcons(i, AppList.Items[listView.Items[i].Tag].applicationInfo, dictonaryAppIcons);
        if Assigned(dictonaryAppIcons) and (dictonaryAppIcons.ContainsKey(i)) then
            listView.Items[i].Bitmap := dictonaryAppIcons.Items[i];
        listView.Items[i].EndUpdate;
        Application.ProcessMessages;
    end;
    listView.EndUpdate;
end;
{------------------------------------------------------------------------------}
end.
Descargar código
Fuente: https://github.com/FMXExpress/Firemonkey/tree/master/FMXExpress/PackageList

Utilizar Intents en rad studio 10

Un intent sirve para hacer una llamada a componentes de la interfaz gráfica, servicios, código que se ejecutan en segundo plano como los  broadcast receivers, broadcast messages, etc ( en android se llaman activities).

En rad studio podemos acceder a los Intents a través de la clase JIntent que está en la Unit 
Androidapi.JNI.GraphicsContentViewText.

Las activities son parecidos a los forms de Delphi y tienen 2 partes, la parte lógica y la parte gráfica.
La parte lógica es un archivo .java que se usa para manipular, interactuar con el código de esa actividad. La parte gráfica es un archivo XML que tiene definidos todos los elementos del form con etiquetas parecidas al HTML.
En definitiva un intent sirve para llamar a aplicaciones externas a la nuestra, lanzar eventos a los que otras aplicaciones puedan responder, lanzar alarmas, etc.
Desde el link developer.android.com/guide/appendix/g-app-intents.html podéis encontrar una lista con las aplicaciones disponibles en Android junto con los intents que las invocan.

Por ejemplo, para el navegador web, tenemos dos acciones, VIEW y WEB_SEARCH, que abren el navegador en una url específica o realizan una búsqueda.
En el caso del dialer (marcador), tenemos las acciones CALL y DIAL, que vienen dadas por la URI tel:numero_de_teléfono, la diferencia entre estas dos acciones, es que CALL realiza la llamada al número de la URI, y DIAL solo lo marca, pero no realiza la llamada.


Ejemplos para rad studio 10 Seattle

-Abrir una URL
-Abrir un archivo PDF 
-
Enviar un texto 
-
Enviar un email 
-
Obtener el estado de la batería


-Obtener la versión de la aplicación
-Comprobar que una app tiene un permiso determinado para enviar un SMS

Abrir una URL
uses
  Androidapi.JNI.GraphicsContentViewText,
  FMX.Helpers.Android;


procedure TForm3.Button1Click(Sender: TObject);
var
  Intent: JIntent;
begin
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
  Intent.setData(StrToJURI('http://www.google.com'));
  SharedActivity.startActivity(Intent);
end;


Abrir un archivo PDF
uses
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNI.JavaTypes,
  FMX.Helpers.Android;


procedure TForm3.Button1Click(Sender: TObject);
var
  Intent: JIntent;
begin
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
  Intent.setDataAndType(StrToJURI('filepath'),  StringToJString('application/pdf'));
  SharedActivity.startActivity(Intent);
end;

Enviar un texto
procedure THeaderFooterForm.Button2Click(Sender: TObject);
var
  Intent: JIntent;
begin
  // Intent intent = new Intent(Intent.ACTION_SEND);
  // intent.setType("text/plain");
  // intent.putExtra(android.content.Intent.EXTRA_TEXT, "Android Rocks!!!");
  // startActivity(intent);

  Intent := TJIntent.Create;
  Intent.setType(StringToJString('text/plain'));
  Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
  Intent.putExtra(TJIntent.JavaClass.EXTRA_TEXT,
    StringToJString('Delphi Rocks!!!'));
  MainActivity.startActivity(Intent);
end;

Enviar un email
Uses
Androidapi.JNI.GraphicsContentViewText, Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, FMX.Helpers.Android, Androidapi.JNI.Net, Androidapi.JNI.Os, Androidapi.IOUtils; 

Procedure SendEmail(Const eAddress, eObject, eText, eAttach : String); 
var
 Intent : JIntent; 
D, S : JString; 
Uri : TJnet_Uri;
 Begin
 Intent := TJIntent.Create;
 Intent.setAction(TJIntent.JavaClass.ACTION_Send);
 Intent.setFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK); 
Intent.putExtra(TJIntent.JavaClass.EXTRA_EMAIL, StringToJString(eAddress)); Intent.putExtra(TJIntent.JavaClass.EXTRA_SUBJECT, StringToJString(eObject)); intent.putExtra(TJIntent.JavaClass.EXTRA_TEXT, StringToJString(eText)); Uri:=TJnet_Uri.JavaClass.parse(StringToJString(FileName));
 Intent.putExtra(TJIntent.JavaClass.EXTRA_STREAM, Uri); Intent.setType(StringToJString('vnd.android.cursor.dir/email'));
 SharedActivity.startActivity(Intent); 
End;


Obtener el estado de la batería

Tomado de http://neftali.clubdelphi.com/?p=3157
Post en el que explica  cómo hacer una app utilizando Intents para obtener el estado de la batería del móvil.

unit Unit1;
interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Edit,
  FMX.StdCtrls, FMX.Layouts, FMX.Memo, FMX.Objects, FMX.Effects;

type

  TForm1 = class(TForm)
    Edit1: TEdit;
    Memo1: TMemo;
    Label1: TLabel;
    ShadowEffect1: TShadowEffect;
    Label2: TLabel;
    Image1: TImage;
    Image2: TImage;
    Label3: TLabel;
    BlurEffect1: TBlurEffect;
    Panel1: TPanel;
    Button2: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
const
  BateryHealthStr: array [1..7] of string =
    ('unknown', 'Good', 'Overhead', 'Dead', 'Over voltage', 'unspecified failure', 'Cold');
  BateryPluggedStr: array [1..4] of string =
    ('AC plugged', 'USB plugged', 'unknown',  'Wireless plugged');
  BateryStatusStr: array [1..5] of string =
    ('Unknown', 'Charging', 'Discharging', 'Not charging', 'Full');

const
  BATTERY_HEALTH_COLD = 7;
  BATTERY_HEALTH_DEAD = 4;
  BATTERY_HEALTH_GOOD = 2;
  BATTERY_HEALTH_OVERHEAT = 3;
  BATTERY_HEALTH_OVER_VOLTAGE = 5;
  BATTERY_HEALTH_UNKNOWN = 1;
  BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;

implementation

{$R *.fmx}

uses
  AndroidAPI.JNI.GraphicsContentViewText,
  AndroidAPI.JNI.JavaTypes,
  AndroidAPI.JNI.OS,
  FMX.Platform.Android,
  Androidapi.JNIBridge, Androidapi.Jni,  androidapi.JNI.Net,
  FMX.Helpers.Android;


procedure TForm1.Button1Click(Sender: TObject);
var
  filter: JIntentFilter;
  intentBatt: JIntent;
  iLevel, iScale: Integer;
  i:Integer;
  Str:JString;
  b:boolean;
  myContext: JContext;
begin
  // Contexto
  myContext := SharedActivityContext;

  // Creamos y Configuramos el Intent
  filter := TJIntentFilter.Create;
  // Asociamos la ACTION que queremos capturar
  filter.addAction(TJIntent.JavaClass.ACTION_BATTERY_CHANGED);
  // lo registramos
  intentBatt := myContext.registerReceiver(nil, filter);


  Memo1.Lines.Clear;

  // health
  i := intentBatt.getIntExtra(StringToJString('health'), -1);
  Memo1.Lines.Add('Salut: ' + BateryHealthStr[i]);
  // Icon
  //  i := battery.getIntExtra(StringToJString('icon-smal'), -1);
  //  Memo1.Lines.Add('icon-smal: ' + IntToStr(i));
  // Nivel de batería
  iLevel := intentBatt.getIntExtra(StringToJString('level'), -1);
  Memo1.Lines.Add('Level: ' + IntToStr(iLevel));
  // Plugged
  i := intentBatt.getIntExtra(StringToJString('plugged'), -1);
  Memo1.Lines.Add('Enchufado: ' + BateryPluggedStr[i]);
  // battery present
  b := intentBatt.getBooleanExtra(StringToJString('present'), False);
  Memo1.Lines.Add('Presente: ' + BoolToStr(b, True));
  // Escala para medir el nivel
  iScale := intentBatt.getIntExtra(StringToJString('scale'), -1);
  Memo1.Lines.Add('Escala: ' + IntToStr(iScale));
  // status de la batería
  i := intentBatt.getIntExtra(StringToJString('status'), -1);
  Memo1.Lines.Add('Estado: ' + BateryStatusStr[i]);
  // tecnología de la batería
  Str := intentBatt.getStringExtra(StringToJString('technology'));
  Memo1.Lines.Add('Tecnología: ' + JStringToString(Str));
  // Temperatura (en décimas de grado)
  i := intentBatt.getIntExtra(StringToJString('temperature'), -1);
  Memo1.Lines.Add('Temperatura: ' + FloatToStr(i / 10) + '°');
  // Voltage (en MILIVOLTIOS)
  i := intentBatt.getIntExtra(StringToJString('voltage'), -1);
  Memo1.Lines.Add('Voltaje: ' + FloatToStr(i/1000) + ' v.');

  // Mostramos la escala en el form
  i := (100 * iLevel) div iScale;
  Edit1.Text := IntToStr(i) + '%';
  // Modificar la imagen  (0..1)
  Image2.Scale.X := (i / 100);


end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Button1Click(nil);
end;


procedure TForm1.Button4Click(Sender: TObject);
var
  Intent: JIntent;
begin
  // Navegar
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
  Intent.setData(StrToJURI('http://neftali.clubdelphi.com'));
  SharedActivity.startActivity(Intent);

end;

end.


Obtener la versión de la aplicación
  uses
    Androidapi.JNI.JavaTypes,
    FMX.Helpers.Android,
    Androidapi.JNI.GraphicsContentViewText;


{$R *.fmx}

procedure TForm25.Button1Click(Sender: TObject);
var
  PackageManager: JPackageManager;
  PackageInfo : JPackageInfo;
begin
  PackageManager := SharedActivity.getPackageManager;
  PackageInfo := PackageManager.getPackageInfo(SharedActivityContext.getPackageName(), TJPackageManager.JavaClass.GET_ACTIVITIES);
  Edit1.Text:= JStringToString(PackageInfo.versionName);
end;


Comprobar que una app tiene un permiso determinado para enviar un SMS

uses
  System.UITypes,
  FMX.Dialogs,
  FMX.Helpers.Android,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNI.Telephony;

function HasPermission(const Permission: string): Boolean;
begin
  //Permissions listed at http://d.android.com/reference/android/Manifest.permission.html
  Result := SharedActivity.checkCallingOrSelfPermission(
    StringToJString(Permission)) =
    TJPackageManager.JavaClass.PERMISSION_GRANTED
end;

procedure SendSMS(const Number, Msg: string);
var
  SmsManager: JSmsManager;
begin
  if not HasPermission('android.permission.SEND_SMS') then
    MessageDlg('App does not have the SEND_SMS permission',
      TMsgDlgType.mtError, [TMsgDlgBtn.mbCancel], 0)
  else
  begin
    SmsManager := TJSmsManager.JavaClass.getDefault;
    SmsManager.sendTextMessage(
      StringToJString(Number),
      nil,
      StringToJString(Msg),
      nil,
      nil);
  end;
end;