Signed-off-by: hmz007 <hmz007@gmail.com> Change-Id: Ib87fdbe7a0be7dc961af3500fe9ea4589a127f9f
372 lines
15 KiB
Java
372 lines
15 KiB
Java
/*
|
|
* Copyright (C) 2021 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.imsserviceentitlement;
|
|
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__CANCELED;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__DISABLED;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__FAILED;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__INCOMPATIBLE;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__SUCCESSFUL;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__TIMEOUT;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNEXPECTED_RESULT;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNKNOWN_RESULT;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__PURPOSE__ACTIVATION;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__PURPOSE__UPDATE;
|
|
import static com.android.imsserviceentitlement.ImsServiceEntitlementStatsLog.IMS_SERVICE_ENTITLEMENT_UPDATED__SERVICE_TYPE__VOWIFI;
|
|
|
|
import android.app.Activity;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.os.CountDownTimer;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.MainThread;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.StringRes;
|
|
|
|
import com.android.imsserviceentitlement.entitlement.EntitlementResult;
|
|
import com.android.imsserviceentitlement.ts43.Ts43VowifiStatus;
|
|
import com.android.imsserviceentitlement.utils.ImsUtils;
|
|
import com.android.imsserviceentitlement.utils.MetricsLogger;
|
|
import com.android.imsserviceentitlement.utils.TelephonyUtils;
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
|
|
import java.time.Duration;
|
|
|
|
/**
|
|
* The driver for WFC activation workflow: go/vowifi-entitlement-status-analysis.
|
|
*
|
|
* <p>One {@link WfcActivationActivity} owns one and only one controller instance.
|
|
*/
|
|
public class WfcActivationController {
|
|
private static final String TAG = "IMSSE-WfcActivationController";
|
|
|
|
// Entitlement status update retry
|
|
private static final int ENTITLEMENT_STATUS_UPDATE_RETRY_MAX = 6;
|
|
private static final long ENTITLEMENT_STATUS_UPDATE_RETRY_INTERVAL_MS =
|
|
Duration.ofSeconds(5).toMillis();
|
|
|
|
// Dependencies
|
|
private final WfcActivationUi mActivationUi;
|
|
private final TelephonyUtils mTelephonyUtils;
|
|
private final ImsEntitlementApi mImsEntitlementApi;
|
|
private final ImsUtils mImsUtils;
|
|
private final Intent mStartIntent;
|
|
private final MetricsLogger mMetricsLogger;
|
|
|
|
// States
|
|
private int mEvaluateTimes = 0;
|
|
private int mAppResult = IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNKNOWN_RESULT;
|
|
|
|
@MainThread
|
|
public WfcActivationController(
|
|
Context context,
|
|
WfcActivationUi wfcActivationUi,
|
|
ImsEntitlementApi imsEntitlementApi,
|
|
Intent intent) {
|
|
this.mStartIntent = intent;
|
|
this.mActivationUi = wfcActivationUi;
|
|
this.mImsEntitlementApi = imsEntitlementApi;
|
|
this.mTelephonyUtils = new TelephonyUtils(context, getSubId());
|
|
this.mImsUtils = ImsUtils.getInstance(context, getSubId());
|
|
this.mMetricsLogger = new MetricsLogger(mTelephonyUtils);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
WfcActivationController(
|
|
Context context,
|
|
WfcActivationUi wfcActivationUi,
|
|
ImsEntitlementApi imsEntitlementApi,
|
|
Intent intent,
|
|
ImsUtils imsUtils,
|
|
MetricsLogger metricsLogger) {
|
|
this.mStartIntent = intent;
|
|
this.mActivationUi = wfcActivationUi;
|
|
this.mImsEntitlementApi = imsEntitlementApi;
|
|
this.mTelephonyUtils = new TelephonyUtils(context, getSubId());
|
|
this.mImsUtils = imsUtils;
|
|
this.mMetricsLogger = metricsLogger;
|
|
}
|
|
|
|
/** Indicates the controller to start WFC activation or emergency address update flow. */
|
|
@MainThread
|
|
public void startFlow() {
|
|
showGeneralWaitingUi();
|
|
evaluateEntitlementStatus();
|
|
if (isActivationFlow()) {
|
|
mMetricsLogger.start(IMS_SERVICE_ENTITLEMENT_UPDATED__PURPOSE__ACTIVATION);
|
|
} else {
|
|
mMetricsLogger.start(IMS_SERVICE_ENTITLEMENT_UPDATED__PURPOSE__UPDATE);
|
|
}
|
|
}
|
|
|
|
/** Evaluates entitlement status for activation or update. */
|
|
@MainThread
|
|
public void evaluateEntitlementStatus() {
|
|
if (!mTelephonyUtils.isNetworkConnected()) {
|
|
handleInitialEntitlementStatus(null);
|
|
return;
|
|
}
|
|
EntitlementUtils.entitlementCheck(
|
|
mImsEntitlementApi, result -> handleInitialEntitlementStatus(result));
|
|
}
|
|
|
|
/**
|
|
* Indicates the controller to re-evaluate WFC entitlement status after activation flow finished
|
|
* successfully (ie. not canceled) by user.
|
|
*/
|
|
@MainThread
|
|
public void finishFlow() {
|
|
showGeneralWaitingUi();
|
|
reevaluateEntitlementStatus();
|
|
}
|
|
|
|
/** Re-evaluate entitlement status after updating. */
|
|
@MainThread
|
|
public void reevaluateEntitlementStatus() {
|
|
EntitlementUtils.entitlementCheck(
|
|
mImsEntitlementApi, result -> handleReevaluationEntitlementStatus(result));
|
|
}
|
|
|
|
/** The interface for handling the entitlement check result. */
|
|
public interface EntitlementResultCallback {
|
|
void onEntitlementResult(EntitlementResult result);
|
|
}
|
|
|
|
/** Indicates the controller to finish on-going tasks and get ready to be destroyed. */
|
|
@MainThread
|
|
public void finish() {
|
|
EntitlementUtils.cancelEntitlementCheck();
|
|
|
|
// If no result set, it must be cancelled by user pressing back button.
|
|
if (mAppResult == IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNKNOWN_RESULT) {
|
|
mAppResult = IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__CANCELED;
|
|
}
|
|
mMetricsLogger.write(IMS_SERVICE_ENTITLEMENT_UPDATED__SERVICE_TYPE__VOWIFI, mAppResult);
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the app is launched for WFC activation; {@code false} for emergency
|
|
* address update.
|
|
*/
|
|
private boolean isActivationFlow() {
|
|
return ActivityConstants.isActivationFlow(mStartIntent);
|
|
}
|
|
|
|
private int getSubId() {
|
|
return ActivityConstants.getSubId(mStartIntent);
|
|
}
|
|
|
|
/** Returns UI title string resource ID based on {@link #isActivationFlow()}. */
|
|
@StringRes
|
|
private int getUiTitle() {
|
|
int intention = ActivityConstants.getLaunchIntention(mStartIntent);
|
|
if (intention == ActivityConstants.LAUNCH_APP_ACTIVATE) {
|
|
return R.string.activate_title;
|
|
}
|
|
if (intention == ActivityConstants.LAUNCH_APP_SHOW_TC) {
|
|
return R.string.tos_title;
|
|
}
|
|
// LAUNCH_APP_UPDATE or otherwise
|
|
return R.string.e911_title;
|
|
}
|
|
|
|
/** Returns general error string resource ID based on {@link #isActivationFlow()}. */
|
|
@StringRes
|
|
private int getGeneralErrorText() {
|
|
int intention = ActivityConstants.getLaunchIntention(mStartIntent);
|
|
if (intention == ActivityConstants.LAUNCH_APP_ACTIVATE) {
|
|
return R.string.wfc_activation_error;
|
|
} else if (intention == ActivityConstants.LAUNCH_APP_SHOW_TC) {
|
|
return R.string.show_terms_and_condition_error;
|
|
}
|
|
// LAUNCH_APP_UPDATE or otherwise
|
|
return R.string.address_update_error;
|
|
}
|
|
|
|
private void showErrorUi(@StringRes int errorMessage) {
|
|
mActivationUi.showActivationUi(
|
|
getUiTitle(), errorMessage, false, R.string.ok, WfcActivationUi.RESULT_FAILURE, 0);
|
|
}
|
|
|
|
private void showGeneralErrorUi() {
|
|
showErrorUi(getGeneralErrorText());
|
|
}
|
|
|
|
private void showGeneralWaitingUi() {
|
|
mActivationUi.showActivationUi(getUiTitle(), R.string.progress_text, true, 0, 0, 0);
|
|
}
|
|
|
|
@MainThread
|
|
private void handleInitialEntitlementStatus(@Nullable EntitlementResult result) {
|
|
Log.d(TAG, "Initial entitlement result: " + result);
|
|
if (result == null) {
|
|
showGeneralErrorUi();
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__FAILED);
|
|
return;
|
|
}
|
|
if (isActivationFlow()) {
|
|
handleEntitlementStatusForActivation(result);
|
|
} else {
|
|
handleEntitlementStatusForUpdating(result);
|
|
}
|
|
}
|
|
|
|
@MainThread
|
|
private void handleEntitlementStatusForActivation(EntitlementResult result) {
|
|
Ts43VowifiStatus vowifiStatus = result.getVowifiStatus();
|
|
if (vowifiStatus.vowifiEntitled()) {
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__SUCCESSFUL);
|
|
mActivationUi.setResultAndFinish(Activity.RESULT_OK);
|
|
} else {
|
|
if (vowifiStatus.serverDataMissing()) {
|
|
if (!TextUtils.isEmpty(result.getTermsAndConditionsWebUrl())) {
|
|
mActivationUi.showWebview(
|
|
result.getTermsAndConditionsWebUrl(), /* postData= */ null);
|
|
} else {
|
|
mActivationUi.showWebview(
|
|
result.getEmergencyAddressWebUrl(),
|
|
result.getEmergencyAddressWebData());
|
|
}
|
|
} else if (vowifiStatus.incompatible()) {
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__INCOMPATIBLE);
|
|
showErrorUi(R.string.failure_contact_carrier);
|
|
} else {
|
|
Log.e(TAG, "Unexpected status. Show error UI.");
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNEXPECTED_RESULT);
|
|
showGeneralErrorUi();
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainThread
|
|
private void handleEntitlementStatusForUpdating(EntitlementResult result) {
|
|
Ts43VowifiStatus vowifiStatus = result.getVowifiStatus();
|
|
if (vowifiStatus.vowifiEntitled()) {
|
|
int launchIntention = ActivityConstants.getLaunchIntention(mStartIntent);
|
|
if (launchIntention == ActivityConstants.LAUNCH_APP_SHOW_TC) {
|
|
mActivationUi.showWebview(
|
|
result.getTermsAndConditionsWebUrl(), /* postData= */ null);
|
|
} else {
|
|
mActivationUi.showWebview(
|
|
result.getEmergencyAddressWebUrl(), result.getEmergencyAddressWebData());
|
|
}
|
|
} else {
|
|
if (vowifiStatus.incompatible()) {
|
|
showErrorUi(R.string.failure_contact_carrier);
|
|
mImsUtils.turnOffWfc(
|
|
() -> finishStatsLog(
|
|
IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__INCOMPATIBLE)
|
|
);
|
|
} else {
|
|
Log.e(TAG, "Unexpected status. Show error UI.");
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNEXPECTED_RESULT);
|
|
showGeneralErrorUi();
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainThread
|
|
private void handleReevaluationEntitlementStatus(@Nullable EntitlementResult result) {
|
|
Log.d(TAG, "Reevaluation entitlement result: " + result);
|
|
if (result == null) { // Network issue
|
|
showGeneralErrorUi();
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__FAILED);
|
|
return;
|
|
}
|
|
if (isActivationFlow()) {
|
|
handleEntitlementStatusAfterActivation(result);
|
|
} else {
|
|
handleEntitlementStatusAfterUpdating(result);
|
|
}
|
|
}
|
|
|
|
@MainThread
|
|
private void handleEntitlementStatusAfterActivation(EntitlementResult result) {
|
|
Ts43VowifiStatus vowifiStatus = result.getVowifiStatus();
|
|
if (vowifiStatus.vowifiEntitled()) {
|
|
mActivationUi.setResultAndFinish(Activity.RESULT_OK);
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__SUCCESSFUL);
|
|
} else {
|
|
if (vowifiStatus.serverDataMissing()) {
|
|
// Check again after 5s, max retry 6 times
|
|
if (mEvaluateTimes < ENTITLEMENT_STATUS_UPDATE_RETRY_MAX) {
|
|
mEvaluateTimes += 1;
|
|
postDelay(
|
|
getEntitlementStatusUpdateRetryIntervalMs(),
|
|
this::reevaluateEntitlementStatus);
|
|
} else {
|
|
mEvaluateTimes = 0;
|
|
showGeneralErrorUi();
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__TIMEOUT);
|
|
}
|
|
} else {
|
|
// These should never happen, but nothing else we can do. Show general error.
|
|
Log.e(TAG, "Unexpected status. Show error UI.");
|
|
showGeneralErrorUi();
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNEXPECTED_RESULT);
|
|
}
|
|
}
|
|
}
|
|
|
|
private long getEntitlementStatusUpdateRetryIntervalMs() {
|
|
return ENTITLEMENT_STATUS_UPDATE_RETRY_INTERVAL_MS;
|
|
}
|
|
|
|
@MainThread
|
|
private void handleEntitlementStatusAfterUpdating(EntitlementResult result) {
|
|
Ts43VowifiStatus vowifiStatus = result.getVowifiStatus();
|
|
if (vowifiStatus.vowifiEntitled()) {
|
|
mActivationUi.setResultAndFinish(Activity.RESULT_OK);
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__SUCCESSFUL);
|
|
} else if (vowifiStatus.serverDataMissing()) {
|
|
// Some carrier allows de-activating in updating flow.
|
|
mImsUtils.turnOffWfc(
|
|
() -> {
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__DISABLED);
|
|
mActivationUi.setResultAndFinish(Activity.RESULT_OK);
|
|
});
|
|
} else {
|
|
Log.e(TAG, "Unexpected status. Show error UI.");
|
|
showGeneralErrorUi();
|
|
finishStatsLog(IMS_SERVICE_ENTITLEMENT_UPDATED__APP_RESULT__UNEXPECTED_RESULT);
|
|
}
|
|
}
|
|
|
|
/** Runs {@code action} on caller's thread after {@code delayMillis} ms. */
|
|
private static void postDelay(long delayMillis, Runnable action) {
|
|
new CountDownTimer(delayMillis, delayMillis + 100) {
|
|
// Use a countDownInterval bigger than millisInFuture so onTick never fires.
|
|
@Override
|
|
public void onTick(long millisUntilFinished) {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void onFinish() {
|
|
action.run();
|
|
}
|
|
}.start();
|
|
}
|
|
|
|
private void finishStatsLog(int result) {
|
|
mAppResult = result;
|
|
}
|
|
}
|