diff options
Diffstat (limited to 'media/tests')
17 files changed, 1619 insertions, 1 deletions
diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk new file mode 100644 index 0000000..33d2976 --- /dev/null +++ b/media/tests/CameraBrowser/Android.mk @@ -0,0 +1,8 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := CameraBrowser + +include $(BUILD_PACKAGE) diff --git a/media/tests/CameraBrowser/AndroidManifest.xml b/media/tests/CameraBrowser/AndroidManifest.xml new file mode 100644 index 0000000..eae0b01 --- /dev/null +++ b/media/tests/CameraBrowser/AndroidManifest.xml @@ -0,0 +1,28 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.camerabrowser"> + + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + + <application android:label="@string/app_label"> + <activity android:name="CameraBrowser" android:label="Camera Browser"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <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> + + +</manifest> diff --git a/media/tests/CameraBrowser/res/layout/object_info.xml b/media/tests/CameraBrowser/res/layout/object_info.xml new file mode 100644 index 0000000..c7fd830 --- /dev/null +++ b/media/tests/CameraBrowser/res/layout/object_info.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +*/ +--> +<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/object_info" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <TableRow> + <TextView android:id="@+id/name_label" + android:text="@string/name_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/name" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/size_label" + android:text="@string/size_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/size" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/thumb_width_label" + android:text="@string/thumb_width_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/thumb_width" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/thumb_height_label" + android:text="@string/thumb_height_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/thumb_height" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/thumb_size_label" + android:text="@string/thumb_size_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/thumb_size" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/width_label" + android:text="@string/width_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/width" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/height_label" + android:text="@string/height_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/height" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/depth_label" + android:text="@string/depth_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/depth" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/sequence_label" + android:text="@string/sequence_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/sequence" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/created_label" + android:text="@string/created_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/created" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/modified_label" + android:text="@string/modified_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/modified" + style="@style/info_value" /> + </TableRow> + <TableRow> + <TextView android:id="@+id/keywords_label" + android:text="@string/keywords_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/keywords" + style="@style/info_value" /> + </TableRow> + <TableRow> + <ImageView android:id="@+id/thumbnail" /> + </TableRow> +</TableLayout> + diff --git a/media/tests/CameraBrowser/res/layout/object_list.xml b/media/tests/CameraBrowser/res/layout/object_list.xml new file mode 100644 index 0000000..30c18bb --- /dev/null +++ b/media/tests/CameraBrowser/res/layout/object_list.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <ImageView android:id="@+id/thumbnail" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:gravity="center_vertical" + android:paddingLeft="6dip" + android:minHeight="?android:attr/listPreferredItemHeight" /> +</LinearLayout> diff --git a/media/tests/CameraBrowser/res/menu/object_menu.xml b/media/tests/CameraBrowser/res/menu/object_menu.xml new file mode 100644 index 0000000..a0865f0 --- /dev/null +++ b/media/tests/CameraBrowser/res/menu/object_menu.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:id="@+id/save" + android:title="@string/save_item" /> + <item android:id="@+id/delete" + android:title="@string/delete_item" /> +</menu> diff --git a/media/tests/CameraBrowser/res/values/strings.xml b/media/tests/CameraBrowser/res/values/strings.xml new file mode 100644 index 0000000..56c5111 --- /dev/null +++ b/media/tests/CameraBrowser/res/values/strings.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <string name="app_label">Camera Browser</string> + + <!-- for object info --> + <string name="name_label">Name: </string> + <string name="size_label">Size: </string> + <string name="thumb_width_label">Thumb Width: </string> + <string name="thumb_height_label">Thumb Height: </string> + <string name="thumb_size_label">Thumb Size: </string> + <string name="width_label">Width: </string> + <string name="height_label">Height: </string> + <string name="depth_label">Depth: </string> + <string name="sequence_label">Sequence: </string> + <string name="created_label">Created: </string> + <string name="modified_label">Modified: </string> + <string name="keywords_label">Keywords: </string> + + <!-- menu items --> + <string name="save_item">Save</string> + <string name="delete_item">Delete</string> + + <!-- toasts --> + <string name="object_saved_message">Object saved</string> + <string name="save_failed_message">Could not save object</string> + <string name="object_deleted_message">Object deleted</string> + <string name="delete_failed_message">Could not delete object</string> + +</resources> diff --git a/media/tests/CameraBrowser/res/values/styles.xml b/media/tests/CameraBrowser/res/values/styles.xml new file mode 100644 index 0000000..c869985 --- /dev/null +++ b/media/tests/CameraBrowser/res/values/styles.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <style name="info_label"> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:textSize">14sp</item> + <item name="android:textStyle">bold</item> + <item name="android:paddingRight">4dip</item> + </style> + + <style name="info_value"> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:textSize">14sp</item> + <item name="android:textStyle">normal</item> + </style> + +</resources> + diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java new file mode 100644 index 0000000..c04873a --- /dev/null +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java @@ -0,0 +1,103 @@ +/* + * 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.app.ListActivity; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.provider.Mtp; +import android.util.Log; +import android.view.View; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; + + /** + * A list view displaying all connected cameras. + */ +public class CameraBrowser extends ListActivity { + + private static final String TAG = "CameraBrowser"; + + private ListAdapter mAdapter; + private ContentResolver mResolver; + private DeviceObserver mDeviceObserver; + private Cursor mCursor; + + private class DeviceObserver extends ContentObserver { + DeviceObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + Log.d(TAG, "DeviceObserver.onChange"); + if (mCursor != null) { + mCursor.requery(); + } + } + } + + private static final String[] DEVICE_COLUMNS = + new String[] { Mtp.Device._ID, Mtp.Device.MANUFACTURER, Mtp.Device.MODEL }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mResolver = getContentResolver(); + mDeviceObserver = new DeviceObserver(new Handler()); + } + + @Override + protected void onResume() { + super.onResume(); + + Cursor c = getContentResolver().query(Mtp.Device.CONTENT_URI, + DEVICE_COLUMNS, null, null, null); + Log.d(TAG, "query returned " + c); + startManagingCursor(c); + mCursor = c; + + // Map Cursor columns to views defined in simple_list_item_2.xml + mAdapter = new SimpleCursorAdapter(this, + android.R.layout.simple_list_item_2, c, + new String[] { Mtp.Device.MANUFACTURER, Mtp.Device.MODEL }, + new int[] { android.R.id.text1, android.R.id.text2 }); + setListAdapter(mAdapter); + + // register for changes to the device list + mResolver.registerContentObserver(Mtp.Device.CONTENT_URI, true, mDeviceObserver); + } + + @Override + protected void onPause() { + super.onPause(); + mResolver.unregisterContentObserver(mDeviceObserver); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + Intent intent = new Intent(this, StorageBrowser.class); + intent.putExtra("device", (int)mAdapter.getItemId(position)); + startActivity(intent); + } +} diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java new file mode 100644 index 0000000..a002028 --- /dev/null +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java @@ -0,0 +1,146 @@ +/* + * 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.app.ListActivity; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Mtp; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.ResourceCursorAdapter; +import android.widget.TextView; + + /** + * A list view displaying all objects within a container (folder or storage unit). + */ +public class ObjectBrowser extends ListActivity { + + private static final String TAG = "ObjectBrowser"; + + private Cursor mCursor; + private ObjectCursorAdapter mAdapter; + private int mDeviceID; + private int mStorageID; + private int mObjectID; + + private static final String[] OBJECT_COLUMNS = + new String[] { Mtp.Object._ID, Mtp.Object.NAME, Mtp.Object.FORMAT, Mtp.Object.THUMB }; + + static final int ID_COLUMN = 0; + static final int NAME_COLUMN = 1; + static final int FORMAT_COLUMN = 2; + static final int THUMB_COLUMN = 3; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected void onResume() { + super.onResume(); + + mDeviceID = getIntent().getIntExtra("device", 0); + mStorageID = getIntent().getIntExtra("storage", 0); + mObjectID = getIntent().getIntExtra("object", 0); + if (mDeviceID != 0 && mStorageID != 0) { + Cursor c; + Uri uri; + if (mObjectID == 0) { + uri = Mtp.Object.getContentUriForStorageChildren(mDeviceID, mStorageID); + } else { + uri = Mtp.Object.getContentUriForObjectChildren(mDeviceID, mObjectID); + } + Log.d(TAG, "query " + uri); + c = getContentResolver().query(uri, OBJECT_COLUMNS, null, null, null); + startManagingCursor(c); + mCursor = c; + + // Map Cursor columns to views defined in simple_list_item_1.xml + mAdapter = new ObjectCursorAdapter(this, c); + setListAdapter(mAdapter); + } + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + int rowID = (int)mAdapter.getItemId(position); + Cursor c = getContentResolver().query( + Mtp.Object.getContentUri(mDeviceID, rowID), + OBJECT_COLUMNS, null, null, null); + Log.d(TAG, "query returned " + c + " count: " + c.getCount()); + long format = 0; + if (c != null && c.getCount() == 1) { + c.moveToFirst(); + long rowId = c.getLong(ID_COLUMN); + String name = c.getString(NAME_COLUMN); + format = c.getLong(FORMAT_COLUMN); + Log.d(TAG, "rowId: " + rowId + " name: " + name + " format: " + format); + } + if (format == Mtp.Object.FORMAT_JFIF) { + Intent intent = new Intent(this, ObjectViewer.class); + intent.putExtra("device", mDeviceID); + intent.putExtra("storage", mStorageID); + intent.putExtra("object",rowID); + startActivity(intent); + } else { + Intent intent = new Intent(this, ObjectBrowser.class); + intent.putExtra("device", mDeviceID); + intent.putExtra("storage", mStorageID); + intent.putExtra("object", rowID); + startActivity(intent); + } + } + + private class ObjectCursorAdapter extends ResourceCursorAdapter { + + public ObjectCursorAdapter(Context context, Cursor c) { + super(context, R.layout.object_list, c); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ImageView thumbView = (ImageView)view.findViewById(R.id.thumbnail); + TextView nameView = (TextView)view.findViewById(R.id.name); + + // get the thumbnail + byte[] thumbnail = cursor.getBlob(THUMB_COLUMN); + if (thumbnail != null) { + Bitmap bitmap = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length); + if (bitmap != null) { + thumbView.setImageBitmap(bitmap); + } + } + + // get the name + String name = cursor.getString(NAME_COLUMN); + if (name == null) { + name = ""; + } + nameView.setText(name); + } + } +} diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java new file mode 100644 index 0000000..aa49cd8 --- /dev/null +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java @@ -0,0 +1,252 @@ +/* + * 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.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.provider.Mtp; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.Calendar; +import java.util.Date; + +/** + * A view to display the properties of an object. + */ +public class ObjectViewer extends Activity { + + private static final String TAG = "ObjectViewer"; + + private int mDeviceID; + private int mStorageID; + private int mObjectID; + + private static final String[] OBJECT_COLUMNS = + new String[] { Mtp.Object._ID, + Mtp.Object.NAME, + Mtp.Object.SIZE, + Mtp.Object.THUMB_WIDTH, + Mtp.Object.THUMB_HEIGHT, + Mtp.Object.THUMB_SIZE, + Mtp.Object.IMAGE_WIDTH, + Mtp.Object.IMAGE_HEIGHT, + Mtp.Object.IMAGE_DEPTH, + Mtp.Object.SEQUENCE_NUMBER, + Mtp.Object.DATE_CREATED, + Mtp.Object.DATE_MODIFIED, + Mtp.Object.KEYWORDS, + Mtp.Object.THUMB, + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.object_info); + } + + @Override + protected void onResume() { + super.onResume(); + + mDeviceID = getIntent().getIntExtra("device", 0); + mStorageID = getIntent().getIntExtra("storage", 0); + mObjectID = getIntent().getIntExtra("object", 0); + + if (mDeviceID != 0 && mObjectID != 0) { + Cursor c = getContentResolver().query( + Mtp.Object.getContentUri(mDeviceID, mObjectID), + OBJECT_COLUMNS, null, null, null); + c.moveToFirst(); + TextView view = (TextView)findViewById(R.id.name); + view.setText(c.getString(1)); + view = (TextView)findViewById(R.id.size); + view.setText(Long.toString(c.getLong(2))); + view = (TextView)findViewById(R.id.thumb_width); + view.setText(Long.toString(c.getLong(3))); + view = (TextView)findViewById(R.id.thumb_height); + view.setText(Long.toString(c.getLong(4))); + view = (TextView)findViewById(R.id.thumb_size); + view.setText(Long.toString(c.getLong(5))); + view = (TextView)findViewById(R.id.width); + view.setText(Long.toString(c.getLong(6))); + view = (TextView)findViewById(R.id.height); + view.setText(Long.toString(c.getLong(7))); + view = (TextView)findViewById(R.id.depth); + view.setText(Long.toString(c.getLong(8))); + view = (TextView)findViewById(R.id.sequence); + view.setText(Long.toString(c.getLong(9))); + view = (TextView)findViewById(R.id.created); + Date date = new Date(c.getLong(10) * 1000); + view.setText(date.toString()); + view = (TextView)findViewById(R.id.modified); + date = new Date(c.getLong(11) * 1000); + view.setText(date.toString()); + view = (TextView)findViewById(R.id.keywords); + view.setText(c.getString(12)); + byte[] thumbnail = c.getBlob(13); + if (thumbnail != null) { + ImageView thumbView = (ImageView)findViewById(R.id.thumbnail); + Bitmap bitmap = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length); + if (bitmap != null) { + thumbView.setImageBitmap(bitmap); + } + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.object_menu, menu); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + MenuItem item = menu.findItem(R.id.save); + item.setEnabled(true); + item = menu.findItem(R.id.delete); + item.setEnabled(true); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.save: + save(); + return true; + case R.id.delete: + delete(); + return true; + } + return false; + } + + private static String getTimestamp() { + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis()); + return String.format("%tY-%tm-%td-%tH-%tM-%tS", c, c, c, c, c, c); + } + + private void save() { + boolean success = false; + Uri uri = Mtp.Object.getContentUri(mDeviceID, mObjectID); + File destFile = null; + ParcelFileDescriptor pfd = null; + FileInputStream fis = null; + FileOutputStream fos = null; + + try { + pfd = getContentResolver().openFileDescriptor(uri, "r"); + Log.d(TAG, "save got pfd " + pfd); + if (pfd != null) { + fis = new FileInputStream(pfd.getFileDescriptor()); + Log.d(TAG, "save got fis " + fis); + File destDir = Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DCIM); + destDir.mkdirs(); + destFile = new File(destDir, "CameraBrowser-" + getTimestamp() + ".jpeg"); + + + Log.d(TAG, "save got destFile " + destFile); + + if (destFile.exists()) { + destFile.delete(); + } + fos = new FileOutputStream(destFile); + + byte[] buffer = new byte[65536]; + int bytesRead; + while ((bytesRead = fis.read(buffer)) >= 0) { + fos.write(buffer, 0, bytesRead); + } + + // temporary workaround until we straighten out permissions in /data/media + // 1015 is AID_SDCARD_RW + FileUtils.setPermissions(destDir.getPath(), 0775, Process.myUid(), 1015); + FileUtils.setPermissions(destFile.getPath(), 0664, Process.myUid(), 1015); + + success = true; + } + } catch (Exception e) { + Log.e(TAG, "Exception in ObjectView.save", e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (Exception e) { + } + } + if (fos != null) { + try { + fos.close(); + } catch (Exception e) { + } + } + if (pfd != null) { + try { + pfd.close(); + } catch (Exception e) { + } + } + } + + if (success) { + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + intent.setData(Uri.fromFile(destFile)); + sendBroadcast(intent); + Toast.makeText(this, R.string.object_saved_message, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, R.string.save_failed_message, Toast.LENGTH_SHORT).show(); + } + } + + private void delete() { + Uri uri = Mtp.Object.getContentUri(mDeviceID, mObjectID); + + Log.d(TAG, "deleting " + uri); + + int result = getContentResolver().delete(uri, null, null); + if (result > 0) { + Toast.makeText(this, R.string.object_deleted_message, Toast.LENGTH_SHORT).show(); + finish(); + } else { + Toast.makeText(this, R.string.delete_failed_message, Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java new file mode 100644 index 0000000..6ddf4e7 --- /dev/null +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java @@ -0,0 +1,76 @@ +/* + * 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.app.ListActivity; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Mtp; +import android.util.Log; +import android.view.View; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; + +/** + * A list view displaying all storage units on a device. + */ +public class StorageBrowser extends ListActivity { + + private static final String TAG = "StorageBrowser"; + + private ListAdapter mAdapter; + private int mDeviceID; + + private static final String[] STORAGE_COLUMNS = + new String[] { Mtp.Storage._ID, Mtp.Storage.DESCRIPTION }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected void onResume() { + super.onResume(); + + mDeviceID = getIntent().getIntExtra("device", 0); + if (mDeviceID != 0) { + Cursor c = getContentResolver().query(Mtp.Storage.getContentUri(mDeviceID), + STORAGE_COLUMNS, null, null, null); + Log.d(TAG, "query returned " + c); + startManagingCursor(c); + + // Map Cursor columns to views defined in simple_list_item_1.xml + mAdapter = new SimpleCursorAdapter(this, + android.R.layout.simple_list_item_1, c, + new String[] { Mtp.Storage.DESCRIPTION }, + new int[] { android.R.id.text1, android.R.id.text2 }); + setListAdapter(mAdapter); + } + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + Intent intent = new Intent(this, ObjectBrowser.class); + intent.putExtra("device", mDeviceID); + intent.putExtra("storage", (int)mAdapter.getItemId(position)); + startActivity(intent); + } +} 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/media/tests/mtp/Android.mk b/media/tests/mtp/Android.mk new file mode 100644 index 0000000..a9074ed --- /dev/null +++ b/media/tests/mtp/Android.mk @@ -0,0 +1,61 @@ +LOCAL_PATH:= $(call my-dir) + +ifneq ($(TARGET_SIMULATOR),true) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + mtp.cpp \ + MtpFile.cpp \ + +LOCAL_C_INCLUDES += \ + frameworks/base/media/mtp \ + +LOCAL_CFLAGS := -DMTP_HOST + +LOCAL_MODULE := mtp + +LOCAL_STATIC_LIBRARIES := libmtp libusbhost libutils libcutils + +include $(BUILD_EXECUTABLE) + +endif + +ifeq ($(HOST_OS),linux) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + mtp.cpp \ + MtpFile.cpp \ + ../../../libs/utils/RefBase.cpp \ + ../../../libs/utils/SharedBuffer.cpp \ + ../../../libs/utils/Threads.cpp \ + ../../../libs/utils/VectorImpl.cpp \ + +LOCAL_C_INCLUDES += \ + frameworks/base/media/mtp \ + +LOCAL_CFLAGS := -DMTP_HOST -g -O0 + +have_readline := $(wildcard /usr/include/readline/readline.h) +have_history := $(wildcard /usr/lib/libhistory*) +ifneq ($(strip $(have_readline)),) +LOCAL_CFLAGS += -DHAVE_READLINE=1 +endif + +LOCAL_LDLIBS += -lpthread +ifneq ($(strip $(have_readline)),) +LOCAL_LDLIBS += -lreadline -lncurses +endif +ifneq ($(strip $(have_history)),) +LOCAL_LDLIBS += -lhistory +endif + +LOCAL_MODULE := mtp + +LOCAL_STATIC_LIBRARIES := libmtp libusbhost libcutils + +include $(BUILD_HOST_EXECUTABLE) + +endif diff --git a/media/tests/mtp/MtpFile.cpp b/media/tests/mtp/MtpFile.cpp new file mode 100644 index 0000000..00d328e --- /dev/null +++ b/media/tests/mtp/MtpFile.cpp @@ -0,0 +1,187 @@ +/* + * 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. + */ + +#include "MtpClient.h" +#include "MtpDevice.h" +#include "MtpDeviceInfo.h" +#include "MtpObjectInfo.h" +#include "MtpStorage.h" +#include "MtpUtils.h" + +#include "MtpFile.h" + +namespace android { + +MtpClient* MtpFile::sClient = NULL; + +MtpFile::MtpFile(MtpDevice* device) + : mDevice(device), + mStorage(0), + mHandle(0) +{ +} + +MtpFile::MtpFile(MtpDevice* device, MtpStorageID storage) + : mDevice(device), + mStorage(storage), + mHandle(0) +{ +} + +MtpFile::MtpFile(MtpDevice* device, MtpStorageID storage, MtpObjectHandle handle) + : mDevice(device), + mStorage(storage), + mHandle(handle) +{ +} + +MtpFile::MtpFile(MtpFile* file) + : mDevice(file->mDevice), + mStorage(file->mStorage), + mHandle(file->mHandle) +{ +} + +MtpFile::~MtpFile() { +} + +void MtpFile::print() { + if (mHandle) { + + } else if (mStorage) { + printf("%x\n", mStorage); + } else { + int id = mDevice->getID(); + MtpDeviceInfo* info = mDevice->getDeviceInfo(); + if (info) + printf("%d\t%s %s %s\n", id, info->mManufacturer, info->mModel, info->mSerial); + else + printf("%d\t(no device info available)\n", id); + delete info; + } +} + +MtpObjectInfo* MtpFile::getObjectInfo() { + return mDevice->getObjectInfo(mHandle); +} + +void MtpFile::list() { + if (mStorage) { + MtpObjectHandleList* handles = mDevice->getObjectHandles(mStorage, 0, + (mHandle ? mHandle : -1)); + if (handles) { + for (int i = 0; i < handles->size(); i++) { + MtpObjectHandle handle = (*handles)[i]; + MtpObjectInfo* info = mDevice->getObjectInfo(handle); + if (info) { + char modified[100]; + struct tm tm; + + gmtime_r(&info->mDateModified, &tm); + strftime(modified, sizeof(modified), "%a %b %e %H:%M:%S GMT %Y", &tm); + printf("%s Handle: %d Format: %04X Size: %d Modified: %s\n", + info->mName, handle, info->mFormat, info->mCompressedSize, modified); + delete info; + } + } + delete handles; + } + } else { + // list storage units for device + MtpStorageIDList* storageList = mDevice->getStorageIDs(); + for (int i = 0; i < storageList->size(); i++) { + MtpStorageID storageID = (*storageList)[i]; + printf("%x\n", storageID); + } + } +} + +void MtpFile::init(MtpClient* client) { + sClient = client; +} + +MtpFile* MtpFile::parsePath(MtpFile* base, char* path) { + MtpDevice* device = NULL; + MtpStorageID storage = 0; + MtpObjectHandle handle = 0; + + if (path[0] != '/' && base) { + device = base->mDevice; + storage = base->mStorage; + handle = base->mHandle; + } + + // parse an absolute path + if (path[0] == '/') + path++; + char* tok = strtok(path, "/"); + while (tok) { + if (storage) { + // find child of current handle + MtpObjectHandleList* handles = device->getObjectHandles(storage, 0, + (handle ? handle : -1)); + MtpObjectHandle childHandle = 0; + + if (handles) { + for (int i = 0; i < handles->size() && !childHandle; i++) { + MtpObjectHandle handle = (*handles)[i]; + MtpObjectInfo* info = device->getObjectInfo(handle); + if (info && !strcmp(tok, info->mName)) + childHandle = handle; + delete info; + } + delete handles; + } + if (childHandle) + handle = childHandle; + else + return NULL; + } else if (device) { + unsigned int id; + // find storage for the device + if (sscanf(tok, "%x", &id) == 1) { + MtpStorageIDList* storageList = device->getStorageIDs(); + bool found = false; + for (int i = 0; i < storageList->size(); i++) { + if ((*storageList)[i] == id) { + found = true; + break; + } + } + if (found) + storage = id; + else + return NULL; + } + } else { + // find device + unsigned int id; + if (sscanf(tok, "%d", &id) == 1) + device = sClient->getDevice(id); + if (!device) + return NULL; + } + + tok = strtok(NULL, "/"); + } + + if (device) + return new MtpFile(device, storage, handle); + else + return NULL; +} + +} diff --git a/media/tests/mtp/MtpFile.h b/media/tests/mtp/MtpFile.h new file mode 100644 index 0000000..ab8762b --- /dev/null +++ b/media/tests/mtp/MtpFile.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef _MTP_FILE_H +#define _MTP_FILE_H + +#include "MtpTypes.h" + +namespace android { + +class MtpClient; +class MtpDevice; +class MtpObjectInfo; + +// File-like abstraction for the interactive shell. +// This can be used to represent an MTP device, storage unit or object +// (either file or association). +class MtpFile { +private: + MtpDevice* mDevice; + MtpStorageID mStorage; + MtpObjectHandle mHandle; + static MtpClient* sClient; + +public: + MtpFile(MtpDevice* device); + MtpFile(MtpDevice* device, MtpStorageID storage); + MtpFile(MtpDevice* device, MtpStorageID storage, MtpObjectHandle handle); + MtpFile(MtpFile* file); + virtual ~MtpFile(); + + MtpObjectInfo* getObjectInfo(); + void print(); + void list(); + + inline MtpDevice* getDevice() const { return mDevice; } + + static void init(MtpClient* client); + static MtpFile* parsePath(MtpFile* base, char* path); +}; + +} + +#endif // _MTP_DIRECTORY_H diff --git a/media/tests/mtp/mtp.cpp b/media/tests/mtp/mtp.cpp new file mode 100644 index 0000000..2c5e23b --- /dev/null +++ b/media/tests/mtp/mtp.cpp @@ -0,0 +1,370 @@ +/* + * 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. + */ + +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#if HAVE_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif + +#include "MtpClient.h" +#include "MtpDevice.h" +#include "MtpObjectInfo.h" + +#include "MtpFile.h" + +#define PROMPT "mtp> " + +using namespace android; + +static MtpClient* sClient = NULL; + +// current working directory information for interactive shell +static MtpFile* sCurrentDirectory = NULL; + +static MtpFile* parse_path(char* path) { + return MtpFile::parsePath(sCurrentDirectory, path); +} + +class MyClient : public MtpClient { +private: + virtual void deviceAdded(MtpDevice *device) { + } + + virtual void deviceRemoved(MtpDevice *device) { + } + +public: +}; + +static void init() { + sClient = new MyClient; + sClient->start(); + MtpFile::init(sClient); +} + +static int set_cwd(int argc, char* argv[]) { + if (argc != 1) { + fprintf(stderr, "cd should have one argument\n"); + return -1; + } + if (!strcmp(argv[0], "/")) { + delete sCurrentDirectory; + sCurrentDirectory = NULL; + } + else { + MtpFile* file = parse_path(argv[0]); + if (file) { + delete sCurrentDirectory; + sCurrentDirectory = file; + } else { + fprintf(stderr, "could not find %s\n", argv[0]); + return -1; + } + } + return 0; +} + +static void list_devices() { + // TODO - need to make sure the list will not change while iterating + MtpDeviceList& devices = sClient->getDeviceList(); + for (int i = 0; i < devices.size(); i++) { + MtpDevice* device = devices[i]; + MtpFile* file = new MtpFile(device); + file->print(); + delete file; + } +} + +static int list(int argc, char* argv[]) { + if (argc == 0) { + // list cwd + if (sCurrentDirectory) { + sCurrentDirectory->list(); + } else { + list_devices(); + } + } + + for (int i = 0; i < argc; i++) { + char* path = argv[i]; + if (!strcmp(path, "/")) { + list_devices(); + } else { + MtpFile* file = parse_path(path); + if (!file) { + fprintf(stderr, "could not find %s\n", path); + return -1; + } + file->list(); + } + } + + return 0; +} + +static int get_file(int argc, char* argv[]) { + int ret = -1; + int srcFD = -1; + int destFD = -1; + MtpFile* srcFile = NULL; + MtpObjectInfo* info = NULL; + char* dest; + + if (argc < 1) { + fprintf(stderr, "not enough arguments\n"); + return -1; + } else if (argc > 2) { + fprintf(stderr, "too many arguments\n"); + return -1; + } + + // find source object + char* src = argv[0]; + srcFile = parse_path(src); + if (!srcFile) { + fprintf(stderr, "could not find %s\n", src); + return -1; + } + info = srcFile->getObjectInfo(); + if (!info) { + fprintf(stderr, "could not find object info for %s\n", src); + goto fail; + } + if (info->mFormat == MTP_FORMAT_ASSOCIATION) { + fprintf(stderr, "copying directories not implemented yet\n"); + goto fail; + } + + dest = (argc > 1 ? argv[1] : info->mName); + destFD = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (destFD < 0) { + fprintf(stderr, "could not create %s\n", dest); + goto fail; + } + srcFD = srcFile->getDevice()->readObject(info->mHandle, info->mCompressedSize); + if (srcFD < 0) + goto fail; + + char buffer[65536]; + while (1) { + int count = read(srcFD, buffer, sizeof(buffer)); + if (count <= 0) + break; + write(destFD, buffer, count); + } + // FIXME - error checking and reporting + ret = 0; + +fail: + delete srcFile; + delete info; + if (srcFD >= 0) + close(srcFD); + if (destFD >= 0) + close(destFD); + return ret; +} + +static int put_file(int argc, char* argv[]) { + int ret = -1; + int srcFD = -1; + MtpFile* destFile = NULL; + MtpObjectInfo* srcInfo = NULL; + MtpObjectInfo* destInfo = NULL; + MtpObjectHandle handle; + struct stat statbuf; + const char* lastSlash; + + if (argc < 1) { + fprintf(stderr, "not enough arguments\n"); + return -1; + } else if (argc > 2) { + fprintf(stderr, "too many arguments\n"); + return -1; + } + const char* src = argv[0]; + srcFD = open(src, O_RDONLY); + if (srcFD < 0) { + fprintf(stderr, "could not open %s\n", src); + goto fail; + } + if (argc == 2) { + char* dest = argv[1]; + destFile = parse_path(dest); + if (!destFile) { + fprintf(stderr, "could not find %s\n", dest); + goto fail; + } + } else { + if (!sCurrentDirectory) { + fprintf(stderr, "current working directory not set\n"); + goto fail; + } + destFile = new MtpFile(sCurrentDirectory); + } + + destInfo = destFile->getObjectInfo(); + if (!destInfo) { + fprintf(stderr, "could not find object info destination directory\n"); + goto fail; + } + if (destInfo->mFormat != MTP_FORMAT_ASSOCIATION) { + fprintf(stderr, "destination not a directory\n"); + goto fail; + } + + if (fstat(srcFD, &statbuf)) + goto fail; + + srcInfo = new MtpObjectInfo(0); + srcInfo->mStorageID = destInfo->mStorageID; + srcInfo->mFormat = MTP_FORMAT_EXIF_JPEG; // FIXME + srcInfo->mCompressedSize = statbuf.st_size; + srcInfo->mParent = destInfo->mHandle; + lastSlash = strrchr(src, '/'); + srcInfo->mName = strdup(lastSlash ? lastSlash + 1 : src); + srcInfo->mDateModified = statbuf.st_mtime; + handle = destFile->getDevice()->sendObjectInfo(srcInfo); + if (handle <= 0) { + printf("sendObjectInfo returned %04X\n", handle); + goto fail; + } + if (destFile->getDevice()->sendObject(srcInfo, srcFD)) + ret = 0; + +fail: + delete destFile; + delete srcInfo; + delete destInfo; + if (srcFD >= 0) + close(srcFD); + printf("returning %d\n", ret); + return ret; +} + +typedef int (* command_func)(int argc, char* argv[]); + +struct command_table_entry { + const char* name; + command_func func; +}; + +const command_table_entry command_list[] = { + { "cd", set_cwd }, + { "ls", list }, + { "get", get_file }, + { "put", put_file }, + { NULL, NULL }, +}; + + +static int do_command(int argc, char* argv[]) { + const command_table_entry* command = command_list; + const char* name = *argv++; + argc--; + + while (command->name) { + if (!strcmp(command->name, name)) + return command->func(argc, argv); + else + command++; + } + fprintf(stderr, "unknown command %s\n", name); + return -1; +} + +static int shell() { + int argc; + int result = 0; +#define MAX_ARGS 100 + char* argv[MAX_ARGS]; + +#if HAVE_READLINE + using_history(); +#endif + + while (1) { +#if HAVE_READLINE + char* line = readline(PROMPT); + if (!line) { + printf("\n"); + exit(0); + } +#else + char buffer[1000]; + printf("%s", PROMPT); + char* line = NULL; + size_t length = 0; + + buffer[0] = 0; + fgets(buffer, sizeof(buffer), stdin); + int count = strlen(buffer); + if (count > 0 && buffer[0] == EOF) { + printf("\n"); + exit(0); + } + if (count > 0 && line[count - 1] == '\n') + line[count - 1] == 0; +#endif + char* tok = strtok(line, " \t\n\r"); + if (!tok) + continue; + if (!strcmp(tok, "quit") || !strcmp(tok, "exit")) { + exit(0); + } +#if HAVE_READLINE + add_history(line); +#endif + argc = 0; + while (tok) { + if (argc + 1 == MAX_ARGS) { + fprintf(stderr, "too many arguments\n"); + result = -1; + goto bottom_of_loop; + } + + argv[argc++] = strdup(tok); + tok = strtok(NULL, " \t\n\r"); + } + + result = do_command(argc, argv); + +bottom_of_loop: + for (int i = 0; i < argc; i++) + free(argv[i]); + free(line); + } + + return result; +} + +int main(int argc, char* argv[]) { + init(); + + if (argc == 1) + return shell(); + else + return do_command(argc - 1, argv + 1); +} diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp index b3cc8b6..53308be 100644 --- a/media/tests/players/invoke_mock_media_player.cpp +++ b/media/tests/players/invoke_mock_media_player.cpp @@ -26,6 +26,7 @@ using android::INVALID_OPERATION; using android::ISurface; +using android::Surface; using android::MediaPlayerBase; using android::OK; using android::Parcel; @@ -67,7 +68,8 @@ class Player: public MediaPlayerBase } virtual status_t setDataSource(int fd, int64_t offset, int64_t length) {return OK;} - virtual status_t setVideoSurface(const sp<ISurface>& surface) {return OK;} + virtual status_t setVideoISurface(const sp<ISurface>& surface) {return OK;} + virtual status_t setVideoSurface(const sp<Surface>& surface) {return OK;} virtual status_t prepare() {return OK;} virtual status_t prepareAsync() {return OK;} virtual status_t start() {return OK;} |