4

我正在构建一个基于 PhoneGAP 的应用程序,我需要在其中拨打电话,然后在 5 秒后返回我的应用程序。

关于拨打电话的部分工作正常。为了让 Android 通过呼叫而不只是拨号盘打开,拨打电话的代码放在 com.phonegap.api.Plugin 中,看起来像

private void callNumber(String phoneNumber){
    Uri calling = Uri.parse("tel:" + phoneNumber);
    Intent callIntent = new Intent(Intent.ACTION_CALL, calling);
    this.ctx.startActivity(callIntent);
}

要重新启动应用程序,我AsyncTask在调用 RestartTask 之前启动了一个。因为这段代码存在于插件中,所以我必须使用Activity.runOnUiThread来启动 RestartTask,但除此之外没有什么特别的。

在 RestartTask 中,只doInBackground实现了方法,它所做的只是休眠 5 秒,然后运行以下意图:

Intent restartIntent = new Intent(DialerPlugin.this.ctx.getBaseContext(), MainActivity.class);
restartIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
DialerPlugin.this.ctx.startActivity(restartIntent);

MainActivity是从 PhoneGAP 派生的主类,它扩展了DroidGap.

设置 FLAG_ACTIVITY_CLEAR_TOP 和 FLAG_ACTIVITY_SINGLE_TOP 正是人们所说的这里这里应该设置,如果要“重新激活”活动,这意味着使用当前实例化活动的任务而不是创建新任务,并且活动与它的运行状态一起重用,而不是创建一个新的活动实例。onNewIntent当操作系统传递意图时,会调用“旧”活动。

但是,当电话呼叫处于活动状态并且似乎意图未传递给 时,没有任何反应MainActivity,直到我挂断其中一部电话。奇怪的。

如果我将标志更改为 include FLAG_ACTIVITY_CLEAR_TOP,则会重新启动应用程序任务或主要活动。但是由于这是PhoneGAP,两者都对应于重新启动应用程序,这不是我想要的。我还可以让 Android 在另一个任务中启动我的应用程序的一个全新实例,该任务被赋予焦点。

但是,我不能让 Android 将焦点重新放在我的主要活动上。我究竟做错了什么?

谢谢!

4

1 回答 1

3

经过数小时的黑客攻击,我设法解决了这个问题。似乎,一旦一个新的 android 任务获得控制权,这就是使用内置拨号器拨打电话时发生的情况,从拨打电话的任务开始的后台任务也失去了启动新活动的特权,除非它正在启动新任务中的活动。

这意味着,AsyncTask 在进行调用之前从 Activity 启动,然后稍微休眠以确保拨号器任务/Activity 处于打开状态,它必须启动一个新任务才能重新获得焦点。再次启动 Cordova 活动不是一个选项,因为这将有效地重新启动整个应用程序,因此解决方案是进行精简重启任务,该任务立即完成。

在 Cordova 插件中,可以放置以下内部类:

protected class RestartTask extends AsyncTask<Void, Void, Void>{
    protected RestartTask() { }

    @Override
    protected Void doInBackground(Void... unused){
        try {
            // pass time so the built-in dialer app can make the call
            Thread.sleep(MyPlugin.restartDelay);
        }
        catch (InterruptedException localInterruptedException)
        {
            Log.d("MyPlugin", "RestartTask received an InterruptedException");
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void justEyeCandy){
        super.onPostExecute(justEyeCandy);

        // Start the RestartActivity in a new task. This will snap the phone out of the built-in dialer app, which
        // has started in it's own task at this point in time. The RestartActivity gains control and finishes
        // immediately, leading control back to the activity at the top of the stack in the
        // app (where the user came from when making the call).
        Intent restartIntent = new Intent(MyPlugin.this.ctx.getApplicationContext(), RestartActivity.class);
        restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        MyPlugin.this.ctx.getApplicationContext().startActivity(restartIntent);
    }
}

AsyncTask可以通过调用在插件中触发:

this.ctx.runOnUiThread(new Runnable(){
    public void run(){
        try {
            RestartTask restartTask = new RestartTask();
            restartTask.execute();
        }
        catch (Exception e) {
            Log.d("MyPlugin", "Exploded when trying to start background task: " + e.getMessage());
        }
    }
});

AsyncTask 在新任务中启动的类是:

public class RestartActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // the prototype RestartActivity there is a possibility that this will be the root activity of the app.
        // If that is the case, this activity will boot the main activity of the app in a new task, before signing off.
        // However, this is not the case for this app, as restarts are only used once a call diversion has taken place,
        // form within the app.
        if (isTaskRoot())
        {
            // Start the app before finishing
            String packageName = this.getBaseContext().getPackageName();
            Intent startAppIntent = this.getBaseContext().getPackageManager().getLaunchIntentForPackage(packageName);
            startAppIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
            startActivity(startAppIntent);
        }

        // Now finish, which will drop the user in to the activity that was at the top of the task stack
        finish();
    }
}
于 2012-05-07T13:04:41.130 回答