Java程序  |  226行  |  7.73 KB

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.phone;

import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.telephony.ServiceState;
import android.util.Log;

import com.android.internal.telephony.Phone;
import com.google.common.base.Preconditions;

/**
 * Starts and displays status for Hands Free Activation (HFA).
 *
 * This class operates with Hands Free Activation apps.
 * It starts by broadcasting the intent com.android.action.START_HFA.
 * An HFA app will pick that up and start the HFA process.
 * If it fails it return ERROR_HFA Intent and upon success returns COMPLETE_HFA.
 *
 * If successful, we bounce the radio so that the service picks up the new number.
 * Once the radio is back on we callback the requestor.
 *
 * If there is an error, we do not bounce the radio but still callback with a failure.
 *
 * TODO(klp): We need system-only permissions for the HFA intents.
 */
public class HfaLogic {
    private static final String TAG = HfaLogic.class.getSimpleName();

    private static final String ACTION_START = "com.android.action.START_HFA";
    private static final String ACTION_ERROR = "com.android.action.ERROR_HFA";
    private static final String ACTION_CANCEL = "com.android.action.CANCEL_HFA";
    private static final String ACTION_COMPLETE = "com.android.action.COMPLETE_HFA";

    private static final int SERVICE_STATE_CHANGED = 1;

    public static final int NOT_WAITING = 0;
    public static final int WAITING_FOR_RADIO_OFF = 1;
    public static final int WAITING_FOR_RADIO_ON = 2;

    public static final int OTASP_UNKNOWN = 0;
    public static final int OTASP_USER_SKIPPED = 1;
    public static final int OTASP_SUCCESS = 2;
    public static final int OTASP_FAILURE = 3;

    private int mPhoneMonitorState = NOT_WAITING;
    private BroadcastReceiver mReceiver;
    private HfaLogicCallback mCallback;
    private PendingIntent mResponseIntent;
    private Context mContext;

    // No retry at the moment. Increase later if necessary.
    private static final int DEFAULT_RETRY_COUNT = 0;
    private int mRetryCount;

    public interface HfaLogicCallback {
        public void onSuccess();
        public void onError(String errorMsg);
    }

    public HfaLogic(Context context, HfaLogicCallback callback, PendingIntent intent) {
        mCallback = Preconditions.checkNotNull(callback);
        mContext = Preconditions.checkNotNull(context);
        mResponseIntent = intent;
    }

    public void start() {
        Log.i(TAG, "start:");
        mRetryCount = DEFAULT_RETRY_COUNT;
        startHfaIntentReceiver();
        startProvisioning();
    }

    private void startProvisioning() {
        Log.i(TAG, "startProvisioning:");
        sendHfaCommand(ACTION_START);
    }

    private void sendHfaCommand(String action) {
        Log.i(TAG, "sendHfaCommand: command=" + action);
        mContext.sendBroadcast(new Intent(action));
    }

    private void onHfaError(String errorMsg) {
        Log.i(TAG, "onHfaError: call mCallBack.onError errorMsg=" + errorMsg
                + " mRetryCount=" + mRetryCount);
        mRetryCount -= 1;
        if (mRetryCount >= 0) {
            Log.i(TAG, "onHfaError: retry");
            startProvisioning();
        } else {
            Log.i(TAG, "onHfaError: Declare OTASP_FAILURE");
            mRetryCount = 0;
            stopHfaIntentReceiver();
            sendFinalResponse(OTASP_FAILURE, errorMsg);
            mCallback.onError(errorMsg);
        }
    }

    private void onHfaSuccess() {
        Log.i(TAG, "onHfaSuccess: NOT bouncing radio call onTotalSuccess");
        stopHfaIntentReceiver();
        // bounceRadio();
        onTotalSuccess();
    }

    private void onTotalSuccess() {
        Log.i(TAG, "onTotalSuccess: call mCallBack.onSuccess");
        sendFinalResponse(OTASP_SUCCESS, null);
        mCallback.onSuccess();
    }

    private void bounceRadio() {
        final Phone phone = PhoneGlobals.getInstance().getPhone();
        phone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);

        mPhoneMonitorState = WAITING_FOR_RADIO_OFF;
        phone.setRadioPower(false);
        onServiceStateChange(phone.getServiceState());
    }

    private void onServiceStateChange(ServiceState state) {
        final boolean radioIsOff = state.getVoiceRegState() == ServiceState.STATE_POWER_OFF;
        final Phone phone = PhoneGlobals.getInstance().getPhone();

        Log.i(TAG, "Radio is on: " + !radioIsOff);

        if (mPhoneMonitorState == WAITING_FOR_RADIO_OFF) {
            if (radioIsOff) {
                mPhoneMonitorState = WAITING_FOR_RADIO_ON;
                phone.setRadioPower(true);
            }
        } else if (mPhoneMonitorState == WAITING_FOR_RADIO_ON) {
            if (!radioIsOff) {
                mPhoneMonitorState = NOT_WAITING;
                phone.unregisterForServiceStateChanged(mHandler);

                onTotalSuccess();
            }
        }
    }

    private void startHfaIntentReceiver() {
        final IntentFilter filter = new IntentFilter(ACTION_COMPLETE);
        filter.addAction(ACTION_ERROR);

        mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                if (action.equals(ACTION_ERROR)) {
                    onHfaError(intent.getStringExtra("errorCode"));
                } else if (action.equals(ACTION_COMPLETE)) {
                    Log.i(TAG, "Hfa Successful");
                    onHfaSuccess();
                }
            }
        };

        mContext.registerReceiver(mReceiver, filter);
    }

    private void stopHfaIntentReceiver() {
        if (mReceiver != null) {
            mContext.unregisterReceiver(mReceiver);
            mReceiver = null;
        }
    }

    private void sendFinalResponse(int responseCode, String errorCode) {
        if (mResponseIntent != null) {
            final Intent extraStuff = new Intent();
            extraStuff.putExtra(OtaUtils.EXTRA_OTASP_RESULT_CODE, responseCode);

            if (responseCode == OTASP_FAILURE && errorCode != null) {
                extraStuff.putExtra(OtaUtils.EXTRA_OTASP_ERROR_CODE, errorCode);
            }

            try {
                Log.i(TAG, "Sending OTASP confirmation with result code: "
                        + responseCode);
                mResponseIntent.send(mContext, 0 /* resultCode (not used) */, extraStuff);
            } catch (CanceledException e) {
                Log.e(TAG, "Pending Intent canceled");
            }
        }
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SERVICE_STATE_CHANGED:
                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
                    onServiceStateChange(state);
                    break;
                default:
                    break;
            }
        }
    };

}