Merge changes I00d6980a,I814221b4,Id88603a5

* changes:
  CameraBrowser: Launch itself when a camera is attached to USB.
  Send Intents when PTP compatible devices are connected/disconnected to USB
  Give system server permission to access USB.
diff --git a/core/java/android/hardware/Usb.java b/core/java/android/hardware/Usb.java
index 57271d4..1028f9f 100644
--- a/core/java/android/hardware/Usb.java
+++ b/core/java/android/hardware/Usb.java
@@ -55,6 +55,24 @@
     public static final String ACTION_USB_STATE =
             "android.hardware.action.USB_STATE";
 
+   /**
+     * Broadcast Action:  A broadcast for USB camera attached event.
+     *
+     * This intent is sent when a USB device supporting PTP is attached to the host USB bus.
+     * The intent's data contains a Uri for the device in the MTP provider.
+     */
+    public static final String ACTION_USB_CAMERA_ATTACHED =
+            "android.hardware.action.USB_CAMERA_ATTACHED";
+
+   /**
+     * Broadcast Action:  A broadcast for USB camera detached event.
+     *
+     * This intent is sent when a USB device supporting PTP is detached from the host USB bus.
+     * The intent's data contains a Uri for the device in the MTP provider.
+     */
+    public static final String ACTION_USB_CAMERA_DETACHED =
+            "android.hardware.action.USB_CAMERA_DETACHED";
+
     /**
      * Boolean extra indicating whether USB is connected or disconnected.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9fcd3f5..f8a77a1 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -523,7 +523,7 @@
         String args[] = {
             "--setuid=1000",
             "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
+            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
             "--capabilities=130104352,130104352",
             "--runtime-init",
             "--nice-name=system_server",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a66fe86..01ded68 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -83,6 +83,8 @@
     <protected-broadcast android:name="android.hardware.action.USB_CONNECTED" />
     <protected-broadcast android:name="android.hardware.action.USB_DISCONNECTED" />
     <protected-broadcast android:name="android.hardware.action.USB_STATE" />
+    <protected-broadcast android:name="android.hardware.action.USB_CAMERA_ATTACHED" />
+    <protected-broadcast android:name="android.hardware.action.USB_CAMERA_DETACHED" />
 
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
diff --git a/media/tests/CameraBrowser/AndroidManifest.xml b/media/tests/CameraBrowser/AndroidManifest.xml
index 5a71179..eae0b01 100644
--- a/media/tests/CameraBrowser/AndroidManifest.xml
+++ b/media/tests/CameraBrowser/AndroidManifest.xml
@@ -14,6 +14,14 @@
         <activity android:name="StorageBrowser" />
         <activity android:name="ObjectBrowser" />
         <activity android:name="ObjectViewer" />
+
+        <receiver android:name="UsbReceiver">
+            <intent-filter>
+                <action android:name="android.hardware.action.USB_CAMERA_ATTACHED" />
+                <data android:scheme="content"/>
+            </intent-filter>
+        </receiver>
+
     </application>
 
 
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/UsbReceiver.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/UsbReceiver.java
new file mode 100644
index 0000000..c05b239
--- /dev/null
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/UsbReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 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.camerabrowser;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.hardware.Usb;
+import android.net.Uri;
+import android.util.Log;
+
+public class UsbReceiver extends BroadcastReceiver
+{
+    private static final String TAG = "UsbReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "onReceive " + intent);
+        if (Usb.ACTION_USB_CAMERA_ATTACHED.equals(intent.getAction())) {
+            Uri uri = intent.getData();
+            intent = new Intent(context, StorageBrowser.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            try {
+                // TODO - add a wrapper to Mtp.Device for this
+                int id = Integer.parseInt(uri.getPathSegments().get(1));
+                intent.putExtra("device", id);
+                context.startActivity(intent);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "bad device Uri " + uri);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/UsbObserver.java b/services/java/com/android/server/UsbObserver.java
index d08fe9b..546e5f8 100644
--- a/services/java/com/android/server/UsbObserver.java
+++ b/services/java/com/android/server/UsbObserver.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.UEventObserver;
+import android.provider.Mtp;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
@@ -147,8 +148,43 @@
         }
     }
 
+    private native void monitorUsbHostBus();
+
+    // called from JNI in monitorUsbHostBus()
+    private void usbCameraAdded(int deviceID) {
+        Intent intent = new Intent(Usb.ACTION_USB_CAMERA_ATTACHED,
+                                Mtp.Device.getContentUri(deviceID));
+        Log.d(TAG, "usbCameraAdded, sending " + intent);
+        mContext.sendBroadcast(intent);
+    }
+
+    // called from JNI in monitorUsbHostBus()
+    private void usbCameraRemoved(int deviceID) {
+        Intent intent = new Intent(Usb.ACTION_USB_CAMERA_DETACHED,
+                                Mtp.Device.getContentUri(deviceID));
+        Log.d(TAG, "usbCameraRemoved, sending " + intent);
+        mContext.sendBroadcast(intent);
+    }
+
+    private void initHostSupport() {
+        // Create a thread to call into native code to wait for USB host events.
+        // This thread will call us back on usbCameraAdded and usbCameraRemoved.
+        Runnable runnable = new Runnable() {
+            public void run() {
+                monitorUsbHostBus();
+            }
+        };
+        new Thread(null, runnable, "UsbObserver host thread").start();
+    }
+
     void systemReady() {
         synchronized (this) {
+            if (mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_hasUsbHostSupport)) {
+                // start monitoring for connected USB devices
+                initHostSupport();
+            }
+
             update();
             mSystemReady = true;
         }
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index cdc0a6f..459551d 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -8,6 +8,7 @@
     com_android_server_LightsService.cpp \
     com_android_server_PowerManagerService.cpp \
     com_android_server_SystemServer.cpp \
+    com_android_server_UsbObserver.cpp \
     com_android_server_VibratorService.cpp \
 	com_android_server_location_GpsLocationProvider.cpp \
     onload.cpp
@@ -25,6 +26,8 @@
 	libutils \
 	libui
 
+LOCAL_STATIC_LIBRARIES := libusbhost
+
 ifeq ($(TARGET_SIMULATOR),true)
 ifeq ($(TARGET_OS),linux)
 ifeq ($(TARGET_ARCH),x86)
diff --git a/services/jni/com_android_server_UsbObserver.cpp b/services/jni/com_android_server_UsbObserver.cpp
new file mode 100644
index 0000000..7c478d5
--- /dev/null
+++ b/services/jni/com_android_server_UsbObserver.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "UsbObserver"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "utils/Vector.h"
+
+#include <usbhost/usbhost.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <linux/usb/ch9.h>
+#else
+#include <linux/usb_ch9.h>
+#endif
+
+#include <stdio.h>
+
+namespace android
+{
+
+static jmethodID method_usbCameraAdded;
+static jmethodID method_usbCameraRemoved;
+
+Vector<int> mDeviceList;
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
+
+static int usb_device_added(const char *devname, void* client_data) {
+    // check to see if it is a camera
+    struct usb_descriptor_header* desc;
+    struct usb_descriptor_iter iter;
+
+    struct usb_device *device = usb_device_open(devname);
+    if (!device) {
+        LOGE("usb_device_open failed\n");
+        return 0;
+    }
+
+    usb_descriptor_iter_init(device, &iter);
+
+    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
+        if (desc->bDescriptorType == USB_DT_INTERFACE) {
+            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
+
+            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
+                interface->bInterfaceSubClass == 1 && // Still Image Capture
+                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
+            {
+                LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
+                        usb_device_get_product_name(device));
+
+                // interface should be followed by three endpoints
+                struct usb_endpoint_descriptor *ep;
+                struct usb_endpoint_descriptor *ep_in_desc = NULL;
+                struct usb_endpoint_descriptor *ep_out_desc = NULL;
+                struct usb_endpoint_descriptor *ep_intr_desc = NULL;
+                for (int i = 0; i < 3; i++) {
+                    ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
+                    if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
+                        LOGE("endpoints not found\n");
+                        goto done;
+                    }
+                    if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+                        if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                            ep_in_desc = ep;
+                        else
+                            ep_out_desc = ep;
+                    } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
+                        ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+                        ep_intr_desc = ep;
+                    }
+                }
+                if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
+                    LOGE("endpoints not found\n");
+                    goto done;
+                }
+
+                // if we got here, we found a camera
+                JNIEnv* env = AndroidRuntime::getJNIEnv();
+                jobject thiz = (jobject)client_data;
+
+                int id = usb_device_get_unique_id_from_name(devname);
+                mDeviceList.add(id);
+
+                env->CallVoidMethod(thiz, method_usbCameraAdded, id);
+                checkAndClearExceptionFromCallback(env, __FUNCTION__);
+            }
+        }
+    }
+done:
+    usb_device_close(device);
+    return 0;
+}
+
+static int usb_device_removed(const char *devname, void* client_data) {
+    int id = usb_device_get_unique_id_from_name(devname);
+
+    // see if it is a device we know about
+    for (int i = 0; i < mDeviceList.size(); i++) {
+        if (id  == mDeviceList[i]) {
+            mDeviceList.removeAt(i);
+
+            JNIEnv* env = AndroidRuntime::getJNIEnv();
+            jobject thiz = (jobject)client_data;
+
+            env->CallVoidMethod(thiz, method_usbCameraRemoved, id);
+            checkAndClearExceptionFromCallback(env, __FUNCTION__);
+            break;
+        }
+    }
+    return 0;
+}
+
+static void android_server_UsbObserver_monitorUsbHostBus(JNIEnv *env, jobject thiz)
+{
+    struct usb_host_context* context = usb_host_init();
+    if (!context) {
+        LOGE("usb_host_init failed");
+        return;
+    }
+    // this will never return so it is safe to pass thiz directly
+    usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
+}
+
+static JNINativeMethod method_table[] = {
+    { "monitorUsbHostBus", "()V", (void*)android_server_UsbObserver_monitorUsbHostBus }
+};
+
+int register_android_server_UsbObserver(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("com/android/server/UsbObserver");
+    if (clazz == NULL) {
+        LOGE("Can't find com/android/server/UsbObserver");
+        return -1;
+    }
+    method_usbCameraAdded = env->GetMethodID(clazz, "usbCameraAdded", "(I)V");
+    if (method_usbCameraAdded == NULL) {
+        LOGE("Can't find usbCameraAdded");
+        return -1;
+    }
+    method_usbCameraRemoved = env->GetMethodID(clazz, "usbCameraRemoved", "(I)V");
+    if (method_usbCameraRemoved == NULL) {
+        LOGE("Can't find usbCameraRemoved");
+        return -1;
+    }
+
+    return jniRegisterNativeMethods(env, "com/android/server/UsbObserver",
+            method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index cd4f0a4..3502aca 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -9,6 +9,7 @@
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_UsbObserver(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
@@ -32,6 +33,7 @@
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
     register_android_server_BatteryService(env);
+    register_android_server_UsbObserver(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
     register_android_server_location_GpsLocationProvider(env);