• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.phone.settings;
18 
19 import android.app.Activity;
20 import android.content.ComponentName;
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.os.RemoteException;
24 import android.telephony.SubscriptionManager;
25 import android.view.WindowManager;
26 import android.util.Log;
27 
28 import com.android.internal.telephony.IIntegerConsumer;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * Trampolines a request to Settings to get the SMS subscription associated with an SmsManager
35  * operation.
36  *
37  * Since a Service can not start an Activity with
38  * {@link Activity#startActivityForResult(Intent, int)} and get a response (only Activities can
39  * handle the results), we have to "Trampoline" this operation by creating an empty Activity whose
40  * only job is to call startActivityForResult with the correct Intent and handle the result.
41  */
42 // TODO: SmsManager should be constructed with an activity context so it can start as part of its
43 // task and fall back to PickSmsSubscriptionActivity being called in PhoneInterfaceManager if not
44 // called from an activity context.
45 public class PickSmsSubscriptionActivity extends Activity {
46 
47     private static final String LOG_TAG = "PickSmsSubActivity";
48 
49     // Defined in Settings SimDialogActivity
50     private static final String RESULT_SUB_ID = "result_sub_id";
51     public static final String DIALOG_TYPE_KEY = "dialog_type";
52     public static final int SMS_PICK_FOR_MESSAGE = 4;
53 
54     private static final ComponentName SETTINGS_SUB_PICK_ACTIVITY = new ComponentName(
55             "com.android.settings", "com.android.settings.sim.SimDialogActivity");
56 
57     private static final List<IIntegerConsumer> sSmsPickPendingList = new ArrayList<>();
58 
59     private static final int REQUEST_GET_SMS_SUB_ID = 1;
60 
61     /**
62      * Adds a consumer to the list of pending results that will be accepted once the activity
63      * completes.
64      */
addPendingResult(IIntegerConsumer consumer)65     public static void addPendingResult(IIntegerConsumer consumer) {
66         synchronized (sSmsPickPendingList) {
67             sSmsPickPendingList.add(consumer);
68         }
69         Log.i(LOG_TAG, "queue pending result, token: " + consumer);
70     }
71 
sendResultAndClear(int resultId)72     private static void sendResultAndClear(int resultId) {
73         // If the calling process died, just ignore callback.
74         synchronized (sSmsPickPendingList) {
75             for (IIntegerConsumer c : sSmsPickPendingList) {
76                 try {
77                     c.accept(resultId);
78                     Log.i(LOG_TAG, "Result received, token: " + c + ", result: " + resultId);
79                 } catch (RemoteException e) {
80                     // The calling process died, skip this one.
81                 }
82             }
83             sSmsPickPendingList.clear();
84         }
85     }
86 
87     // Keep track if this activity has been stopped (i.e. user navigated away, power screen off,...)
88     // if so, treat it as the user navigating away and end the task if it is restarted without an
89     // onCreate/onNewIntent.
90     private boolean mPreviouslyStopped = false;
91 
92     @Override
onCreate(Bundle savedInstanceState)93     protected void onCreate(Bundle savedInstanceState) {
94         super.onCreate(savedInstanceState);
95         getWindow().addSystemFlags(
96                 android.view.WindowManager.LayoutParams
97                         .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
98         mPreviouslyStopped = false;
99     }
100 
101     @Override
onNewIntent(Intent intent)102     protected void onNewIntent(Intent intent) {
103         mPreviouslyStopped = false;
104     }
105 
106     @Override
onResume()107     protected void onResume() {
108         super.onResume();
109         // This is cause a little jank with the recents display, but there is no other way to handle
110         // the case where activity has stopped and we want to dismiss the dialog. We use the
111         // tag "excludeFromRecents", but in the cases where it is still shown, kill it in onResume.
112         if (mPreviouslyStopped) {
113             finishAndRemoveTask();
114         } else {
115             launchSmsPicker(new Intent(getIntent()));
116         }
117     }
118 
119     @Override
onStop()120     protected void onStop() {
121         super.onStop();
122         // User navigated away from dialog, send invalid sub id result.
123         mPreviouslyStopped = true;
124         sendResultAndClear(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
125         // triggers cancelled result for onActivityResult
126         finishActivity(REQUEST_GET_SMS_SUB_ID);
127     }
128 
129     @Override
onActivityResult(int requestCode, int resultCode, Intent data)130     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
131         if (requestCode == REQUEST_GET_SMS_SUB_ID) {
132             int result = data == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
133                     data.getIntExtra(RESULT_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
134             if (resultCode == Activity.RESULT_OK) {
135                 sendResultAndClear(result);
136             } else {
137                 sendResultAndClear(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
138             }
139         }
140         // This will be handled in onResume - we do not want to call this all the time here because
141         // we need to be able to restart if stopped and a new intent comes in via onNewIntent.
142         if (!mPreviouslyStopped) {
143             finishAndRemoveTask();
144         }
145     }
146 
launchSmsPicker(Intent trampolineIntent)147     private void launchSmsPicker(Intent trampolineIntent) {
148         trampolineIntent.setComponent(SETTINGS_SUB_PICK_ACTIVITY);
149         // Remove this flag if it exists, we want the settings activity to be part of this task.
150         trampolineIntent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
151         startActivityForResult(trampolineIntent, REQUEST_GET_SMS_SUB_ID);
152     }
153 }
154