【问题标题】:Delphi Android READ_PHONE_STATE not triggeringDelphi Android READ_PHONE_STATE 未触发
【发布时间】:2020-04-14 19:35:54
【问题描述】:

我设法获得了 READ_PHONE_STATE 的运行时权限,但应用程序根本不会对手机状态更改做出反应。我还在清单文件中启用了 READ_PHONE_STATE。

已尝试使用 3 部 Android 手机,但都无法跟踪状态变化。

在 iOS 中,我设法让 READ_PHONE_STATE 使用与我在 Android 上尝试过的代码相同的代码,但在 iOS 中,Apple 已弃用显示来电者电话号码。

    uses
      System.Permissions;

    {$R *.fmx}


    constructor TForm1.Create(AOwner: TComponent);
    const
      PermissionAccessReadPhoneState = 'android.permission.READ_PHONE_STATE';
      PermissionAccessMakeCall = 'android.permission.CALL_PHONE';
    begin
      inherited Create(AOwner);

      TPlatformServices.Current.SupportsPlatformService(IFMXPhoneDialerService, IInterface(PhoneDialerService));

      PermissionsService.RequestPermissions([PermissionAccessMakeCall, PermissionAccessReadPhoneState],
        procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TpermissionStatus>)
        begin
          if (Length(AgrantResults) = 2) and (AgrantResults[0] = TPermissionStatus.Granted) and (AgrantResults[1] = TPermissionStatus.Granted) then
            begin
              ShowMessage('READ_PHONE_STATE + CALL_PHONE Activated!');
            end;
        end);

if Assigned(PhoneDialerService) then
    begin
      PhoneDialerService.OnCallStateChanged := MyOnCallStateChanged;
    end;
end;

    procedure TForm1.MyOnCallStateChanged(const ACallID: String;
      const ACallState: TCallState);
    var
      outText: String;
    begin
      case ACallState of
        TCallState.None:          outText := 'No calls';
        TCallState.Connected:     outText := 'Connected';
        TCallState.Incoming:      outText := 'Incoming Call';
        TCallState.Dialing:       outText := 'Dialing';
        TCallState.Disconnected:  outText := 'Disconnected';
      end;

      lblCallState.Text := outText;

    end;

【问题讨论】:

  • 请提供minimal reproducible example。如果不确切知道自己在做什么,就很难知道问题出在哪里
  • 添加代码到帖子
  • 为什么要调用PlatformServices.Current.SupportsPlatformService() 两次来分配相同的PhoneDialerService 变量?你应该摆脱其中一项任务。我会建议第一个,并将第二个移到您的匿名程序中。除非您首先被授予权限,否则不应分配 OnCallStateChanged 处理程序。
  • 感谢您的回复。第二个 PhoneDialerService 是错误的。在 if 语句之前的匿名过程中添加了 PhoneDialer 服务。授予权限后移动 OnCallStateChanged。还在 TForm.Create 之前移动了 MyOnCallStatement 过程。但仍然无法获得手机状态的变化。可以拨打电话并获取运营商信息。
  • 如果这不起作用,另一种方法是使用 Android API 代码实现 PhoneStateListener

标签: android delphi


【解决方案1】:

我遇到了同样的问题。加载应用程序表单后,我刚刚获得了第一个状态,但没有触发更多状态更改。 我通过在单独的线程中运行 PhoneStateListener/TelephonyManager 解决了这个问题。然后手机的状态变化就正常触发了。

【讨论】:

    【解决方案2】:
    uses
      Androidapi.JNI.Telephony;
    
    type
      TPhoneStateListener = class;
      TfrmTabbed = class(TForm)
        HeaderToolBar: TToolBar;
        ToolBarLabel: TLabel;
        TabControl1: TTabControl;
        ...
    
      private
        { Private declarations }
        PhoneStateListener: TPhoneStateListener;
        ...
    
      end;
    
      TPhoneStateListener = class(TJavaLocal, JICustomPhoneStateListener)
      private
        [weak]
        FParent : TfrmTabbed;
      public
        constructor Create(AParent : TfrmTabbed);
        procedure onCallForwardingIndicatorChanged(cfi: Boolean); cdecl;
        procedure onCallStateChanged(state: Integer; incomingNumber: JString); cdecl;
        procedure onCellInfoChanged(cellInfo: JList); cdecl;
        procedure onCellLocationChanged(location: JCellLocation); cdecl;
        procedure onDataActivity(direction: Integer); cdecl;
        procedure onDataConnectionStateChanged(state: Integer); overload; cdecl;
        procedure onDataConnectionStateChanged(state: Integer; networkType: Integer); overload; cdecl;
        procedure onMessageWaitingIndicatorChanged(mwi: Boolean); cdecl;
        procedure onServiceStateChanged(serviceState: JServiceState); cdecl;
        procedure onSignalStrengthChanged(asu: Integer); cdecl;
        procedure onSignalStrengthsChanged(signalStrength: JSignalStrength); cdecl;
      end;
    
    procedure TfrmTabbed.FormShow(Sender: TObject);
    var
      obj: JObject;
    begin
      if PhoneStateListener = nil then
          PhoneStateListener := TPhoneStateListener.Create(Self);
        obj := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.TELEPHONY_SERVICE);
        if obj = nil then
          raise Exception.Create('Telephony service not supported');
        CallinUIThread(procedure
        var
          TelephonyManager: JTelephonyManager;
          PSL: JCustomPhoneStateListener;
        begin
          TelephonyManager := TJTelephonyManager.Wrap(obj);
          PSL := TJCustomPhoneStateListener.JavaClass.init(PhoneStateListener);
          TelephonyManager.listen(PSL,
            TJPhoneStateListener.JavaClass.LISTEN_CALL_STATE
          );
        end
        );
    
    { TPhoneStateListener }
    
    constructor TPhoneStateListener.Create(AParent: TfrmTabbed);
    begin
      inherited Create;
      FParent := AParent;
    end;
    
    procedure TPhoneStateListener.onCallForwardingIndicatorChanged(cfi: Boolean);
    begin
    end;
    
    procedure TPhoneStateListener.onCallStateChanged(state: Integer;
      incomingNumber: JString);
    begin
      if state = TJTelephonyManager.JavaClass.CALL_STATE_IDLE then
      begin
      end
      else if state = TJTelephonyManager.JavaClass.CALL_STATE_OFFHOOK then
      begin
      end
      else if state = TJTelephonyManager.JavaClass.CALL_STATE_RINGING then
      begin
      end;
    end;
    
    procedure TPhoneStateListener.onCellInfoChanged(cellInfo: JList);
    begin
    end;
    
    procedure TPhoneStateListener.onCellLocationChanged(location: JCellLocation);
    begin
    end;
    
    procedure TPhoneStateListener.onDataActivity(direction: Integer);
    begin
    end;
    
    procedure TPhoneStateListener.onDataConnectionStateChanged(state: Integer);
    begin
    end;
    
    procedure TPhoneStateListener.onDataConnectionStateChanged(state: Integer; networkType: Integer);
    begin
    end;
    
    procedure TPhoneStateListener.onMessageWaitingIndicatorChanged(mwi: Boolean);
    begin
    end;
    
    procedure TPhoneStateListener.onServiceStateChanged(serviceState: JServiceState);
    begin
    end;
    
    procedure TPhoneStateListener.onSignalStrengthChanged(asu: Integer);
    begin
    end;
    
    procedure TPhoneStateListener.onSignalStrengthsChanged(signalStrength: JSignalStrength);
    begin
    end;
    

    【讨论】:

    • 我几乎成功了。当应用程序启动时,CALL_STATE_IDLE 会执行。但是,当我拨打电话或接听电话并结束此电话时,不会执行 CallStateChange。为代码添加了运行时权限。
    • 是的,我没有包含权限代码,因为我知道您已经知道该怎么做! (此外,此代码将在 10.3.2 及更早版本中运行,无需权限)。我知道,因为它来自一个工作应用程序。
    • 还有一个问题,app在拨打或接听电话时不执行CallStateChange。首先认为这是因为当 Android 自己的电话窗口打开时,应用程序会进入后台。向应用程序添加了调用按钮,但从应用程序调用时仍然不执行 CallStateChange。
    • Android 开发者也有同样的问题。根据这个cannot-detect-when-outgoing-call-is-answered-in-android,需要在manifest中添加READ_PRECISE_PHONE_STATE。我以前只使用 phonestatelistener 来改变自己的信号强度。
    • 您帮了大忙,再次感谢。我没想到完整的解决方案,很高兴知道这件事的人愿意帮助我。我添加到清单 READ_PRECISE_PHONE_STATE,现在设法让 CALL_STATE_OFFHOOK 执行。当我直接从应用程序拨打电话时,它执行了一次。需要多玩一点,了解这些不同的状态何时触发。
    猜你喜欢
    • 2014-09-19
    • 1970-01-01
    • 2016-01-27
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2016-11-22
    • 2017-07-01
    相关资源
    最近更新 更多