I need get telephone number of device on which my application runing. If has device two SIM cards ideal to get both numbers or if SIM card is not inserted (tablet device) can detect this.
I found some JAVA code but I have no idea how translate it to Delphi
TelephonyManager phneMgr = (TelephonyManager)mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
String phneNmbr = phneMgr.getLine1Number();
I try write something but it not working ....
USES Androidapi.Helpers, Androidapi.JNI.JavaTypes, Androidapi.JNI.Telephony;
procedure TForm1.Button1Click(Sender: TObject);
var
num: JString;
tman: Androidapi.JNI.Telephony.JTelephonyManager;
begin
tman:=TJtelephonyManager.Create;
num := tman.getLine1Number;
edit1.Text:=Jstringtostring(num);
end;
Something like this should do it, based on experience with other system services. This translates what you have suggested is viable Java code.
I'll edit this to make it compile correctly (if there are any issues with it) when I have a copy of Delphi to hand later, but this is roughly what is required.
Note that quick look at the telephony manager documentation doesn't readily say how one would get the phone number for a second SIM, but it does translate what you were trying to translate.
uses
System.SysUtils,
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.Telephony;
function DeviceTelephoneNumber: string;
var
TelephonyManagerObj: JObject;
TelephonyManager: JTelephonyManager;
begin
TelephonyManagerObj:= TAndroidHelper.Context.getSystemService(
TJContext.JavaClass.TELEPHONY_SERVICE);
if TelephonyManagerObj <> nil then
begin
TelephonyManager := TJTelephonyManager.Wrap(TelephonyManagerObj);
if TelephonyManager <> nil then
Result := JStringToString(TelephonyManager.getLine1Number);
end;
end;
This code is also a possibility, which works in Android 5.1 and later.
function DeviceTelephoneNumbers: TArray<string>;
var
SubscriptionManager: JSubscriptionManager;
I, SubscriptionInfoCount: Integer;
SubscriptionInfoList: JList;
SubscriptionInfo: JSubscriptionInfo;
begin
// Subscription manager is only available in Android 5.1 and later
if TOSVersion.Check(5, 1) then
begin
SubscriptionManager := TJSubscriptionManager.JavaClass.from(
TAndroidHelper.Context);
SubscriptionInfoCount := SubscriptionManager.getActiveSubscriptionInfoCount;
SubscriptionInfoList := SubscriptionManager.getActiveSubscriptionInfoList;
SetLength(Result, SubscriptionInfoCount);
for I := 0 to Pred(SubscriptionInfoCount) do
begin
SubscriptionInfo := TJSubscriptionInfo.Wrap(SubscriptionInfoList.get(I));
if SubscriptionInfo <> nil then
Result[I] := JStringToString(SubscriptionInfo.getNumber);
end;
end
else
begin
// If running on older OS, use older API
SetLength(Result, SubscriptionInfoCount);
Result[0] := DeviceTelephoneNumber
end;
end;
Related
How I can open Short Message Service (SMS) window on Android phode with pretyped message text and recipient number.
In manuals i found only Phone dialer
PhoneDialerService.Call(edtTelephoneNumber.Text)
which allow make call, but nothing about sending SMS messages.
See the class SMSManager on Android API.
There is a sendTextMessage method that you can use:
Try some code like this:
uses
Androidapi.Helpers,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.Telephony;
procedure TForm1.Button1Click(Sender: TObject);
var
destAdress: JString;
smsManager: JSmsManager;
begin
smsManager := TJSmsManager.JavaClass.getDefault;
destAdress := StringToJString('0034123456789');
smsManager.sendTextMessage(destAdress, nil, StringToJString('The message content'), nil, nil);
end;
You must add permissions to the project configuration. See the "Send SMS":
Send SMS - Allows an application to send SMS messages.
Regards.
The question asks about launching the SMS window, which I've taken to mean launching the built-in SMS-sending app. It wants a target number and message content sent in.
This can be done by asking Android to start an activity using an intent set up to view a carefully crafted SMS-specific URI and containing the required message as an extra field.
The primary benefit to invoking the SMS app rather than sending the SMS within your own app is that it does not require additional permissions - the SMS app already has those permissions.
I show how to do this in my old activity launching article (which was written for Delphi XE6 but is still applicable to all later versions, with a few minor code updates here and there), but for completeness here is a helper unit that does the job:
unit SMSHelperU;
interface
procedure CreateSMS(const Number, Msg: string);
implementation
uses
Androidapi.Helpers,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.App,
Androidapi.JNI.Net,
Androidapi.JNI.GraphicsContentViewText,
System.SysUtils;
function LaunchActivity(const Intent: JIntent): Boolean; overload;
var
ResolveInfo: JResolveInfo;
begin
{$IF RTLVersion >= 30}
ResolveInfo := TAndroidHelper.Activity.getPackageManager.resolveActivity(Intent, 0);
{$ELSE}
ResolveInfo := SharedActivity.getPackageManager.resolveActivity(Intent, 0);
{$ENDIF}
Result := ResolveInfo <> nil;
if Result then
{$IF RTLVersion >= 30}
TAndroidHelper.Activity.startActivity(Intent);
{$ELSE}
SharedActivity.startActivity(Intent);
{$ENDIF}
end;
procedure CreateSMS(const Number, Msg: string);
var
Intent: JIntent;
URI: Jnet_Uri;
begin
URI := StrToJURI(Format('smsto:%s', [Number]));
Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW, URI);
Intent.putExtra(StringToJString('sms_body'), StringToJString(Msg));
LaunchActivity(Intent);
end;
end.
The routine can be called like this:
CreateSMS('123456789', 'O HAI2U!');
If you did want to actually send the SMS the unit below does that job but also includes code that self-checks the relevant permission is set for the app:
unit AndroidStuff;
interface
function HasPermission(const Permission: string): Boolean;
procedure SendSMS(const Number, Msg: string);
implementation
uses
System.SysUtils,
System.UITypes,
{$IF RTLVersion >= 31}
FMX.DialogService,
{$ELSE}
FMX.Dialogs,
{$ENDIF}
FMX.Helpers.Android,
Androidapi.Helpers,
Androidapi.JNI.App,
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
{$IF RTLVersion >= 30}
Result := TAndroidHelper.Context.checkCallingOrSelfPermission(
{$ELSE}
Result := SharedActivityContext.checkCallingOrSelfPermission(
{$ENDIF}
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
{$IF RTLVersion >= 31}
TDialogService.MessageDialog('App does not have the SEND_SMS permission', TMsgDlgType.mtError, [TMsgDlgBtn.mbCancel], TMsgDlgBtn.mbCancel, 0, nil)
{$ELSE}
MessageDlg('App does not have the SEND_SMS permission', TMsgDlgType.mtError, [TMsgDlgBtn.mbCancel], 0)
{$ENDIF}
else
begin
SmsManager := TJSmsManager.JavaClass.getDefault;
SmsManager.sendTextMessage(
StringToJString(Number),
nil,
StringToJString(Msg),
nil,
nil);
end;
end;
end.
I'm using Delphi 10.1 Berlin for developing android mobile application. And in that I need to check if the location sensor is not switched ON, then I need to redirect to the Location sensor Settings in android mobile. How can I able to implement using Delphi? I have seen example using JAVA but not found for Delphi. And Thanks in Advance.
You could try some code like the following. Here is a helper unit:
unit LocationU;
interface
function IsGPSProviderEnabled: Boolean;
function IsNetworkProviderEnabled: Boolean;
procedure LaunchLocationSettings;
implementation
uses
System.SysUtils,
Androidapi.Helpers,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.Location,
Androidapi.JNI.Provider;
function IsProviderEnabled(const Provider: JString): Boolean;
var
LocationManagerObj: JObject;
LocationManager: JLocationManager;
begin
LocationManagerObj := TAndroidHelper.Context.getSystemService(
TJContext.JavaClass.LOCATION_SERVICE);
LocationManager := TJLocationManager.Wrap(LocationManagerObj);
Result := LocationManager.isProviderEnabled(Provider);
end;
function IsGPSProviderEnabled: Boolean;
begin
Result := IsProviderEnabled(TJLocationManager.JavaClass.GPS_PROVIDER);
end;
function IsNetworkProviderEnabled: Boolean;
begin
Result := IsProviderEnabled(TJLocationManager.JavaClass.NETWORK_PROVIDER);
end;
procedure LaunchLocationSettings;
begin
TAndroidHelper.Activity.startActivity(
TJIntent.JavaClass.init(TJSettings.JavaClass.ACTION_LOCATION_SOURCE_SETTINGS));
end;
end.
and here is some code that calls it:
uses
FMX.Helpers.Android,
Androidapi.Helpers,
Androidapi.JNI.Widget,
LocationU;
procedure TMainForm.FormCreate(Sender: TObject);
begin
if not IsGPSProviderEnabled and not IsNetworkProviderEnabled then
begin
CallInUiThread(
procedure
begin
TJToast.JavaClass.makeText(
TAndroidHelper.Context,
StrToJCharSequence('Location services not enabled - launching settings'),
TJToast.JavaClass.LENGTH_SHORT).show
end);
LaunchLocationSettings;
end;
end;
I am porting an older project (app for iOS ans Android) for a customer from an older AppMethod version to the newest RAD Studio version (10.0 Berlin). MessageDlg and similar were used often in the project but this does not work anymore. The apps shows a message, that modal dialogs are not supported on Android. I know and understand why this is so for the Android platform (so please don't mark this question as a dublicate by referencing to an explanation - I'm asking for something else!).
Firemonkey allows to set an anonymous function to be executed asynchronously after the user taps on a button in the dialog box or when it is closed. However, there is often code which depends on users decision or code which must be executed after the dialog box, regardless of which button the user taps on. For example, a dialog box must ask the user for his decision in the middle of an ongoing operation. Further operations then depend on the users decision (which might also include to stop further code execution in the current application!). Since RAD Studio does not support blocking dialogs on Android, I seem to be forced to break up my code - from one function to multiple functions (worse readability...). This gets even more complicated when there are nested function calls with possible modal dialog boxes, which require user interaction.
Is there still a way to emulate blocking dialogs somehow? It doesn't has to be perfect. I just don't want to rewrite a lot of code and outsource even small code fragments into many separate functions, everwhere where user interaction is required.
OK, I think the following "dirty" solution might be sufficient for me:
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.DialogService,
FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
blockDlg: array[0..99] of Boolean;
blockDlgIdx: Integer = 0;
implementation
{$R *.fmx}
procedure NShowMessageAsync(AMessage: String);
begin
TDialogService.ShowMessage(AMessage);
end;
procedure NShowMessageSync(AMessage: String);
var
locBlockIdx: Integer;
begin
if blockDlgIdx = Length(blockDlg)-1 then blockDlgIdx := 0 else Inc(blockDlgIdx);
locBlockIdx := blockDlgIdx;
blockDlg[locBlockIdx] := true;
TDialogService.ShowMessage(AMessage,
procedure(const AResult: TModalResult)
begin
blockDlg[locBlockIdx] := false;
end);
while blockDlg[locBlockIdx] do begin
Sleep(40);
Application.ProcessMessages();
end;
end;
procedure NMessageDialogAsync(const AMessage: string; const ADialogType: TMsgDlgType;
const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn;
const AHelpCtx: LongInt);
begin
TDialogService.MessageDialog(AMessage, ADialogType, AButtons, ADefaultButton,
AHelpCtx, procedure(const AResult: TModalResult) begin end);
end;
function NMessageDialogSync(const AMessage: string; const ADialogType: TMsgDlgType;
const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn;
const AHelpCtx: LongInt): TModalResult;
var
locBlockIdx: Integer;
LModalResult: TModalResult;
begin
Result := -1;
if blockDlgIdx = Length(blockDlg)-1 then blockDlgIdx := 0 else Inc(blockDlgIdx);
locBlockIdx := blockDlgIdx;
blockDlg[locBlockIdx] := true;
TDialogService.MessageDialog(AMessage, ADialogType, AButtons, ADefaultButton, AHelpCtx,
procedure(const AResult: TModalResult)
begin
LModalResult := AResult;
blockDlg[locBlockIdx] := false;
end);
while blockDlg[locBlockIdx] do begin
Sleep(40);
Application.ProcessMessages();
end;
Result := LModalResult;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
mr: TModalResult;
begin
mr := NMessageDialogSync('1',
System.UITypes.TMsgDlgType.mtInformation,
[System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo, System.UITypes.TMsgDlgBtn.mbCancel],
System.UITypes.TMsgDlgBtn.mbYes,
0);
NShowMessageSync(IntToStr(mr));
mr := NMessageDialogSync('2',
System.UITypes.TMsgDlgType.mtWarning,
[System.UITypes.TMsgDlgBtn.mbYesToAll, System.UITypes.TMsgDlgBtn.mbAbort],
System.UITypes.TMsgDlgBtn.mbAbort,
0);
NShowMessageSync(IntToStr(mr));
mr := NMessageDialogSync('3',
System.UITypes.TMsgDlgType.mtInformation,
[System.UITypes.TMsgDlgBtn.mbIgnore, System.UITypes.TMsgDlgBtn.mbAll, System.UITypes.TMsgDlgBtn.mbHelp, System.UITypes.TMsgDlgBtn.mbClose],
System.UITypes.TMsgDlgBtn.mbClose,
0);
NShowMessageSync(IntToStr(mr));
Form1.Fill.Kind := TBrushKind.Solid;
if Form1.Fill.Color = TAlphaColors.Red then
Form1.Fill.Color := TAlphaColors.Blue
else
Form1.Fill.Color := TAlphaColors.Red;
end;
end.
Not very clean, but at least I can use this for a while.
I need to get the list of packages of my Android device using Embarcadero Delphi XE10 Seattle
procedure TDeviceInfoForm.Button1Click(Sender: TObject);
var stdout:JOutputStream;
stdin:JInputStream;
suProcess:JProcess;
begin
suProcess:=TJRuntime.JavaClass.getRuntime.exec(StringToJString('pm list packages'));
stdout:=suProcess.getoutputStream;
stdin:=suProcess.getInputStream;
end;
You are going about this the wrong way. You should not be using ADB at all. Use Android's PackageManager class instead. Its getInstalledPackages() method returns a List of PackageInfo objects, one for each package. Simply loop through that list, eg:
uses
...,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.GraphicsContentViewText,
Androidapi.Helpers;
procedure TDeviceInfoForm.Button1Click(Sender: TObject);
var
list: JList;
iter: JIterator;
pkg: JPackageInfo;
begin
// read the getInstalledPackages() documentation for details about the available flags...
list := TAndroidHelper.Context.getPackageManager.getInstalledPackages(0);
iter := list.iterator;
while iter.hasNext do
begin
pkg := TJPackageInfo.Wrap((iter.next as ILocalObject).GetObjectID);
// use pkg as needed...
end;
end;
I am building an application for Android using Delphi XE5 that makes use of the Zxing barcode application and it uses the clipboard to retrieve the result. All of the code (Most of it anyway) is from a tutorial that I have found on the web. When I followed the tutorial, it worked to a charm but when applying the SAME code within an application that I was already working on - it did not work. Whenever accessing the clipboard ( in the 'OnTimer' event), the application always hangs and stops working. No error, nothing. App freezes and I have to close it via the phone's task manager.
The application fails right after the following line
Log.Add('AndroidClipboardScanner:1'); Log.SaveToFile(INIFileLog);
I have changed the coding around so that the app assumed the Clipboard service was available in the Ontimer event and it proceeded but it then failed after the following line:
Log.Add('AndroidClipboardScanner:4'); Log.SaveToFile(INIFileLog);
I am not sure where to begin debugging because the same code works in the other application that I created following the initial guide I found. I can also confirm that the ClipService is being assigned properly, otherwise the intent wouldn't even begin. Any help or guidance would be much appreciated ! Below is my code...
This Declared in the 'Private' variables section of the form:
ClipService: IFMXClipboardService;
This within the 'OnTimer' event for Timer1:
procedure TMain_Form.Timer1Timer(Sender: TObject);
var
barCode : String;
begin
timer1.Enabled := false;
Log.Add('AndroidClipboardScanner:0.1'); Log.SaveToFile(INIFileLog);
Try
if assigned(ClipService) then begin
Log.Add('AndroidClipboardScanner:1'); Log.SaveToFile(INIFileLog);
if (ClipService.GetClipboard.ToString <> 'nil') then
begin
Log.Add('AndroidClipboardScanner:2'); Log.SaveToFile(INIFileLog);
timer1.Enabled := false;
Log.Add('AndroidClipboardScanner:3'); Log.SaveToFile(INIFileLog);
Elapsed := 0;
Log.Add('AndroidClipboardScanner:4'); Log.SaveToFile(INIFileLog);
editHold.PasteFromClipboard;
//EditHold.Text := ClipService.GetClipboard.ToString;
Log.Add('AndroidClipboardScanner:5'); Log.SaveToFile(INIFileLog);
end else
begin
Log.Add('AndroidClipboardScanner:6'); Log.SaveToFile(INIFileLog);
Timer1.Enabled := False;
Log.Add('AndroidClipboardScanner:7'); Log.SaveToFile(INIFileLog);
end;
Log.Add('AndroidClipboardScanner:8'); Log.SaveToFile(INIFileLog);
end else begin
ShowMessage('Unexpected error has occured');
end;
Except
ShowMessage('Unexpected error has occured..');
End;
end;
Within the ONCreate procedure of the form:
if not TPlatformServices.Current.SupportsPlatformService(IFMXClipboardService,
IInterface(ClipService)) then begin
ShowMessage('Clipboard Failed:1');
ClipService := nil;
end;
Elapsed := 0;
This is for click event for the button that begins the intent:
procedure TMain_Form.Button_ShowScannerClick(Sender: TObject);
{$IFDEF ANDROID}
var
intent: JIntent; {$ENDIF}
begin
{$IFDEF ANDROID}
//ShowMessage('Scanner:1');
if assigned(ClipService) then begin
//ShowMessage('Scanner:2');
ClipService.SetClipboard('nil');
intent := tjintent.Create;
intent.setAction(stringtojstring('com.google.zxing.client.android.SCAN'));
intent.putExtra(tjintent.JavaClass.EXTRA_INTENT,
stringtojstring('"SCAN_MODE"'));
sharedactivity.startActivityForResult(intent,0);
Elapsed := 0;
timer1.Enabled := true;
//ShowMessage('Scanner:3');
end;
{$ENDIF}
You didn't set the SCAN_MODE parameters like:
intent.putExtra(tjintent.JavaClass.EXTRA_TEXT,
stringtojstring('"SCAN_MODE","ONE_D_MODE,QR_CODE_MODE,PRODUCT_MODE,DATA_MATRIX_MODE"'));
Also you can check timer interval parameter...
I tested the solution on few devices.
With low interval value I had black screen sometimes