HfaLogic.java revision 00d7a430ac98cd65b7ae3afca5fa9509f1480eda
100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon/*
200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * Copyright (C) 2013 The Android Open Source Project
300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * you may not use this file except in compliance with the License.
600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * You may obtain a copy of the License at
700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
1000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * Unless required by applicable law or agreed to in writing, software
1100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
1200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * See the License for the specific language governing permissions and
1400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * limitations under the License.
1500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon */
1600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
1700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonpackage com.android.phone;
1800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
1900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.content.BroadcastReceiver;
2000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.content.Context;
2100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.content.Intent;
2200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.content.IntentFilter;
2300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.os.AsyncResult;
2400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.os.Handler;
2500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.os.Message;
2600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.telephony.ServiceState;
2700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport android.util.Log;
2800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
2900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport com.android.internal.telephony.Phone;
3000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonimport com.google.common.base.Preconditions;
3100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
3200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon/**
3300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * Starts and displays status for Hands Free Activation (HFA).
3400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
3500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * This class operates with Hands Free Activation apps.
3600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * It starts by broadcasting the intent com.android.action.START_HFA.
3700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * An HFA app will pick that up and start the HFA process.
3800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * If it fails it return ERROR_HFA Intent and upon success returns COMPLETE_HFA.
3900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
4000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * If successful, we bounce the radio so that the service picks up the new number.
4100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * Once the radio is back on we callback the requestor.
4200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
4300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * If there is an error, we do not bounce the radio but still callback with a failure.
4400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon *
4500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon * TODO(klp): We need system-only permissions for the HFA intents.
4600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon */
4700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordonpublic class HfaLogic {
4800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final String TAG = HfaLogic.class.getSimpleName();
4900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
5000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
5100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final String ACTION_START = "com.android.action.START_HFA";
5200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final String ACTION_ERROR = "com.android.action.ERROR_HFA";
5300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final String ACTION_CANCEL = "com.android.action.CANCEL_HFA";
5400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final String ACTION_COMPLETE = "com.android.action.COMPLETE_HFA";
5500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
5600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private static final int SERVICE_STATE_CHANGED = 1;
5700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
5800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    public static final int NOT_WAITING = 0;
5900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    public static final int WAITING_FOR_RADIO_OFF = 1;
6000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    public static final int WAITING_FOR_RADIO_ON = 2;
6100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
6200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private int mPhoneMonitorState = NOT_WAITING;
6300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private BroadcastReceiver mReceiver;
6400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private HfaLogicCallback mCallback;
6500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private Context mContext;
6600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
6700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    public interface HfaLogicCallback {
6800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        public void onSuccess();
6900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        public void onError(String errorMsg);
7000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
7100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
7200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    public HfaLogic(Context context, HfaLogicCallback callback) {
7300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mCallback = Preconditions.checkNotNull(callback);
7400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mContext = Preconditions.checkNotNull(context);
7500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
7600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
7700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    public void start() {
7800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        Log.i(TAG, "Start Hfa Provisioning.");
7900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        startHfaIntentReceiver();
8000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        startProvisioning();
8100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
8200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
8300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void startProvisioning() {
8400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        sendHfaCommand(ACTION_START);
8500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
8600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
8700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void sendHfaCommand(String action) {
8800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        if (VERBOSE) Log.v(TAG, "Sending command: " + action);
8900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mContext.sendBroadcast(new Intent(action));
9000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
9100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
9200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void onHfaError(String errorMsg) {
9300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        stopHfaIntentReceiver();
9400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mCallback.onError(errorMsg);
9500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
9600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
9700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void onHfaSuccess() {
9800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        stopHfaIntentReceiver();
9900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        bounceRadio();
10000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
10100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
10200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void onTotalSuccess() {
10300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mCallback.onSuccess();
10400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
10500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
10600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void bounceRadio() {
10700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        final Phone phone = PhoneGlobals.getInstance().getPhone();
10800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        phone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);
10900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
11000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mPhoneMonitorState = WAITING_FOR_RADIO_OFF;
11100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        phone.setRadioPower(false);
11200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        onServiceStateChange(phone.getServiceState());
11300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
11400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
11500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void onServiceStateChange(ServiceState state) {
11600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        final boolean radioIsOff = state.getVoiceRegState() == ServiceState.STATE_POWER_OFF;
11700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        final Phone phone = PhoneGlobals.getInstance().getPhone();
11800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
11900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        if (VERBOSE) Log.v(TAG, "Radio is on: " + !radioIsOff);
12000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
12100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        if (mPhoneMonitorState == WAITING_FOR_RADIO_OFF) {
12200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            if (radioIsOff) {
12300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                mPhoneMonitorState = WAITING_FOR_RADIO_ON;
12400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                phone.setRadioPower(true);
12500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            }
12600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        } else if (mPhoneMonitorState == WAITING_FOR_RADIO_ON) {
12700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            if (!radioIsOff) {
12800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                mPhoneMonitorState = NOT_WAITING;
12900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                phone.unregisterForServiceStateChanged(mHandler);
13000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
13100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                onTotalSuccess();
13200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            }
13300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        }
13400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
13500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
13600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void startHfaIntentReceiver() {
13700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        final IntentFilter filter = new IntentFilter(ACTION_COMPLETE);
13800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        filter.addAction(ACTION_ERROR);
13900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
14000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mReceiver = new BroadcastReceiver() {
14100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            @Override
14200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            public void onReceive(Context context, Intent intent) {
14300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                final String action = intent.getAction();
14400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                if (action.equals(ACTION_ERROR)) {
14500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    onHfaError(intent.getStringExtra("errorCode"));
14600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                } else if (action.equals(ACTION_COMPLETE)) {
14700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    if (VERBOSE) Log.v(TAG, "Hfa Successful");
14800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    onHfaSuccess();
14900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                }
15000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            }
15100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        };
15200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
15300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        mContext.registerReceiver(mReceiver, filter);
15400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
15500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
15600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private void stopHfaIntentReceiver() {
15700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        if (mReceiver != null) {
15800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            mContext.unregisterReceiver(mReceiver);
15900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            mReceiver = null;
16000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        }
16100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    }
16200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
16300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    private Handler mHandler = new Handler() {
16400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        @Override
16500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        public void handleMessage(Message msg) {
16600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            switch (msg.what) {
16700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                case SERVICE_STATE_CHANGED:
16800d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
16900d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    onServiceStateChange(state);
17000d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    break;
17100d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                default:
17200d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon                    break;
17300d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon            }
17400d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon        }
17500d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon    };
17600d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon
17700d7a430ac98cd65b7ae3afca5fa9509f1480edaSantos Cordon}
178