diff --git a/api/system-current.txt b/api/system-current.txt index 3e47ac723abed..31973222bf54b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -15944,6 +15944,7 @@ package android.hardware.usb { method public java.lang.String getSerial(); method public boolean releaseInterface(android.hardware.usb.UsbInterface); method public android.hardware.usb.UsbRequest requestWait(); + method public boolean resetDevice(); method public boolean setConfiguration(android.hardware.usb.UsbConfiguration); method public boolean setInterface(android.hardware.usb.UsbInterface); } diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 6e4c9de1c8ef7..fafe116df606f 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -17,6 +17,7 @@ package android.hardware.usb; import android.app.PendingIntent; +import android.content.ComponentName; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbPort; @@ -116,4 +117,7 @@ interface IUsbManager /* Sets the port's current role. */ void setPortRoles(in String portId, int powerRole, int dataRole); + + /* Sets USB device connection handler. */ + void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler); } diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index c062b3a311526..54fea52624c0c 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -16,6 +16,7 @@ package android.hardware.usb; +import android.annotation.SystemApi; import android.os.ParcelFileDescriptor; import java.io.FileDescriptor; @@ -214,9 +215,21 @@ public class UsbDeviceConnection { return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout); } + /** + * Reset USB port for the connected device. + * + * @return true if reset succeeds. + * + * @hide + */ + @SystemApi + public boolean resetDevice() { + return native_reset_device(); + } + /** * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation - * Note that this may return requests queued on multiple + * Note that this may return requests queued on multiple * {@link android.hardware.usb.UsbEndpoint}s. * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining @@ -263,4 +276,5 @@ public class UsbDeviceConnection { int offset, int length, int timeout); private native UsbRequest native_request_wait(); private native String native_get_serial(); + private native boolean native_reset_device(); } diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 629db06a30e37..df4785ee45d96 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -19,7 +19,9 @@ package android.hardware.usb; import com.android.internal.util.Preconditions; +import android.annotation.Nullable; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; @@ -469,8 +471,20 @@ public class UsbManager { * {@hide} */ public void grantPermission(UsbDevice device) { + grantPermission(device, Process.myUid()); + } + + /** + * Grants permission for USB device to given uid without showing system dialog. + * Only system components can call this function. + * @param device to request permissions for + * @uid uid to give permission + * + * {@hide} + */ + public void grantPermission(UsbDevice device, int uid) { try { - mService.grantDevicePermission(device, Process.myUid()); + mService.grantDevicePermission(device, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -488,11 +502,9 @@ public class UsbManager { try { int uid = mContext.getPackageManager() .getPackageUidAsUser(packageName, mContext.getUserId()); - mService.grantDevicePermission(device, uid); + grantPermission(device, uid); } catch (NameNotFoundException e) { Log.e(TAG, "Package " + packageName + " not found.", e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); } } @@ -631,6 +643,26 @@ public class UsbManager { } } + /** + * Sets the component that will handle USB device connection. + *

+ * Setting component allows to specify external USB host manager to handle use cases, where + * selection dialog for an activity that will handle USB device is undesirable. + * Only system components can call this function, as it requires the MANAGE_USB permission. + * + * @param usbDeviceConnectionHandler The component to handle usb connections, + * {@code null} to unset. + * + * {@hide} + */ + public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) { + try { + mService.setUsbDeviceConnectionHandler(usbDeviceConnectionHandler); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ public static String addFunction(String functions, String function) { if (USB_FUNCTION_NONE.equals(functions)) { diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index 1ba9fc58800ca..f899c00ec1000 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -246,6 +246,18 @@ android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz) return result; } +static jboolean +android_hardware_UsbDeviceConnection_reset_device(JNIEnv *env, jobject thiz) +{ + struct usb_device* device = get_device_from_object(env, thiz); + if (!device) { + ALOGE("device is closed in native_reset_device"); + return JNI_FALSE; + } + int ret = usb_device_reset(device); + return (ret == 0) ? JNI_TRUE : JNI_FALSE; +} + static const JNINativeMethod method_table[] = { {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", (void *)android_hardware_UsbDeviceConnection_open}, @@ -264,6 +276,7 @@ static const JNINativeMethod method_table[] = { (void *)android_hardware_UsbDeviceConnection_request_wait}, { "native_get_serial", "()Ljava/lang/String;", (void*)android_hardware_UsbDeviceConnection_get_serial }, + {"native_reset_device","()Z", (void *)android_hardware_UsbDeviceConnection_reset_device}, }; int register_android_hardware_UsbDeviceConnection(JNIEnv *env) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ec93e47060f03..15b32c75010da 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1829,6 +1829,11 @@ Do not set this to true for production devices. Doing so will cause you to fail CTS. --> false + + @null + + + + + + + + + + + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/layout/device.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/layout/device.xml new file mode 100644 index 0000000000000..cc71cf9fc37ad --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/layout/device.xml @@ -0,0 +1,20 @@ + + + + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/xml/accessory_filter.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/xml/accessory_filter.xml new file mode 100644 index 0000000000000..d854a45923be6 --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/xml/accessory_filter.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java new file mode 100644 index 0000000000000..aa4f8caa0b20b --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 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.hardware.usb.aoapdevicetest; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbManager; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import libcore.io.IoUtils; + +public class UsbAoapDeviceTestActivity extends Activity { + private static final String TAG = UsbAoapDeviceTestActivity.class.getSimpleName(); + private static final boolean DBG = true; + + private static final String ACTION_USB_ACCESSORY_PERMISSION = + "com.android.hardware.usb.aoapdevicetest.ACTION_USB_ACCESSORY_PERMISSION"; + + private UsbManager mUsbManager; + private AccessoryReceiver mReceiver; + private ParcelFileDescriptor mFd; + private ReaderThread mReaderThread; + private UsbAccessory mAccessory; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.device); + + mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE); + IntentFilter filter = new IntentFilter(); + filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); + filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); + filter.addAction(ACTION_USB_ACCESSORY_PERMISSION); + mReceiver = new AccessoryReceiver(); + registerReceiver(mReceiver, filter); + + Intent intent = getIntent(); + if (intent.getAction().equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) { + UsbAccessory accessory = + (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); + if (accessory != null) { + onAccessoryAttached(accessory); + } else { + throw new RuntimeException("USB accessory is null."); + } + } else { + finish(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(mReceiver); + IoUtils.closeQuietly(mFd); + if (mReaderThread != null) { + mReaderThread.requestToQuit(); + try { + mReaderThread.join(1000); + } catch (InterruptedException e) { + } + if (mReaderThread.isAlive()) { // reader thread stuck + Log.w(TAG, "ReaderThread still alive"); + } + } + } + + private void onAccessoryAttached(UsbAccessory accessory) { + Log.i(TAG, "Starting AOAP discovery protocol, accessory attached: " + accessory); + // Check whether we have permission to access the accessory. + if (!mUsbManager.hasPermission(accessory)) { + Log.i(TAG, "Prompting the user for access to the accessory."); + Intent intent = new Intent(ACTION_USB_ACCESSORY_PERMISSION); + intent.setPackage(getPackageName()); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + this, 0, intent, PendingIntent.FLAG_ONE_SHOT); + mUsbManager.requestPermission(accessory, pendingIntent); + return; + } + mFd = mUsbManager.openAccessory(accessory); + if (mFd == null) { + Log.e(TAG, "UsbManager.openAccessory returned null"); + finish(); + return; + } + mAccessory = accessory; + mReaderThread = new ReaderThread(mFd); + mReaderThread.start(); + } + + private void onAccessoryDetached(UsbAccessory accessory) { + Log.i(TAG, "Accessory detached: " + accessory); + finish(); + } + + private class ReaderThread extends Thread { + private boolean mShouldQuit = false; + private final FileInputStream mInputStream; + private final FileOutputStream mOutputStream; + private final byte[] mBuffer = new byte[16384]; + + private ReaderThread(ParcelFileDescriptor fd) { + super("AOAP"); + mInputStream = new FileInputStream(fd.getFileDescriptor()); + mOutputStream = new FileOutputStream(fd.getFileDescriptor()); + } + + private synchronized void requestToQuit() { + mShouldQuit = true; + } + + private synchronized boolean shouldQuit() { + return mShouldQuit; + } + + @Override + public void run() { + while (!shouldQuit()) { + try { + int read = mInputStream.read(mBuffer); + } catch (IOException e) { + Log.i(TAG, "ReaderThread IOException", e); + // AOAP App should release FD when IOException happens. + // If FD is kept, device will not behave nicely on reset and multiple reset + // can be required. + finish(); + return; + } + } + } + } + + private class AccessoryReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); + if (accessory != null) { + String action = intent.getAction(); + if (action.equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) { + onAccessoryAttached(accessory); + } else if (action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)) { + if (mAccessory != null && mAccessory.equals(accessory)) { + onAccessoryDetached(accessory); + } + } else if (action.equals(ACTION_USB_ACCESSORY_PERMISSION)) { + if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { + Log.i(TAG, "Accessory permission granted: " + accessory); + onAccessoryAttached(accessory); + } else { + Log.e(TAG, "Accessory permission denied: " + accessory); + finish(); + } + } + } + } + } +} diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk new file mode 100644 index 0000000000000..354e8c9b7bf43 --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk @@ -0,0 +1,35 @@ +# Copyright (C) 2016 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. +# +# + +LOCAL_PATH:= $(call my-dir) + +################################################## + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := AoapTestHostApp + +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml new file mode 100644 index 0000000000000..8cc470eaa85c7 --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/res/layout/host.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/layout/host.xml new file mode 100644 index 0000000000000..cc71cf9fc37ad --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/layout/host.xml @@ -0,0 +1,20 @@ + + + + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/res/xml/usb_device_filter.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/xml/usb_device_filter.xml new file mode 100644 index 0000000000000..0509e89761643 --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/xml/usb_device_filter.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/src/com/android/hardware/usb/aoaphosttest/UsbAoapHostTestActivity.java b/tests/UsbHostExternalManagmentTest/AoapTestHost/src/com/android/hardware/usb/aoaphosttest/UsbAoapHostTestActivity.java new file mode 100644 index 0000000000000..6e2dc5d65fa7d --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/src/com/android/hardware/usb/aoaphosttest/UsbAoapHostTestActivity.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 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.hardware.usb.aoaphosttest; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbConstants; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.hardware.usb.UsbEndpoint; +import android.hardware.usb.UsbInterface; +import android.hardware.usb.UsbManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Process; +import android.text.TextUtils; +import android.util.Log; + +import libcore.io.IoUtils; + +public class UsbAoapHostTestActivity extends Activity { + + private static final String TAG = UsbAoapHostTestActivity.class.getSimpleName(); + + private UsbManager mUsbManager; + private UsbStateReceiver mReceiver; + private UsbDevice mUsbDevice; + private UsbDeviceConnection mUsbConnection; + private ReaderThread mReaderThread; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.host); + + mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE); + IntentFilter filter = new IntentFilter(); + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + mReceiver = new UsbStateReceiver(); + registerReceiver(mReceiver, filter); + + Intent intent = getIntent(); + if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) { + mUsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + mUsbConnection = mUsbManager.openDevice(mUsbDevice); + mReaderThread = new ReaderThread(mUsbDevice, mUsbConnection); + mReaderThread.start(); + } else { + finish(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(mReceiver); + if (mUsbConnection != null) { + mUsbConnection.close(); + } + if (mReaderThread != null) { + mReaderThread.requestToQuit(); + try { + mReaderThread.join(1000); + } catch (InterruptedException e) { + } + if (mReaderThread.isAlive()) { // reader thread stuck + throw new RuntimeException("ReaderThread still alive"); + } + } + } + + private static boolean isDevicesMatching(UsbDevice l, UsbDevice r) { + if (l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId() && + TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) { + return true; + } + return false; + } + + private class ReaderThread extends Thread { + private boolean mShouldQuit = false; + private final UsbDevice mDevice; + private final UsbDeviceConnection mUsbConnection; + private final UsbEndpoint mBulkIn; + private final UsbEndpoint mBulkOut; + private final byte[] mBuffer = new byte[16384]; + + private ReaderThread(UsbDevice device, UsbDeviceConnection conn) { + super("AOAP"); + mDevice = device; + mUsbConnection = conn; + UsbInterface iface = mDevice.getInterface(0); + // Setup bulk endpoints. + UsbEndpoint bulkIn = null; + UsbEndpoint bulkOut = null; + for (int i = 0; i < iface.getEndpointCount(); i++) { + UsbEndpoint ep = iface.getEndpoint(i); + if (ep.getDirection() == UsbConstants.USB_DIR_IN) { + if (bulkIn == null) { + bulkIn = ep; + } + } else { + if (bulkOut == null) { + bulkOut = ep; + } + } + } + if (bulkIn == null || bulkOut == null) { + throw new IllegalStateException("Unable to find bulk endpoints"); + } + mBulkIn = bulkIn; + mBulkOut = bulkOut; + } + + private synchronized void requestToQuit() { + mShouldQuit = true; + } + + private synchronized boolean shouldQuit() { + return mShouldQuit; + } + + @Override + public void run() { + while (!shouldQuit()) { + int read = mUsbConnection.bulkTransfer(mBulkIn, mBuffer, mBuffer.length, + Integer.MAX_VALUE); + if (read < 0) { + throw new RuntimeException("bulkTransfer failed, read = " + read); + } + } + } + } + + private class UsbStateReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) { + UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + if (isDevicesMatching(mUsbDevice, device)) { + finish(); + } + } + } + } +} diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk new file mode 100644 index 0000000000000..2d6d6ea8cdcca --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk @@ -0,0 +1,37 @@ +# Copyright (C) 2016 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. +# +# + +LOCAL_PATH:= $(call my-dir) + +################################################## + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := UsbHostExternalManagementTestApp + +LOCAL_PRIVILEGED_MODULE := true +# TODO remove tests tag +#LOCAL_MODULE_TAGS := tests +#LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml new file mode 100644 index 0000000000000..97bbefb5c4afa --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/layout/host_management.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/layout/host_management.xml new file mode 100644 index 0000000000000..51911846d78c7 --- /dev/null +++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/layout/host_management.xml @@ -0,0 +1,56 @@ + + + + + +