Add utility for manipulating CallForwardInfo.

Part of the motivation in this is to be able to provide clearer
function names and constant names for magical operations. It seemed
like to CallFeatureSettings (Voicemail Settings), these details
could be encapsulated on their own.

Bug: 17019623
Change-Id: Ie064cc0d47fb47643145562936ce8feadc4bec49
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 5c11521..eb1d7d8 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -57,11 +57,11 @@
 
 import com.android.ims.ImsManager;
 import com.android.internal.telephony.CallForwardInfo;
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.phone.common.util.SettingsUtil;
 import com.android.phone.settings.AccountSelectionPreference;
+import com.android.phone.settings.CallForwardInfoUtil;
 import com.android.phone.settings.VoicemailProviderSettings;
 import com.android.phone.settings.VoicemailProviderSettingsUtil;
 import com.android.phone.settings.fdn.FdnSetting;
@@ -200,11 +200,6 @@
     private static final int VOICEMAIL_FWD_READING_DIALOG = 602;
     private static final int VOICEMAIL_REVERTING_DIALOG = 603;
 
-    /**
-     * @see CallForwardInfo#status
-     */
-    private static final int CALL_FORWARD_INFO_INACTIVE_STATUS = 0;
-
     // voicemail notification vibration string constants
     private static final String VOICEMAIL_VIBRATION_ALWAYS = "always";
     private static final String VOICEMAIL_VIBRATION_NEVER = "never";
@@ -562,24 +557,16 @@
                     Log.i(LOG_TAG, "Requested to rollback Fwd changes.");
                     final CallForwardInfo[] prevFwdSettings = prevSettings.getForwardingSettings();
                     if (prevFwdSettings != null) {
-                        Map<Integer, AsyncResult> results =
-                            mForwardingChangeResults;
+                        Map<Integer, AsyncResult> results = mForwardingChangeResults;
                         resetForwardingChangeState();
                         for (int i = 0; i < prevFwdSettings.length; i++) {
                             CallForwardInfo fi = prevFwdSettings[i];
                             if (DBG) log("Reverting fwd #: " + i + ": " + fi.toString());
-                            // Only revert the settings for which the update
-                            // succeeded
+                            // Only revert the settings for which the update succeeded.
                             AsyncResult result = results.get(fi.reason);
                             if (result != null && result.exception == null) {
                                 mExpectedChangeResultReasons.add(fi.reason);
-                                mPhone.setCallForwardingOption(
-                                        (fi.status == 1 ?
-                                                CommandsInterface.CF_ACTION_REGISTRATION :
-                                                CommandsInterface.CF_ACTION_DISABLE),
-                                        fi.reason,
-                                        fi.number,
-                                        fi.timeSeconds,
+                                CallForwardInfoUtil.setCallForwardingOption(mPhone, fi,
                                         mRevertOptionComplete.obtainMessage(
                                                 EVENT_FORWARDING_CHANGED, i, 0));
                             }
@@ -808,14 +795,12 @@
         if (DBG) Log.d(LOG_TAG, "handleForwardingSettingsReadResult: " + idx);
         Throwable error = null;
         if (ar.exception != null) {
-            if (DBG) Log.d(LOG_TAG, "FwdRead: ar.exception=" +
-                    ar.exception.getMessage());
             error = ar.exception;
+            if (DBG) Log.d(LOG_TAG, "FwdRead: ar.exception=" + error.getMessage());
         }
         if (ar.userObj instanceof Throwable) {
-            if (DBG) Log.d(LOG_TAG, "FwdRead: userObj=" +
-                    ((Throwable)ar.userObj).getMessage());
-            error = (Throwable)ar.userObj;
+            error = (Throwable) ar.userObj;
+            if (DBG) Log.d(LOG_TAG, "FwdRead: userObj=" + error.getMessage());
         }
 
         // We may have already gotten an error and decided to ignore the other results.
@@ -833,33 +818,10 @@
             return;
         }
 
-        // Get the forwarding info
-        final CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
-        CallForwardInfo fi = null;
-        for (int i = 0 ; i < cfInfoArray.length; i++) {
-            if ((cfInfoArray[i].serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) {
-                fi = cfInfoArray[i];
-                break;
-            }
-        }
-        if (fi == null) {
-
-            // In case we go nothing it means we need this reason disabled
-            // so create a CallForwardInfo for capturing this
-            if (DBG) Log.d(LOG_TAG, "Creating default info for " + idx);
-            fi = new CallForwardInfo();
-            fi.status = 0;
-            fi.reason = VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[idx];
-            fi.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
-        } else {
-            // if there is not a forwarding number, ensure the entry is set to "not active."
-            if (fi.number == null || fi.number.length() == 0) {
-                fi.status = 0;
-            }
-
-            if (DBG) Log.d(LOG_TAG, "Got  " + fi.toString() + " for " + idx);
-        }
-        mForwardingReadResults[idx] = fi;
+        // Get the forwarding info.
+        mForwardingReadResults[idx] = CallForwardInfoUtil.getCallForwardInfo(
+                (CallForwardInfo[]) ar.result,
+                VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[idx]);
 
         // Check if we got all the results already
         boolean done = true;
@@ -869,9 +831,11 @@
                 break;
             }
         }
+
         if (done) {
             if (DBG) Log.d(LOG_TAG, "Done receiving fwd info");
             dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
+
             if (mReadingSettingsForDefaultProvider) {
                 mVmProviderSettingsUtil.save(DEFAULT_VM_PROVIDER_KEY,
                         new VoicemailProviderSettings(this.mOldVmNumber, mForwardingReadResults));
@@ -882,34 +846,6 @@
             if (DBG) Log.d(LOG_TAG, "Not done receiving fwd info");
         }
     }
-
-    private CallForwardInfo infoForReason(CallForwardInfo[] infos, int reason) {
-        CallForwardInfo result = null;
-        if (null != infos) {
-            for (CallForwardInfo info : infos) {
-                if (info.reason == reason) {
-                    result = info;
-                    break;
-                }
-            }
-        }
-        return result;
-    }
-
-    private boolean isUpdateRequired(CallForwardInfo oldInfo, CallForwardInfo newInfo) {
-        if (oldInfo == null) {
-            return true;
-        }
-
-        // If we're disabling a type of forwarding, don't make any change if it's already disabled.
-        if (newInfo.status == CALL_FORWARD_INFO_INACTIVE_STATUS
-                && oldInfo.status == CALL_FORWARD_INFO_INACTIVE_STATUS) {
-            return false;
-        }
-
-        return true;
-    }
-
     private void resetForwardingChangeState() {
         mForwardingChangeResults = new HashMap<Integer, AsyncResult>();
         mExpectedChangeResultReasons = new HashSet<Integer>();
@@ -924,21 +860,15 @@
             resetForwardingChangeState();
             for (int i = 0; i < mNewFwdSettings.length; i++) {
                 CallForwardInfo fi = mNewFwdSettings[i];
-
-                final boolean doUpdate = isUpdateRequired(infoForReason(
-                            mForwardingReadResults, fi.reason), fi);
+                CallForwardInfo fiForReason =
+                        CallForwardInfoUtil.infoForReason(mForwardingReadResults, fi.reason);
+                final boolean doUpdate = CallForwardInfoUtil.isUpdateRequired(fiForReason, fi);
 
                 if (doUpdate) {
                     if (DBG) log("Setting fwd #: " + i + ": " + fi.toString());
                     mExpectedChangeResultReasons.add(i);
 
-                    mPhone.setCallForwardingOption(
-                            fi.status == 1 ?
-                                    CommandsInterface.CF_ACTION_REGISTRATION :
-                                    CommandsInterface.CF_ACTION_DISABLE,
-                            fi.reason,
-                            fi.number,
-                            fi.timeSeconds,
+                    CallForwardInfoUtil.setCallForwardingOption(mPhone, fi,
                             mSetOptionComplete.obtainMessage(
                                     EVENT_FORWARDING_CHANGED, fi.reason, 0));
                 }
diff --git a/src/com/android/phone/settings/CallForwardInfoUtil.java b/src/com/android/phone/settings/CallForwardInfoUtil.java
new file mode 100644
index 0000000..1983fab
--- /dev/null
+++ b/src/com/android/phone/settings/CallForwardInfoUtil.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2008 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.settings;
+
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+import com.android.phone.PhoneGlobals;
+
+public class CallForwardInfoUtil {
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
+    private static final String LOG_TAG = CallForwardInfoUtil.class.getSimpleName();
+
+    /**
+     * @see CallForwardInfo#status
+     */
+    private static final int CALL_FORWARD_INFO_INACTIVE_STATUS = 0;
+    private static final int CALL_FORWARD_INFO_ACTIVE_STATUS = 1;
+
+    /**
+     * Returns the first CallForwardInfo in infos which has the specified reason.
+     * @param infos array of CallForwardInfo objects.
+     * @param reason The reason we want to find a CallForwardInfo for.
+     */
+    public static CallForwardInfo infoForReason(CallForwardInfo[] infos, int reason) {
+        if (infos == null) {
+            return null;
+        }
+
+        CallForwardInfo result = null;
+        for (int i = 0; i < infos.length; i++) {
+            if (infos[i].reason == reason) {
+                return infos[i];
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Update, unless we're disabling a type of forwarding and it's already disabled.
+     */
+    public static boolean isUpdateRequired(CallForwardInfo oldInfo, CallForwardInfo newInfo) {
+        if (oldInfo == null) {
+            return true;
+        }
+
+        if (newInfo.status == CALL_FORWARD_INFO_INACTIVE_STATUS
+                && oldInfo.status == CALL_FORWARD_INFO_INACTIVE_STATUS) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Sets the call forwarding option on the phone, with the command interface action set to the
+     * appropriate value depending on whether the CallForwardInfo is active or inactive.
+     */
+    public static void setCallForwardingOption(Phone phone, CallForwardInfo info, Message message) {
+        int commandInterfaceCfAction = info.status == CALL_FORWARD_INFO_ACTIVE_STATUS
+                ? CommandsInterface.CF_ACTION_REGISTRATION
+                : CommandsInterface.CF_ACTION_DISABLE;
+
+        phone.setCallForwardingOption(commandInterfaceCfAction,
+                info.reason,
+                info.number,
+                info.timeSeconds,
+                message);
+    }
+
+    /**
+     * Retrieves a CallForwardInfo object of type {@link CommandInterface.SERVICE_CLASS_VOICE} from
+     * the array of CallForwardInfo objects. If one does not exist, instantiates an CallForwardInfo
+     * object which disables the specified reason.
+     */
+    public static CallForwardInfo getCallForwardInfo(CallForwardInfo[] infos, int reason) {
+        CallForwardInfo info = null;
+        for (int i = 0 ; i < infos.length; i++) {
+            if (isServiceClassVoice(infos[i])) {
+                info = infos[i];
+                break;
+            }
+        }
+
+        if (info == null) {
+            // If there is  no info, create a CallForwardInfo to disable this reason.
+            info = new CallForwardInfo();
+            info.status = CALL_FORWARD_INFO_INACTIVE_STATUS;
+            info.reason = reason;
+            info.serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
+
+            if (DBG) Log.d(LOG_TAG, "Created default info for reason: " + reason);
+        } else {
+            if (!hasForwardingNumber(info)) {
+                info.status = CALL_FORWARD_INFO_INACTIVE_STATUS;
+            }
+
+            if (DBG) Log.d(LOG_TAG, "Retrieved  " + info.toString() + " for " + reason);
+        }
+
+        return info;
+    }
+
+    private static boolean isServiceClassVoice(CallForwardInfo info) {
+        return (info.serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0;
+    }
+
+    private static boolean hasForwardingNumber(CallForwardInfo info) {
+        return info.number != null && info.number.length() > 0;
+    }
+}