1 /*
2  * Copyright (C) 2013 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;
18 
19 import android.app.Activity;
20 import android.app.Dialog;
21 import android.content.Intent;
22 import android.os.AsyncResult;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.telephony.SubscriptionManager;
27 import android.util.Log;
28 
29 import com.android.internal.telephony.CallManager;
30 import com.android.internal.telephony.MmiCode;
31 import com.android.internal.telephony.Phone;
32 import com.android.internal.telephony.PhoneConstants;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 
37 /**
38  * Used to display a dialog from within the Telephony service when running an USSD code
39  */
40 public class MMIDialogActivity extends Activity {
41     private static final String TAG = MMIDialogActivity.class.getSimpleName();
42 
43     private Dialog mMMIDialog;
44 
45     private Handler mHandler;
46 
47     private CallManager mCM = PhoneGlobals.getInstance().getCallManager();
48     private Phone mPhone;
49 
50 
51     @Override
onCreate(Bundle savedInstanceState)52     protected void onCreate(Bundle savedInstanceState) {
53         super.onCreate(savedInstanceState);
54         Intent intent = getIntent();
55         int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
56                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
57         mPhone = PhoneGlobals.getPhone(subId);
58         if (mPhone == null) {
59             Log.w(TAG, "onCreate: invalid subscription id (" + subId + ") lead to null"
60                     + " Phone.");
61             finish();
62         }
63         mHandler = new Handler() {
64                 @Override
65                 public void handleMessage(Message msg) {
66                     switch (msg.what) {
67                         case PhoneGlobals.MMI_COMPLETE:
68                             onMMIComplete((MmiCode) ((AsyncResult) msg.obj).result);
69                             break;
70                         case PhoneGlobals.MMI_CANCEL:
71                             onMMICancel();
72                             break;
73                     }
74                 }
75         };
76         Log.d(TAG, "onCreate; registering for mmi complete.");
77         mCM.registerForMmiComplete(mHandler, PhoneGlobals.MMI_COMPLETE, null);
78         showMMIDialog();
79     }
80 
81     @Override
onDestroy()82     protected void onDestroy() {
83         super.onDestroy();
84 
85         if (mMMIDialog != null) {
86             mMMIDialog.dismiss();
87             mMMIDialog = null;
88         }
89         if (mHandler != null) {
90             mCM.unregisterForMmiComplete(mHandler);
91             mHandler = null;
92         }
93     }
94 
showMMIDialog()95     private void showMMIDialog() {
96         final List<MmiCode> codes = new ArrayList<>(mPhone.getPendingMmiCodes());
97         // If the phone has an IMS phone, also get pending imS MMIsl.
98         if (mPhone.getImsPhone() != null) {
99             codes.addAll(mPhone.getImsPhone().getPendingMmiCodes());
100         }
101         if (codes.size() > 0) {
102             final MmiCode mmiCode = codes.get(0);
103             final Message message = Message.obtain(mHandler, PhoneGlobals.MMI_CANCEL);
104             Log.d(TAG, "showMMIDialog: mmiCode = " + mmiCode);
105             mMMIDialog = PhoneUtils.displayMMIInitiate(this, mmiCode, message, mMMIDialog);
106         } else {
107             Log.d(TAG, "showMMIDialog: no pending MMIs; finishing");
108             finish();
109         }
110     }
111 
112     /**
113      * Handles an MMI_COMPLETE event, which is triggered by telephony
114      */
onMMIComplete(MmiCode mmiCode)115     private void onMMIComplete(MmiCode mmiCode) {
116         // Check the code to see if the request is ready to
117         // finish, this includes any MMI state that is not
118         // PENDING.
119         Log.d(TAG, "onMMIComplete: mmi=" + mmiCode);
120 
121         // if phone is a CDMA phone display feature code completed message
122         int phoneType = mPhone.getPhoneType();
123         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
124             PhoneUtils.displayMMIComplete(mPhone, this, mmiCode, null, null);
125         } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
126             if (mmiCode.getState() != MmiCode.State.PENDING) {
127                 Log.d(TAG, "onMMIComplete: Got MMI_COMPLETE, finishing dialog activity...");
128                 dismissDialogsAndFinish();
129             } else {
130                 Log.d(TAG, "onMMIComplete: still pending.");
131             }
132         }
133     }
134 
135     /**
136      * Handles an MMI_CANCEL event, which is triggered by the button
137      * (labeled either "OK" or "Cancel") on the "MMI Started" dialog.
138      * @see PhoneUtils#cancelMmiCode(Phone)
139      */
onMMICancel()140     private void onMMICancel() {
141         Log.v(TAG, "onMMICancel()...");
142 
143         // First of all, cancel the outstanding MMI code (if possible.)
144         PhoneUtils.cancelMmiCode(mPhone);
145 
146         // Regardless of whether the current MMI code was cancelable, the
147         // PhoneApp will get an MMI_COMPLETE event very soon, which will
148         // take us to the MMI Complete dialog (see
149         // PhoneUtils.displayMMIComplete().)
150         //
151         // But until that event comes in, we *don't* want to stay here on
152         // the in-call screen, since we'll be visible in a
153         // partially-constructed state as soon as the "MMI Started" dialog
154         // gets dismissed. So let's forcibly bail out right now.
155         Log.d(TAG, "onMMICancel: finishing MMI dialog...");
156         dismissDialogsAndFinish();
157     }
158 
dismissDialogsAndFinish()159     private void dismissDialogsAndFinish() {
160         if (mMMIDialog != null) {
161             mMMIDialog.dismiss();
162             mMMIDialog = null;
163         }
164         if (mHandler != null) {
165             mCM.unregisterForMmiComplete(mHandler);
166             mHandler = null;
167         }
168         Log.v(TAG, "dismissDialogsAndFinish");
169         finish();
170     }
171 }
172