1 /* 2 * Copyright (C) 2009 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.PendingIntent; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.content.pm.ResolveInfo; 25 import android.os.Bundle; 26 import android.os.SystemProperties; 27 import android.provider.Settings; 28 import android.util.Log; 29 30 import com.android.internal.telephony.Phone; 31 import com.android.internal.telephony.TelephonyCapabilities; 32 33 /** 34 * Invisible activity that handles the com.android.phone.PERFORM_CDMA_PROVISIONING intent. 35 * This activity is protected by the android.permission.PERFORM_CDMA_PROVISIONING permission. 36 * 37 * We handle the PERFORM_CDMA_PROVISIONING action by launching an OTASP 38 * call via one of the OtaUtils helper methods: startInteractiveOtasp() on 39 * regular phones, or startNonInteractiveOtasp() on data-only devices. 40 * 41 * TODO: The class name InCallScreenShowActivation is misleading, since 42 * this activity is totally unrelated to the InCallScreen (which 43 * implements the in-call UI.) Let's eventually rename this to something 44 * like CdmaProvisioningLauncher or CdmaProvisioningHandler... 45 */ 46 public class InCallScreenShowActivation extends Activity { 47 private static final String LOG_TAG = "InCallScreenShowActivation"; 48 private static final boolean DBG = 49 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 50 51 @Override 52 protected void onCreate(Bundle icicle) { 53 super.onCreate(icicle); 54 55 Intent intent = getIntent(); 56 if (DBG) Log.d(LOG_TAG, "onCreate: intent = " + intent); 57 Bundle extras = intent.getExtras(); 58 if (DBG && (extras != null)) { 59 Log.d(LOG_TAG, " - has extras: size = " + extras.size()); // forces an unparcel() 60 Log.d(LOG_TAG, " - extras = " + extras); 61 } 62 63 PhoneGlobals app = PhoneGlobals.getInstance(); 64 Phone phone = app.getPhone(); 65 if (!TelephonyCapabilities.supportsOtasp(phone)) { 66 Log.w(LOG_TAG, "CDMA Provisioning not supported on this device"); 67 setResult(RESULT_CANCELED); 68 finish(); 69 return; 70 } 71 72 if (intent.getAction().equals(OtaUtils.ACTION_PERFORM_CDMA_PROVISIONING)) { 73 74 boolean usesHfa = getResources().getBoolean(R.bool.config_use_hfa_for_provisioning); 75 if (usesHfa) { 76 Log.i(LOG_TAG, "Starting Hfa from ACTION_PERFORM_CDMA_PROVISIONING"); 77 startHfa(); 78 finish(); 79 return; 80 } 81 82 boolean usesOtasp = getResources().getBoolean(R.bool.config_use_otasp_for_provisioning); 83 if (usesOtasp) { 84 // On voice-capable devices, we perform CDMA provisioning in 85 // "interactive" mode by directly launching the InCallScreen. 86 // boolean interactiveMode = PhoneGlobals.sVoiceCapable; 87 // TODO: Renable interactive mode for device provisioning. 88 boolean interactiveMode = false; 89 Log.i(LOG_TAG, "ACTION_PERFORM_CDMA_PROVISIONING (interactiveMode = " 90 + interactiveMode + ")..."); 91 92 // Testing: this intent extra allows test apps manually 93 // enable/disable "interactive mode", regardless of whether 94 // the current device is voice-capable. This is allowed only 95 // in userdebug or eng builds. 96 if (intent.hasExtra(OtaUtils.EXTRA_OVERRIDE_INTERACTIVE_MODE) 97 && (SystemProperties.getInt("ro.debuggable", 0) == 1)) { 98 interactiveMode = 99 intent.getBooleanExtra(OtaUtils.EXTRA_OVERRIDE_INTERACTIVE_MODE, false); 100 Log.d(LOG_TAG, "==> MANUALLY OVERRIDING interactiveMode to " + interactiveMode); 101 } 102 103 // We allow the caller to pass a PendingIntent (as the 104 // EXTRA_NONINTERACTIVE_OTASP_RESULT_PENDING_INTENT extra) 105 // which we'll later use to notify them when the OTASP call 106 // fails or succeeds. 107 // 108 // Stash that away here, and we'll fire it off later in 109 // OtaUtils.sendOtaspResult(). 110 app.cdmaOtaScreenState.otaspResultCodePendingIntent = 111 (PendingIntent) intent.getParcelableExtra( 112 OtaUtils.EXTRA_OTASP_RESULT_CODE_PENDING_INTENT); 113 114 if (interactiveMode) { 115 // On voice-capable devices, launch an OTASP call and arrange 116 // for the in-call UI to come up. (The InCallScreen will 117 // notice that an OTASP call is active, and display the 118 // special OTASP UI instead of the usual in-call controls.) 119 120 if (DBG) Log.d(LOG_TAG, "==> Starting interactive CDMA provisioning..."); 121 OtaUtils.startInteractiveOtasp(this); 122 123 // The result we set here is actually irrelevant, since the 124 // InCallScreen's "interactive" OTASP sequence never actually 125 // finish()es; it ends by directly launching the Home 126 // activity. So our caller won't actually ever get an 127 // onActivityResult() call in this case. 128 setResult(OtaUtils.RESULT_INTERACTIVE_OTASP_STARTED); 129 } else { 130 // On data-only devices, manually launch the OTASP call 131 // *without* displaying any UI. (Our caller, presumably 132 // SetupWizardActivity, is responsible for displaying some 133 // sort of progress UI.) 134 135 if (DBG) Log.d(LOG_TAG, "==> Starting non-interactive CDMA provisioning..."); 136 int callStatus = OtaUtils.startNonInteractiveOtasp(this); 137 138 if (callStatus == PhoneUtils.CALL_STATUS_DIALED) { 139 if (DBG) Log.d(LOG_TAG, 140 " ==> successful result from startNonInteractiveOtasp(): " + 141 callStatus); 142 setResult(OtaUtils.RESULT_NONINTERACTIVE_OTASP_STARTED); 143 } else { 144 Log.w(LOG_TAG, "Failure code from startNonInteractiveOtasp(): " + 145 callStatus); 146 setResult(OtaUtils.RESULT_NONINTERACTIVE_OTASP_FAILED); 147 } 148 } 149 } else { 150 Log.i(LOG_TAG, "Skipping activation."); 151 } 152 } else { 153 Log.e(LOG_TAG, "Unexpected intent action: " + intent); 154 setResult(RESULT_CANCELED); 155 } 156 157 finish(); 158 } 159 160 /** 161 * On devices that provide a phone initialization wizard (such as Google Setup Wizard), 162 * the wizard displays it's own activation UI. The Hfa activation started by this class 163 * will show a UI or not depending on the status of the setup wizard. If the setup wizard 164 * is running, do not show a UI, otherwise show our own UI since setup wizard will not. 165 * 166 * The method checks two properties: 167 * 1. Does the device require a setup wizard (ro.setupwizard.mode == (REQUIRED|OPTIONAL)) 168 * 2. Is device_provisioned set to non-zero--a property that setup wizard sets at completion. 169 * @return true if wizard is running, false otherwise. 170 */ 171 private boolean isWizardRunning(Context context) { 172 Intent intent = new Intent("android.intent.action.DEVICE_INITIALIZATION_WIZARD"); 173 ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 174 PackageManager.MATCH_DEFAULT_ONLY); 175 boolean provisioned = Settings.Global.getInt(context.getContentResolver(), 176 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 177 String mode = SystemProperties.get("ro.setupwizard.mode", "REQUIRED"); 178 boolean runningSetupWizard = "REQUIRED".equals(mode) || "OPTIONAL".equals(mode); 179 if (DBG) { 180 Log.v(LOG_TAG, "resolvInfo = " + resolveInfo + ", provisioned = " + provisioned 181 + ", runningSetupWizard = " + runningSetupWizard); 182 } 183 return resolveInfo != null && !provisioned && runningSetupWizard; 184 } 185 186 /** 187 * Starts the HFA provisioning process by bringing up the HFA Activity. 188 */ 189 private void startHfa() { 190 boolean isWizardRunning = isWizardRunning(this); 191 // We always run our HFA logic if we're in setup wizard, but if we're outside of setup 192 // wizard then we have to check a config to see if we should still run HFA. 193 if (isWizardRunning || 194 getResources().getBoolean(R.bool.config_allow_hfa_outside_of_setup_wizard)) { 195 196 final Intent intent = new Intent(); 197 198 final PendingIntent otaResponseIntent = getIntent().getParcelableExtra( 199 OtaUtils.EXTRA_OTASP_RESULT_CODE_PENDING_INTENT); 200 201 final boolean showUi = !isWizardRunning; 202 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 203 204 if (otaResponseIntent != null) { 205 intent.putExtra(OtaUtils.EXTRA_OTASP_RESULT_CODE_PENDING_INTENT, otaResponseIntent); 206 } 207 208 Log.v(LOG_TAG, "Starting hfa activation activity"); 209 if (showUi) { 210 intent.setClassName(this, HfaActivity.class.getName()); 211 startActivity(intent); 212 } else { 213 intent.setClassName(this, HfaService.class.getName()); 214 startService(intent); 215 } 216 217 } 218 setResult(RESULT_OK); 219 } 220 } 221