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.PendingIntent; 20 import android.app.PendingIntent.CanceledException; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.os.AsyncResult; 26 import android.os.Handler; 27 import android.os.Message; 28 import android.telephony.ServiceState; 29 import android.util.Log; 30 31 import com.android.internal.telephony.Phone; 32 import com.google.common.base.Preconditions; 33 34 /** 35 * Starts and displays status for Hands Free Activation (HFA). 36 * 37 * This class operates with Hands Free Activation apps. 38 * It starts by broadcasting the intent com.android.action.START_HFA. 39 * An HFA app will pick that up and start the HFA process. 40 * If it fails it return ERROR_HFA Intent and upon success returns COMPLETE_HFA. 41 * 42 * If successful, we bounce the radio so that the service picks up the new number. 43 * Once the radio is back on we callback the requestor. 44 * 45 * If there is an error, we do not bounce the radio but still callback with a failure. 46 * 47 * TODO(klp): We need system-only permissions for the HFA intents. 48 */ 49 public class HfaLogic { 50 private static final String TAG = HfaLogic.class.getSimpleName(); 51 52 private static final String ACTION_START = "com.android.action.START_HFA"; 53 private static final String ACTION_ERROR = "com.android.action.ERROR_HFA"; 54 private static final String ACTION_CANCEL = "com.android.action.CANCEL_HFA"; 55 private static final String ACTION_COMPLETE = "com.android.action.COMPLETE_HFA"; 56 57 private static final int SERVICE_STATE_CHANGED = 1; 58 59 public static final int NOT_WAITING = 0; 60 public static final int WAITING_FOR_RADIO_OFF = 1; 61 public static final int WAITING_FOR_RADIO_ON = 2; 62 63 public static final int OTASP_UNKNOWN = 0; 64 public static final int OTASP_USER_SKIPPED = 1; 65 public static final int OTASP_SUCCESS = 2; 66 public static final int OTASP_FAILURE = 3; 67 68 private int mPhoneMonitorState = NOT_WAITING; 69 private BroadcastReceiver mReceiver; 70 private HfaLogicCallback mCallback; 71 private PendingIntent mResponseIntent; 72 private Context mContext; 73 74 // No retry at the moment. Increase later if necessary. 75 private static final int DEFAULT_RETRY_COUNT = 0; 76 private int mRetryCount; 77 78 public interface HfaLogicCallback { onSuccess()79 public void onSuccess(); onError(String errorMsg)80 public void onError(String errorMsg); 81 } 82 HfaLogic(Context context, HfaLogicCallback callback, PendingIntent intent)83 public HfaLogic(Context context, HfaLogicCallback callback, PendingIntent intent) { 84 mCallback = Preconditions.checkNotNull(callback); 85 mContext = Preconditions.checkNotNull(context); 86 mResponseIntent = intent; 87 } 88 start()89 public void start() { 90 Log.i(TAG, "start:"); 91 mRetryCount = DEFAULT_RETRY_COUNT; 92 startHfaIntentReceiver(); 93 startProvisioning(); 94 } 95 startProvisioning()96 private void startProvisioning() { 97 Log.i(TAG, "startProvisioning:"); 98 sendHfaCommand(ACTION_START); 99 } 100 sendHfaCommand(String action)101 private void sendHfaCommand(String action) { 102 Log.i(TAG, "sendHfaCommand: command=" + action); 103 mContext.sendBroadcast(new Intent(action)); 104 } 105 onHfaError(String errorMsg)106 private void onHfaError(String errorMsg) { 107 Log.i(TAG, "onHfaError: call mCallBack.onError errorMsg=" + errorMsg 108 + " mRetryCount=" + mRetryCount); 109 mRetryCount -= 1; 110 if (mRetryCount >= 0) { 111 Log.i(TAG, "onHfaError: retry"); 112 startProvisioning(); 113 } else { 114 Log.i(TAG, "onHfaError: Declare OTASP_FAILURE"); 115 mRetryCount = 0; 116 stopHfaIntentReceiver(); 117 sendFinalResponse(OTASP_FAILURE, errorMsg); 118 mCallback.onError(errorMsg); 119 } 120 } 121 onHfaSuccess()122 private void onHfaSuccess() { 123 Log.i(TAG, "onHfaSuccess: NOT bouncing radio call onTotalSuccess"); 124 stopHfaIntentReceiver(); 125 // bounceRadio(); 126 onTotalSuccess(); 127 } 128 onTotalSuccess()129 private void onTotalSuccess() { 130 Log.i(TAG, "onTotalSuccess: call mCallBack.onSuccess"); 131 sendFinalResponse(OTASP_SUCCESS, null); 132 mCallback.onSuccess(); 133 } 134 bounceRadio()135 private void bounceRadio() { 136 final Phone phone = PhoneGlobals.getInstance().getPhone(); 137 phone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null); 138 139 mPhoneMonitorState = WAITING_FOR_RADIO_OFF; 140 phone.setRadioPower(false); 141 onServiceStateChange(phone.getServiceState()); 142 } 143 onServiceStateChange(ServiceState state)144 private void onServiceStateChange(ServiceState state) { 145 final boolean radioIsOff = state.getVoiceRegState() == ServiceState.STATE_POWER_OFF; 146 final Phone phone = PhoneGlobals.getInstance().getPhone(); 147 148 Log.i(TAG, "Radio is on: " + !radioIsOff); 149 150 if (mPhoneMonitorState == WAITING_FOR_RADIO_OFF) { 151 if (radioIsOff) { 152 mPhoneMonitorState = WAITING_FOR_RADIO_ON; 153 phone.setRadioPower(true); 154 } 155 } else if (mPhoneMonitorState == WAITING_FOR_RADIO_ON) { 156 if (!radioIsOff) { 157 mPhoneMonitorState = NOT_WAITING; 158 phone.unregisterForServiceStateChanged(mHandler); 159 160 onTotalSuccess(); 161 } 162 } 163 } 164 startHfaIntentReceiver()165 private void startHfaIntentReceiver() { 166 final IntentFilter filter = new IntentFilter(ACTION_COMPLETE); 167 filter.addAction(ACTION_ERROR); 168 169 mReceiver = new BroadcastReceiver() { 170 @Override 171 public void onReceive(Context context, Intent intent) { 172 final String action = intent.getAction(); 173 if (action.equals(ACTION_ERROR)) { 174 onHfaError(intent.getStringExtra("errorCode")); 175 } else if (action.equals(ACTION_COMPLETE)) { 176 Log.i(TAG, "Hfa Successful"); 177 onHfaSuccess(); 178 } 179 } 180 }; 181 182 mContext.registerReceiver(mReceiver, filter); 183 } 184 stopHfaIntentReceiver()185 private void stopHfaIntentReceiver() { 186 if (mReceiver != null) { 187 mContext.unregisterReceiver(mReceiver); 188 mReceiver = null; 189 } 190 } 191 sendFinalResponse(int responseCode, String errorCode)192 private void sendFinalResponse(int responseCode, String errorCode) { 193 if (mResponseIntent != null) { 194 final Intent extraStuff = new Intent(); 195 extraStuff.putExtra(OtaUtils.EXTRA_OTASP_RESULT_CODE, responseCode); 196 197 if (responseCode == OTASP_FAILURE && errorCode != null) { 198 extraStuff.putExtra(OtaUtils.EXTRA_OTASP_ERROR_CODE, errorCode); 199 } 200 201 try { 202 Log.i(TAG, "Sending OTASP confirmation with result code: " 203 + responseCode); 204 mResponseIntent.send(mContext, 0 /* resultCode (not used) */, extraStuff); 205 } catch (CanceledException e) { 206 Log.e(TAG, "Pending Intent canceled"); 207 } 208 } 209 } 210 211 private Handler mHandler = new Handler() { 212 @Override 213 public void handleMessage(Message msg) { 214 switch (msg.what) { 215 case SERVICE_STATE_CHANGED: 216 ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result; 217 onServiceStateChange(state); 218 break; 219 default: 220 break; 221 } 222 } 223 }; 224 225 } 226