blob: 97dada00c8af35e37f78e17e08ce5adc408bcdb6 [file] [log] [blame]
/*
* Copyright (C) 2019 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.phone.settings;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.SubscriptionManager;
import android.view.WindowManager;
import android.util.Log;
import com.android.internal.telephony.IIntegerConsumer;
import java.util.ArrayList;
import java.util.List;
/**
* Trampolines a request to Settings to get the SMS subscription associated with an SmsManager
* operation.
*
* Since a Service can not start an Activity with
* {@link Activity#startActivityForResult(Intent, int)} and get a response (only Activities can
* handle the results), we have to "Trampoline" this operation by creating an empty Activity whose
* only job is to call startActivityForResult with the correct Intent and handle the result.
*/
// TODO: SmsManager should be constructed with an activity context so it can start as part of its
// task and fall back to PickSmsSubscriptionActivity being called in PhoneInterfaceManager if not
// called from an activity context.
public class PickSmsSubscriptionActivity extends Activity {
private static final String LOG_TAG = "PickSmsSubActivity";
// Defined in Settings SimDialogActivity
private static final String RESULT_SUB_ID = "result_sub_id";
public static final String DIALOG_TYPE_KEY = "dialog_type";
public static final int SMS_PICK_FOR_MESSAGE = 4;
private static final ComponentName SETTINGS_SUB_PICK_ACTIVITY = new ComponentName(
"com.android.settings", "com.android.settings.sim.SimDialogActivity");
private static final List<IIntegerConsumer> sSmsPickPendingList = new ArrayList<>();
private static final int REQUEST_GET_SMS_SUB_ID = 1;
/**
* Adds a consumer to the list of pending results that will be accepted once the activity
* completes.
*/
public static void addPendingResult(IIntegerConsumer consumer) {
synchronized (sSmsPickPendingList) {
sSmsPickPendingList.add(consumer);
}
Log.i(LOG_TAG, "queue pending result, token: " + consumer);
}
private static void sendResultAndClear(int resultId) {
// If the calling process died, just ignore callback.
synchronized (sSmsPickPendingList) {
for (IIntegerConsumer c : sSmsPickPendingList) {
try {
c.accept(resultId);
Log.i(LOG_TAG, "Result received, token: " + c + ", result: " + resultId);
} catch (RemoteException e) {
// The calling process died, skip this one.
}
}
sSmsPickPendingList.clear();
}
}
// Keep track if this activity has been stopped (i.e. user navigated away, power screen off,...)
// if so, treat it as the user navigating away and end the task if it is restarted without an
// onCreate/onNewIntent.
private boolean mPreviouslyStopped = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addSystemFlags(
android.view.WindowManager.LayoutParams
.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
mPreviouslyStopped = false;
}
@Override
protected void onNewIntent(Intent intent) {
mPreviouslyStopped = false;
}
@Override
protected void onResume() {
super.onResume();
// This is cause a little jank with the recents display, but there is no other way to handle
// the case where activity has stopped and we want to dismiss the dialog. We use the
// tag "excludeFromRecents", but in the cases where it is still shown, kill it in onResume.
if (mPreviouslyStopped) {
finishAndRemoveTask();
} else {
launchSmsPicker(new Intent(getIntent()));
}
}
@Override
protected void onStop() {
super.onStop();
// User navigated away from dialog, send invalid sub id result.
mPreviouslyStopped = true;
sendResultAndClear(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
// triggers cancelled result for onActivityResult
finishActivity(REQUEST_GET_SMS_SUB_ID);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_GET_SMS_SUB_ID) {
int result = data == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
data.getIntExtra(RESULT_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (resultCode == Activity.RESULT_OK) {
sendResultAndClear(result);
} else {
sendResultAndClear(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
}
// This will be handled in onResume - we do not want to call this all the time here because
// we need to be able to restart if stopped and a new intent comes in via onNewIntent.
if (!mPreviouslyStopped) {
finishAndRemoveTask();
}
}
private void launchSmsPicker(Intent trampolineIntent) {
trampolineIntent.setComponent(SETTINGS_SUB_PICK_ACTIVITY);
// Remove this flag if it exists, we want the settings activity to be part of this task.
trampolineIntent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(trampolineIntent, REQUEST_GET_SMS_SUB_ID);
}
}