HfaLogic.java revision 00d7a430ac98cd65b7ae3afca5fa9509f1480eda
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
17package com.android.phone;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.os.AsyncResult;
24import android.os.Handler;
25import android.os.Message;
26import android.telephony.ServiceState;
27import android.util.Log;
28
29import com.android.internal.telephony.Phone;
30import com.google.common.base.Preconditions;
31
32/**
33 * Starts and displays status for Hands Free Activation (HFA).
34 *
35 * This class operates with Hands Free Activation apps.
36 * It starts by broadcasting the intent com.android.action.START_HFA.
37 * An HFA app will pick that up and start the HFA process.
38 * If it fails it return ERROR_HFA Intent and upon success returns COMPLETE_HFA.
39 *
40 * If successful, we bounce the radio so that the service picks up the new number.
41 * Once the radio is back on we callback the requestor.
42 *
43 * If there is an error, we do not bounce the radio but still callback with a failure.
44 *
45 * TODO(klp): We need system-only permissions for the HFA intents.
46 */
47public class HfaLogic {
48    private static final String TAG = HfaLogic.class.getSimpleName();
49    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
50
51    private static final String ACTION_START = "com.android.action.START_HFA";
52    private static final String ACTION_ERROR = "com.android.action.ERROR_HFA";
53    private static final String ACTION_CANCEL = "com.android.action.CANCEL_HFA";
54    private static final String ACTION_COMPLETE = "com.android.action.COMPLETE_HFA";
55
56    private static final int SERVICE_STATE_CHANGED = 1;
57
58    public static final int NOT_WAITING = 0;
59    public static final int WAITING_FOR_RADIO_OFF = 1;
60    public static final int WAITING_FOR_RADIO_ON = 2;
61
62    private int mPhoneMonitorState = NOT_WAITING;
63    private BroadcastReceiver mReceiver;
64    private HfaLogicCallback mCallback;
65    private Context mContext;
66
67    public interface HfaLogicCallback {
68        public void onSuccess();
69        public void onError(String errorMsg);
70    }
71
72    public HfaLogic(Context context, HfaLogicCallback callback) {
73        mCallback = Preconditions.checkNotNull(callback);
74        mContext = Preconditions.checkNotNull(context);
75    }
76
77    public void start() {
78        Log.i(TAG, "Start Hfa Provisioning.");
79        startHfaIntentReceiver();
80        startProvisioning();
81    }
82
83    private void startProvisioning() {
84        sendHfaCommand(ACTION_START);
85    }
86
87    private void sendHfaCommand(String action) {
88        if (VERBOSE) Log.v(TAG, "Sending command: " + action);
89        mContext.sendBroadcast(new Intent(action));
90    }
91
92    private void onHfaError(String errorMsg) {
93        stopHfaIntentReceiver();
94        mCallback.onError(errorMsg);
95    }
96
97    private void onHfaSuccess() {
98        stopHfaIntentReceiver();
99        bounceRadio();
100    }
101
102    private void onTotalSuccess() {
103        mCallback.onSuccess();
104    }
105
106    private void bounceRadio() {
107        final Phone phone = PhoneGlobals.getInstance().getPhone();
108        phone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);
109
110        mPhoneMonitorState = WAITING_FOR_RADIO_OFF;
111        phone.setRadioPower(false);
112        onServiceStateChange(phone.getServiceState());
113    }
114
115    private void onServiceStateChange(ServiceState state) {
116        final boolean radioIsOff = state.getVoiceRegState() == ServiceState.STATE_POWER_OFF;
117        final Phone phone = PhoneGlobals.getInstance().getPhone();
118
119        if (VERBOSE) Log.v(TAG, "Radio is on: " + !radioIsOff);
120
121        if (mPhoneMonitorState == WAITING_FOR_RADIO_OFF) {
122            if (radioIsOff) {
123                mPhoneMonitorState = WAITING_FOR_RADIO_ON;
124                phone.setRadioPower(true);
125            }
126        } else if (mPhoneMonitorState == WAITING_FOR_RADIO_ON) {
127            if (!radioIsOff) {
128                mPhoneMonitorState = NOT_WAITING;
129                phone.unregisterForServiceStateChanged(mHandler);
130
131                onTotalSuccess();
132            }
133        }
134    }
135
136    private void startHfaIntentReceiver() {
137        final IntentFilter filter = new IntentFilter(ACTION_COMPLETE);
138        filter.addAction(ACTION_ERROR);
139
140        mReceiver = new BroadcastReceiver() {
141            @Override
142            public void onReceive(Context context, Intent intent) {
143                final String action = intent.getAction();
144                if (action.equals(ACTION_ERROR)) {
145                    onHfaError(intent.getStringExtra("errorCode"));
146                } else if (action.equals(ACTION_COMPLETE)) {
147                    if (VERBOSE) Log.v(TAG, "Hfa Successful");
148                    onHfaSuccess();
149                }
150            }
151        };
152
153        mContext.registerReceiver(mReceiver, filter);
154    }
155
156    private void stopHfaIntentReceiver() {
157        if (mReceiver != null) {
158            mContext.unregisterReceiver(mReceiver);
159            mReceiver = null;
160        }
161    }
162
163    private Handler mHandler = new Handler() {
164        @Override
165        public void handleMessage(Message msg) {
166            switch (msg.what) {
167                case SERVICE_STATE_CHANGED:
168                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
169                    onServiceStateChange(state);
170                    break;
171                default:
172                    break;
173            }
174        }
175    };
176
177}
178