blob: 1014d824a04d555354d96552b65e3b0f275d9440 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.incallui.multisim;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.preferredsim.suggestion.SimSuggestionComponent;
import com.android.dialer.util.PermissionsUtil;
import com.android.incallui.call.CallList;
import com.android.incallui.call.DialerCall;
import com.android.incallui.call.DialerCallListener;
import com.android.incallui.incalluilock.InCallUiLock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Hangs up the current call and redial the call using the {@code otherAccount} instead. the in call
* ui will be prevented from closing until the process has finished.
*/
public class SwapSimWorker implements Worker<Void, Void>, DialerCallListener, CallList.Listener {
// Timeout waiting for the call to hangup or redial.
private static final int DEFAULT_TIMEOUT_MILLIS = 5_000;
private final Context context;
private final DialerCall call;
private final CallList callList;
private final InCallUiLock inCallUiLock;
private final CountDownLatch disconnectLatch = new CountDownLatch(1);
private final CountDownLatch dialingLatch = new CountDownLatch(1);
private final PhoneAccountHandle otherAccount;
private final String number;
private final int timeoutMillis;
private CountDownLatch latchForTest;
@MainThread
public SwapSimWorker(
Context context,
DialerCall call,
CallList callList,
PhoneAccountHandle otherAccount,
InCallUiLock lock) {
this(context, call, callList, otherAccount, lock, DEFAULT_TIMEOUT_MILLIS);
}
@VisibleForTesting
SwapSimWorker(
Context context,
DialerCall call,
CallList callList,
PhoneAccountHandle otherAccount,
InCallUiLock lock,
int timeoutMillis) {
Assert.isMainThread();
this.context = context;
this.call = call;
this.callList = callList;
this.otherAccount = otherAccount;
inCallUiLock = lock;
this.timeoutMillis = timeoutMillis;
number = call.getNumber();
call.addListener(this);
call.disconnect();
}
@WorkerThread
@Nullable
@Override
@SuppressWarnings("MissingPermission")
public Void doInBackground(Void unused) {
try {
SimSuggestionComponent.get(context)
.getSuggestionProvider()
.reportIncorrectSuggestion(context, number, otherAccount);
if (!PermissionsUtil.hasPhonePermissions(context)) {
LogUtil.e("SwapSimWorker.doInBackground", "missing phone permission");
return null;
}
if (!disconnectLatch.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
LogUtil.e("SwapSimWorker.doInBackground", "timeout waiting for call to disconnect");
return null;
}
LogUtil.i("SwapSimWorker.doInBackground", "call disconnected, redialing");
TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, otherAccount);
callList.addListener(this);
telecomManager.placeCall(Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null), extras);
if (latchForTest != null) {
latchForTest.countDown();
}
if (!dialingLatch.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
LogUtil.e("SwapSimWorker.doInBackground", "timeout waiting for call to dial");
}
return null;
} catch (InterruptedException e) {
LogUtil.e("SwapSimWorker.doInBackground", "interrupted", e);
Thread.currentThread().interrupt();
return null;
} finally {
ThreadUtil.postOnUiThread(
() -> {
call.removeListener(this);
callList.removeListener(this);
inCallUiLock.release();
});
}
}
@MainThread
@Override
public void onDialerCallDisconnect() {
disconnectLatch.countDown();
}
@Override
public void onCallListChange(CallList callList) {
if (callList.getOutgoingCall() != null) {
dialingLatch.countDown();
}
}
@VisibleForTesting
void setLatchForTest(CountDownLatch latch) {
latchForTest = latch;
}
@Override
public void onDialerCallUpdate() {}
@Override
public void onDialerCallChildNumberChange() {}
@Override
public void onDialerCallLastForwardedNumberChange() {}
@Override
public void onDialerCallUpgradeToVideo() {}
@Override
public void onDialerCallSessionModificationStateChange() {}
@Override
public void onWiFiToLteHandover() {}
@Override
public void onHandoverToWifiFailure() {}
@Override
public void onInternationalCallOnWifi() {}
@Override
public void onEnrichedCallSessionUpdate() {}
@Override
public void onIncomingCall(DialerCall call) {}
@Override
public void onUpgradeToVideo(DialerCall call) {}
@Override
public void onSessionModificationStateChange(DialerCall call) {}
@Override
public void onDisconnect(DialerCall call) {}
@Override
public void onWiFiToLteHandover(DialerCall call) {}
@Override
public void onHandoverToWifiFailed(DialerCall call) {}
@Override
public void onInternationalCallOnWifi(@NonNull DialerCall call) {}
}