Combine UsbManager.setPrimaryFunction and setDefaultFunction

Due to the property trigger on persist.sys.usb.config,
setting the default function also sets the current function.
Now we combine both of these methods into setCurrentFunction, which has
a "makeDefault" option to make the new function the default.

This change should eliminate some problems with setting properties due to
multiple property triggers happening at the same time.

Change-Id: I9851299e9c2ee20475eada1a8104c0d50bf5a9e1
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 2b9c082..9bab797 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -82,11 +82,8 @@
     /* Clears default preferences and permissions for the package */
     void clearDefaults(String packageName);
 
-    /* Sets the current primary USB function. */
-    void setPrimaryFunction(String functions);
-
-    /* Sets the default primary USB function. */
-    void setDefaultFunction(String functions);
+    /* Sets the current USB function. */
+    void setCurrentFunction(String function, boolean makeDefault);
 
     /* Sets the file path for USB mass storage backing file. */
     void setMassStorageBackingFile(String path);
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index a828a23..67d200c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -408,32 +408,18 @@
     }
 
     /**
-     * Sets the primary USB function.
+     * Sets the current USB function.
      *
      * @param function name of the USB function
+     * @param makeDefault true if this should be set as the default
      *
      * {@hide}
      */
-    public void setPrimaryFunction(String function) {
+    public void setCurrentFunction(String function, boolean makeDefault) {
         try {
-            mService.setPrimaryFunction(function);
+            mService.setCurrentFunction(function, makeDefault);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setPrimaryFunction", e);
-        }
-    }
-
-    /**
-     * Sets the default primary USB function.
-     *
-     * @param function name of the USB function
-     *
-     * {@hide}
-     */
-    public void setDefaultFunction(String function) {
-        try {
-            mService.setDefaultFunction(function);
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setDefaultFunction", e);
+            Log.e(TAG, "RemoteException in setCurrentFunction", e);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
index 7b07f79..60906a1 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
@@ -1,97 +1,96 @@
-/*

- * Copyright (C) 2011 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.systemui.usb;

-

-import android.app.Activity;

-import android.app.AlertDialog;

-import android.content.Context;

-import android.content.DialogInterface;

-import android.hardware.usb.UsbManager;

-import android.os.Bundle;

-import android.view.LayoutInflater;

-import android.view.View;

-import android.util.Log;

-import android.widget.Button;

-

-import java.io.File;

-

-import com.android.systemui.R;

-

-public class UsbPreferenceActivity extends Activity implements View.OnClickListener  {

-

-    private static final String TAG = "UsbPreferenceActivity";

-

-    private UsbManager mUsbManager;

-    private String mCurrentFunction;

-    private String[] mFunctions;

-    private String mInstallerImagePath;

+/*
+ * Copyright (C) 2011 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.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.util.Log;
+import android.widget.Button;
+
+import java.io.File;
+
+import com.android.systemui.R;
+
+public class UsbPreferenceActivity extends Activity implements View.OnClickListener  {
+
+    private static final String TAG = "UsbPreferenceActivity";
+
+    private UsbManager mUsbManager;
+    private String mCurrentFunction;
+    private String[] mFunctions;
+    private String mInstallerImagePath;
     private AlertDialog mDialog;
-    private Button mMtpPtpButton;

-    private Button mInstallerCdButton;

-    private boolean mPtpActive;

-

-    @Override

-    public void onCreate(Bundle icicle) {

-        super.onCreate(icicle);

-

-        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);

-

-        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);

-        dialogBuilder.setTitle(getString(R.string.usb_preference_title));

-

-        LayoutInflater inflater = (LayoutInflater)getSystemService(

-                Context.LAYOUT_INFLATER_SERVICE);

-        View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);

-        dialogBuilder.setView(buttonView);

-        mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);

-        mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);

-        mMtpPtpButton.setOnClickListener(this);

-        mInstallerCdButton.setOnClickListener(this);

-

-        mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);

-        if (mPtpActive) {

-            mMtpPtpButton.setText(R.string.use_mtp_button_title);

-        }

-

-        mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);

-        if (!(new File(mInstallerImagePath)).exists()) {

-            mInstallerCdButton.setVisibility(View.GONE);

-        }

-

+    private Button mMtpPtpButton;
+    private Button mInstallerCdButton;
+    private boolean mPtpActive;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+
+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+        dialogBuilder.setTitle(getString(R.string.usb_preference_title));
+
+        LayoutInflater inflater = (LayoutInflater)getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);
+        dialogBuilder.setView(buttonView);
+        mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);
+        mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);
+        mMtpPtpButton.setOnClickListener(this);
+        mInstallerCdButton.setOnClickListener(this);
+
+        mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);
+        if (mPtpActive) {
+            mMtpPtpButton.setText(R.string.use_mtp_button_title);
+        }
+
+        mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);
+        if (!(new File(mInstallerImagePath)).exists()) {
+            mInstallerCdButton.setVisibility(View.GONE);
+        }
+
         mDialog = dialogBuilder.show();
-    }

-

-    public void onClick(View v) {

-        if (v.equals(mMtpPtpButton)) {

-            if (mPtpActive) {

-                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MTP);

-                mUsbManager.setDefaultFunction(UsbManager.USB_FUNCTION_MTP);

-            } else {

-                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_PTP);

-                mUsbManager.setDefaultFunction(UsbManager.USB_FUNCTION_PTP);

-            }

-        } else if (v.equals(mInstallerCdButton)) {

-            mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MASS_STORAGE);

-            mUsbManager.setMassStorageBackingFile(mInstallerImagePath);

-        }

-

+    }
+
+    public void onClick(View v) {
+        if (v.equals(mMtpPtpButton)) {
+            if (mPtpActive) {
+                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);
+            } else {
+                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
+            }
+        } else if (v.equals(mInstallerCdButton)) {
+            // installer CD is never default
+            mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MASS_STORAGE, false);
+            mUsbManager.setMassStorageBackingFile(mInstallerImagePath);
+        }
+
         if (mDialog != null) {
             mDialog.dismiss();
         }
         finish();

-    }

-}

+    }
+}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 15e67d0..946a270 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -509,9 +509,9 @@
         }
         try {
             if (enabled) {
-                usbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_RNDIS);
+                usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
             } else {
-                usbManager.setPrimaryFunction(null);
+                usbManager.setCurrentFunction(null, false);
             }
         } catch (Exception e) {
             Log.e(TAG, "Error toggling usb RNDIS", e);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index b7f9d5c..918f1b6 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -77,9 +77,8 @@
 
     private static final int MSG_UPDATE_STATE = 0;
     private static final int MSG_ENABLE_ADB = 1;
-    private static final int MSG_SET_PRIMARY_FUNCTION = 2;
-    private static final int MSG_SET_DEFAULT_FUNCTION = 3;
-    private static final int MSG_SYSTEM_READY = 4;
+    private static final int MSG_SET_CURRENT_FUNCTION = 2;
+    private static final int MSG_SYSTEM_READY = 3;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
@@ -227,7 +226,7 @@
                 mHandler.updateState(state);
             } else if ("START".equals(accessory)) {
                 Slog.d(TAG, "got accessory start");
-                setPrimaryFunction(UsbManager.USB_FUNCTION_ACCESSORY);
+                setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
             }
         }
     };
@@ -371,6 +370,14 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, Object arg0, boolean arg1) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg0;
+            m.arg1 = (arg1 ? 1 : 0);
+            sendMessage(m);
+        }
+
         public void updateState(String state) {
             int connected, configured;
 
@@ -395,24 +402,30 @@
             sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
         }
 
-        private boolean setUsbConfig(String config) {
-            // set the new configuration
-            SystemProperties.set("sys.usb.config", config);
+        private boolean waitForState(String state) {
             // wait for the transition to complete.
             // give up after 1 second.
             for (int i = 0; i < 20; i++) {
                 // State transition is done when sys.usb.conf.done is set to the new configuration
-                if (config.equals(SystemProperties.get("sys.usb.state"))) return true;
+                if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
                 try {
                     // try again in 50ms
                     Thread.sleep(50);
                 } catch (InterruptedException e) {
                 }
             }
+            Log.e(TAG, "waitForState(" + state + ") FAILED");
             return false;
         }
 
-        private void setCurrentFunctions(String functions) {
+        private boolean setUsbConfig(String config) {
+            Log.d(TAG, "setUsbConfig(" + config + ")");
+            // set the new configuration
+            SystemProperties.set("sys.usb.config", config);
+            return waitForState(config);
+        }
+
+        private void doSetCurrentFunctions(String functions) {
             if (!mCurrentFunctions.equals(functions)) {
                 if (!setUsbConfig("none") || !setUsbConfig(functions)) {
                     Log.e(TAG, "Failed to switch USB configuration to " + functions);
@@ -428,17 +441,14 @@
             if (enable != mAdbEnabled) {
                 mAdbEnabled = enable;
                 String functions;
+                // Due to the persist.sys.usb.config property trigger, changing adb state requires
+                // switching to default function
                 if (enable) {
-                    functions = addFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
-                    mDefaultFunctions = addFunction(mDefaultFunctions,
-                            UsbManager.USB_FUNCTION_ADB);
+                    functions = addFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB);
                 } else {
-                    functions = removeFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
-                    mDefaultFunctions = removeFunction(mDefaultFunctions,
-                            UsbManager.USB_FUNCTION_ADB);
+                    functions = removeFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB);
                 }
-                SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
-                setCurrentFunctions(functions);
+                setCurrentFunction(functions, true);
                 updateAdbNotification(mAdbEnabled && mConnected);
             }
         }
@@ -449,7 +459,7 @@
             } else {
                 functionList = removeFunction(functionList, UsbManager.USB_FUNCTION_ADB);
             }
-            setCurrentFunctions(functionList);
+            doSetCurrentFunctions(functionList);
         }
 
         private void updateCurrentAccessory() {
@@ -503,8 +513,6 @@
 
         @Override
         public void handleMessage(Message msg) {
-            String function;
-
             switch (msg.what) {
                 case MSG_UPDATE_STATE:
                     mConnected = (msg.arg1 == 1);
@@ -518,7 +526,7 @@
 
                     if (!mConnected) {
                         // restore defaults when USB is disconnected
-                        setCurrentFunctions(mDefaultFunctions);
+                        doSetCurrentFunctions(mDefaultFunctions);
                     }
                     if (mSystemReady) {
                         updateUsbState();
@@ -527,20 +535,31 @@
                 case MSG_ENABLE_ADB:
                     setAdbEnabled(msg.arg1 == 1);
                     break;
-                case MSG_SET_PRIMARY_FUNCTION:
-                    function = (String)msg.obj;
-                    if (function == null) {
-                        function = mDefaultFunctions;
+                case MSG_SET_CURRENT_FUNCTION:
+                    String function = (String)msg.obj;
+                    boolean makeDefault = (msg.arg1 == 1);
+                    if (makeDefault) {
+                        if (function == null) {
+                            throw new NullPointerException();
+                        }
+                        if (mAdbEnabled) {
+                            function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
+                        }
+
+                        setUsbConfig("none");
+                        // setting this property will change the current USB state
+                        // via a property trigger
+                        SystemProperties.set("persist.sys.usb.config", function);
+                        if (waitForState(function)) {
+                            mCurrentFunctions = function;
+                            mDefaultFunctions = function;
+                        }
+                    } else {
+                        if (function == null) {
+                            function = mDefaultFunctions;
+                        }
+                        setEnabledFunctions(function);
                     }
-                    setEnabledFunctions(function);
-                    break;
-                case MSG_SET_DEFAULT_FUNCTION:
-                    function = (String)msg.obj;
-                    if (mAdbEnabled) {
-                        function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
-                    }
-                    SystemProperties.set("persist.sys.usb.config", function);
-                    mDefaultFunctions = function;
                     break;
                 case MSG_SYSTEM_READY:
                     updateUsbNotification(mConnected);
@@ -588,15 +607,8 @@
             return nativeOpenAccessory();
         }
 
-    public void setPrimaryFunction(String function) {
-        mHandler.sendMessage(MSG_SET_PRIMARY_FUNCTION, function);
-    }
-
-    public void setDefaultFunction(String function) {
-        if (function == null) {
-            throw new NullPointerException();
-        }
-        mHandler.sendMessage(MSG_SET_DEFAULT_FUNCTION, function);
+    public void setCurrentFunction(String function, boolean makeDefault) {
+        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
     }
 
     public void setMassStorageBackingFile(String path) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 193638f..9f2c17a 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -146,19 +146,10 @@
         mSettingsManager.clearDefaults(packageName);
     }
 
-    public void setPrimaryFunction(String function) {
+    public void setCurrentFunction(String function, boolean makeDefault) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         if (mDeviceManager != null) {
-            mDeviceManager.setPrimaryFunction(function);
-        } else {
-            throw new IllegalStateException("USB device mode not supported");
-        }
-    }
-
-    public void setDefaultFunction(String function) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        if (mDeviceManager != null) {
-            mDeviceManager.setDefaultFunction(function);
+            mDeviceManager.setCurrentFunction(function, makeDefault);
         } else {
             throw new IllegalStateException("USB device mode not supported");
         }