am 3e132a1a: Fix sdk source prop to include proper layoutlib api level.
* commit '3e132a1a2602019ccccc4d965cb7d3aded1c988d':
Fix sdk source prop to include proper layoutlib api level.
diff --git a/apps/Fallback/res/values-af/strings.xml b/apps/Fallback/res/values-af/strings.xml
deleted file mode 100644
index 8cf16a7..0000000
--- a/apps/Fallback/res/values-af/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Terugval"</string>
- <string name="title" msgid="8156274565006125136">"Nie-ondersteunde handeling"</string>
- <string name="error" msgid="6539615832923362301">"Hierdie handeling word tans nie ondersteun nie."</string>
-</resources>
diff --git a/apps/Fallback/res/values-am/strings.xml b/apps/Fallback/res/values-am/strings.xml
deleted file mode 100644
index 0c89122..0000000
--- a/apps/Fallback/res/values-am/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
- <string name="title" msgid="8156274565006125136">"የማይደገፍ ድርጊት"</string>
- <string name="error" msgid="6539615832923362301">"ያድርጊት በአሁኑ ጊዜ የማይደገፍ ነው።"</string>
-</resources>
diff --git a/apps/Fallback/res/values-iw/strings.xml b/apps/Fallback/res/values-iw/strings.xml
index cbf35ef..671919b 100644
--- a/apps/Fallback/res/values-iw/strings.xml
+++ b/apps/Fallback/res/values-iw/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"חלופי"</string>
+ <string name="appTitle" msgid="161410001913116606">"החזרה"</string>
<string name="title" msgid="8156274565006125136">"פעולה לא נתמכת"</string>
<string name="error" msgid="6539615832923362301">"הפעולה אינה נתמכת בשלב זה."</string>
</resources>
diff --git a/apps/Fallback/res/values-ms/strings.xml b/apps/Fallback/res/values-ms/strings.xml
deleted file mode 100644
index 930fe79..0000000
--- a/apps/Fallback/res/values-ms/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Jatuh balik"</string>
- <string name="title" msgid="8156274565006125136">"Tindakan tidak disokong"</string>
- <string name="error" msgid="6539615832923362301">"Tindakan tidak disokong pada masa ini."</string>
-</resources>
diff --git a/apps/Fallback/res/values-sw/strings.xml b/apps/Fallback/res/values-sw/strings.xml
deleted file mode 100644
index f322c20..0000000
--- a/apps/Fallback/res/values-sw/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Rudi nyuma"</string>
- <string name="title" msgid="8156274565006125136">"Kitendo kinachohimiliwa"</string>
- <string name="error" msgid="6539615832923362301">"Kitendo hakijahimiliwa ipasavyo"</string>
-</resources>
diff --git a/apps/Fallback/res/values-zu/strings.xml b/apps/Fallback/res/values-zu/strings.xml
deleted file mode 100644
index 2c85d28..0000000
--- a/apps/Fallback/res/values-zu/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Buyela emuva"</string>
- <string name="title" msgid="8156274565006125136">"Isenzo esingasekelwe"</string>
- <string name="error" msgid="6539615832923362301">"Leso senzo okwamanje asisekelwe."</string>
-</resources>
diff --git a/samples/ApiDemos/res/layout/layout_animations_by_default.xml b/samples/ApiDemos/res/layout/layout_animations_by_default.xml
index a5062bb..6236088 100644
--- a/samples/ApiDemos/res/layout/layout_animations_by_default.xml
+++ b/samples/ApiDemos/res/layout/layout_animations_by_default.xml
@@ -24,18 +24,11 @@
android:text="Add Button"
android:id="@+id/addNewButton"
/>
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/horizontalContainer"
- android:animateLayoutChanges="true"
- />
- <LinearLayout
- android:orientation="vertical"
+ <GridLayout
+ android:columnCount="4"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:id="@+id/verticalContainer"
+ android:layout_height="wrap_content"
+ android:id="@+id/gridContainer"
android:animateLayoutChanges="true"
/>
</LinearLayout>
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java
index 67b9b51..8898b55 100644
--- a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java
@@ -21,11 +21,11 @@
import com.example.android.apis.R;
import android.view.View;
-import android.view.ViewGroup;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
+import android.widget.GridLayout;
/**
* This application demonstrates how to use the animateLayoutChanges tag in XML to automate
@@ -35,36 +35,25 @@
private int numButtons = 1;
- /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_animations_by_default);
- final ViewGroup horizontalContainer = (ViewGroup) findViewById(R.id.horizontalContainer);
- final ViewGroup verticalContainer = (ViewGroup) findViewById(R.id.verticalContainer);
+ final GridLayout gridContainer = (GridLayout) findViewById(R.id.gridContainer);
Button addButton = (Button) findViewById(R.id.addNewButton);
addButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button newButton = new Button(LayoutAnimationsByDefault.this);
- newButton.setText("Click To Remove " + (numButtons++));
+ newButton.setText(String.valueOf(numButtons++));
newButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- horizontalContainer.removeView(v);
+ gridContainer.removeView(v);
}
});
- horizontalContainer.addView(newButton, Math.min(1, horizontalContainer.getChildCount()));
-
- newButton = new Button(LayoutAnimationsByDefault.this);
- newButton.setText("Click To Remove " + (numButtons++));
- newButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- verticalContainer.removeView(v);
- }
- });
- verticalContainer.addView(newButton, Math.min(1, verticalContainer.getChildCount()));
+ gridContainer.addView(newButton, Math.min(1, gridContainer.getChildCount()));
}
});
}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java b/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
index b98a5b5..b0a1f96 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
@@ -84,7 +84,8 @@
private final void initLabelView() {
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
- mTextPaint.setTextSize(16);
+ // Must manually scale the desired text size to match screen density
+ mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
mTextPaint.setColor(0xFF000000);
setPadding(3, 3, 3, 3);
}
@@ -104,6 +105,7 @@
* @param size Font size
*/
public void setTextSize(int size) {
+ // This text size has been pre-scaled by the getDimensionPixelOffset method
mTextPaint.setTextSize(size);
requestLayout();
invalidate();
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java
index 3ee63e5..464b601 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java
@@ -99,9 +99,8 @@
}
private class OverscanState implements State {
public void apply() {
- display("FULLSCREEN + LOW_PROFILE + HIDE_NAVIGATION");
- mImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+ display("FULLSCREEN + HIDE_NAVIGATION");
+ mImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
public State next() {
return new NormalState();
diff --git a/samples/HoneycombGallery/AndroidManifest.xml b/samples/HoneycombGallery/AndroidManifest.xml
index 704a1c6..2a99856 100644
--- a/samples/HoneycombGallery/AndroidManifest.xml
+++ b/samples/HoneycombGallery/AndroidManifest.xml
@@ -16,9 +16,9 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.hcgallery" android:versionCode="2"
- android:versionName="1.2">
+ android:versionName="1.5">
- <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="13" />
+ <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="14" />
<!-- Declares that the app supports devices w/o touch, such as a mouse-driven device
or a device that provides only a d-pad for navigation -->
diff --git a/samples/HoneycombGallery/res/values-port/dimens.xml b/samples/HoneycombGallery/res/values-large-port/dimens.xml
similarity index 100%
rename from samples/HoneycombGallery/res/values-port/dimens.xml
rename to samples/HoneycombGallery/res/values-large-port/dimens.xml
diff --git a/samples/SampleSyncAdapter/AndroidManifest.xml b/samples/SampleSyncAdapter/AndroidManifest.xml
index 25e9e99..285abfb 100644
--- a/samples/SampleSyncAdapter/AndroidManifest.xml
+++ b/samples/SampleSyncAdapter/AndroidManifest.xml
@@ -46,7 +46,7 @@
<uses-permission
android:name="android.permission.WRITE_SYNC_SETTINGS" />
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="11"/>
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14"/>
<application
android:icon="@drawable/icon"
@@ -100,27 +100,8 @@
</activity>
<activity
- android:name=".editor.ContactEditorActivity"
- android:theme="@style/ContactEditTheme"
- android:windowSoftInputMode="adjustResize">
- <intent-filter>
- <action
- android:name="android.intent.action.INSERT" />
- <data
- android:mimeType="vnd.android.cursor.item/contact" />
- </intent-filter>
-
- <!--
- Note that the editor gets a raw contact URI, but is expected to call
- setResult with the corresponding aggregate contact URI, not raw contact
- URI.
- -->
- <intent-filter>
- <action
- android:name="android.intent.action.EDIT" />
- <data
- android:mimeType="vnd.android.cursor.item/raw_contact" />
- </intent-filter>
+ android:name=".activites.InviteContactActivity"
+ android:theme="@android:style/Theme.Dialog">
<!--
We use the INVITE intent to add a raw contact to an existing contact.
It always comes with a lookup URI.
@@ -132,5 +113,50 @@
android:mimeType="vnd.android.cursor.item/contact" />
</intent-filter>
</activity>
+
+ <activity
+ android:name=".activities.ViewGroupActivity"
+ android:theme="@android:style/Theme.Dialog">
+ <!--
+ We use the VIEW intent to view a group in our app.
+ It always comes with a lookup URI.
+ -->
+ <intent-filter>
+ <action
+ android:name="android.intent.action.VIEW" />
+ <data
+ android:mimeType="vnd.android.cursor.item/group" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".activities.ViewStreamItemActivity"
+ android:theme="@android:style/Theme.Dialog">
+ <!--
+ We use the VIEW intent to view a stream item in our app.
+ It always comes with a lookup URI.
+ -->
+ <intent-filter>
+ <action
+ android:name="android.intent.action.VIEW" />
+ <data
+ android:mimeType="vnd.android.cursor.item/stream_item" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".activities.ViewStreamItemPhotoActivity"
+ android:theme="@android:style/Theme.Dialog">
+ <!--
+ We use the VIEW intent to view a stream item photo in our app.
+ It always comes with a lookup URI.
+ -->
+ <intent-filter>
+ <action
+ android:name="android.intent.action.VIEW" />
+ <data
+ android:mimeType="vnd.android.cursor.item/stream_item_photo" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/samples/SampleSyncAdapter/res/drawable/border.xml b/samples/SampleSyncAdapter/res/drawable/border.xml
deleted file mode 100644
index ab71f2c..0000000
--- a/samples/SampleSyncAdapter/res/drawable/border.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/EditPanelBackgroundColor" />
- <stroke android:width="2dip" android:color="@color/EditPanelBorderColor" />
- <padding android:left="5dip" android:top="5dip" android:right="5dip" android:bottom="5dip" />
-</shape>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png b/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png
deleted file mode 100644
index 3468bbd..0000000
--- a/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png
+++ /dev/null
Binary files differ
diff --git a/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml b/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml
deleted file mode 100644
index 3b7d97b..0000000
--- a/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_horizontal">
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="600dip"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:background="@drawable/border">
- <include layout="@layout/editor_header" />
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:paddingTop="20dip"
- android:paddingRight="20dip"
- android:paddingBottom="20dip"
- android:paddingLeft="20dip"
- android:layout_weight="1">
- <include layout="@layout/editor_fields" />
- </ScrollView>
- </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml b/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml
deleted file mode 100644
index 648e6f9..0000000
--- a/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?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.
--->
-
-
-<!-- Account info header -->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="64dip"
- android:layout_width="match_parent"
- android:background="?android:attr/selectableItemBackground">
-
- <ImageView
- android:id="@+id/header_account_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="7dip"
- android:layout_marginRight="7dip"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:src="@drawable/icon" />
-
- <TextView
- android:id="@+id/header_account_type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@+id/header_account_icon"
- android:layout_alignTop="@id/header_account_icon"
- android:layout_marginTop="-4dip"
- android:textSize="24sp"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true"
- android:text="@string/header_account_type" />
-
- <TextView
- android:id="@+id/header_account_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@+id/header_account_icon"
- android:layout_alignBottom="@+id/header_account_icon"
- android:layout_marginBottom="2dip"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true" />
-
-</RelativeLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/editor_fields.xml b/samples/SampleSyncAdapter/res/layout/editor_fields.xml
deleted file mode 100644
index 31d0128..0000000
--- a/samples/SampleSyncAdapter/res/layout/editor_fields.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?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.
- */
--->
-
-<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:stretchColumns="2">
-
- <TableRow>
- <TextView
- android:layout_column="1"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_name"
- android:padding="3dip" />
- <EditText
- android:layout_column="2"
- android:id="@+id/editor_name"
- android:singleLine="true"
- android:inputType="textPersonName"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minWidth="250dip"
- android:scrollHorizontally="true"
- android:capitalize="none"
- android:textSize="@dimen/contact_name_text_size"
- android:gravity="fill_horizontal"
- android:autoText="false" />
- </TableRow>
- <TableRow>
- <TextView
- android:layout_column="1"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_phone_home"
- android:padding="3dip" />
- <EditText
- android:id="@+id/editor_phone_home"
- android:singleLine="true"
- android:inputType="phone"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minWidth="250dip"
- android:scrollHorizontally="true"
- android:capitalize="none"
- android:gravity="fill_horizontal"
- android:autoText="false" />
- </TableRow>
- <TableRow>
- <TextView
- android:layout_column="1"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_phone_mobile"
- android:padding="3dip" />
- <EditText
- android:id="@+id/editor_phone_mobile"
- android:singleLine="true"
- android:inputType="phone"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minWidth="250dip"
- android:scrollHorizontally="true"
- android:capitalize="none"
- android:gravity="fill_horizontal"
- android:autoText="false" />
- </TableRow>
- <TableRow>
- <TextView
- android:layout_column="1"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_phone_work"
- android:padding="3dip" />
- <EditText
- android:id="@+id/editor_phone_work"
- android:singleLine="true"
- android:phoneNumber="true"
- android:autoText="true"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minWidth="250dip"
- android:scrollHorizontally="true"
- android:capitalize="none"
- android:gravity="fill_horizontal" />
- </TableRow>
- <TableRow>
- <TextView
- android:layout_column="1"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_email"
- android:padding="3dip" />
- <EditText
- android:id="@+id/editor_email"
- android:singleLine="true"
- android:inputType="textEmailAddress"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minWidth="250dip"
- android:scrollHorizontally="true"
- android:capitalize="none"
- android:gravity="fill_horizontal"
- android:autoText="false" />
- </TableRow>
-</TableLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/editor.xml b/samples/SampleSyncAdapter/res/layout/invite_contact_activity.xml
similarity index 61%
rename from samples/SampleSyncAdapter/res/layout/editor.xml
rename to samples/SampleSyncAdapter/res/layout/invite_contact_activity.xml
index a0c36d2..1e09d5b 100644
--- a/samples/SampleSyncAdapter/res/layout/editor.xml
+++ b/samples/SampleSyncAdapter/res/layout/invite_contact_activity.xml
@@ -18,19 +18,15 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:paddingTop="20dip"
- android:paddingRight="20dip"
- android:paddingBottom="20dip"
- android:paddingLeft="20dip"
- android:layout_weight="1">
- <include layout="@layout/editor_fields" />
- </ScrollView>
-
-</LinearLayout>
\ No newline at end of file
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:text="@string/invite_contact_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/invite_contact_uri"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/login_activity.xml b/samples/SampleSyncAdapter/res/layout/login_activity.xml
index 7408ffe..6c93f90 100644
--- a/samples/SampleSyncAdapter/res/layout/login_activity.xml
+++ b/samples/SampleSyncAdapter/res/layout/login_activity.xml
@@ -55,7 +55,8 @@
android:scrollHorizontally="true"
android:capitalize="none"
android:autoText="false"
- android:inputType="textEmailAddress" />
+ android:inputType="textEmailAddress"
+ android:text="user" />
<TextView
android:id="@+id/username_fixed"
android:textAppearance="?android:attr/textAppearanceSmall"
@@ -81,7 +82,8 @@
android:capitalize="none"
android:autoText="false"
android:password="true"
- android:inputType="textPassword" />
+ android:inputType="textPassword"
+ android:text="test" />
<TextView
android:id="@+id/message_bottom"
android:textAppearance="?android:attr/textAppearanceSmall"
diff --git a/samples/SampleSyncAdapter/res/layout/view_group_activity.xml b/samples/SampleSyncAdapter/res/layout/view_group_activity.xml
new file mode 100644
index 0000000..45212d9
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/view_group_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * 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.
+ */
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:text="@string/view_group_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/view_group_uri"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
new file mode 100644
index 0000000..a04d07f
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * 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.
+ */
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:text="@string/view_stream_item_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/view_stream_item_uri"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
new file mode 100644
index 0000000..ddc09d0
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * 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.
+ */
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:text="@string/view_stream_item_photo_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/view_stream_item_photo_uri"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/menu/edit.xml b/samples/SampleSyncAdapter/res/menu/edit.xml
deleted file mode 100644
index 1227584..0000000
--- a/samples/SampleSyncAdapter/res/menu/edit.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:id="@+id/menu_done"
- android:alphabeticShortcut="\n"
- android:icon="@drawable/done_menu_icon"
- android:title="@string/menu_done"
- android:showAsAction="always|withText" />
-
- <item
- android:id="@+id/menu_cancel"
- android:alphabeticShortcut="q"
- android:title="@string/menu_cancel"
- android:showAsAction="always|withText" />
-</menu>
diff --git a/samples/SampleSyncAdapter/res/values/strings.xml b/samples/SampleSyncAdapter/res/values/strings.xml
index 7ac95f5..22fe14e 100644
--- a/samples/SampleSyncAdapter/res/values/strings.xml
+++ b/samples/SampleSyncAdapter/res/values/strings.xml
@@ -109,4 +109,34 @@
<!-- The label of the button to add contact to this contact provider -->
<string name="invite_action_label">Add to Sample SyncAdaper</string>
+ <!-- The description for the invite contact flow -->
+ <string name="invite_contact_description">Congratulations! The user wants to add the contact
+ to the amazing Sample SyncAdapter social network. If this was a real app, it should now
+ make best efforts to add the contact to this network. This would probably involve
+ looking up the person on the network, inviting if he is not there already and syncing
+ the new contact down.
+
+ Ideally, when the user gets back to the People app, the new contact should already
+ be there, enriching the original contact.
+
+ This is the information we got to lookup the contact:</string>
+
+ <!-- The label of the button to view a group -->
+ <string name="view_group_action_label">Show sample group details</string>
+
+ <!-- The description for the view group button -->
+ <string name="view_group_description">This would now show the details of the group.
+
+ This is the group uri:</string>
+
+ <!-- The description for the view stream item -->
+ <string name="view_stream_item_description">This would now show the details of the stream item.
+
+ This is the uri of the stream item:</string>
+
+ <!-- The description for the view stream item photo -->
+ <string name="view_stream_item_photo_description">This would now show the details of the stream item photo.
+
+ This is the uri of the photo:</string>
+
</resources>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/SampleSyncAdapter/res/values/styles.xml
deleted file mode 100644
index 074613e..0000000
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <!--
- These styles will only be used in Honeycomb and later because
- Android doesn't support third-party contact editing in pre-
- Honeycomb versions.
- -->
- <color name="EditPanelBackgroundColor">#ffffff</color>
- <color name="EditPanelBorderColor">#cccccc</color>
- <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
- </style>
-</resources>
diff --git a/samples/SampleSyncAdapter/res/xml-v11/contacts.xml b/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
index 62dfa80..48cf503 100644
--- a/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
@@ -19,8 +19,6 @@
<ContactsAccountType
xmlns:android="http://schemas.android.com/apk/res/android"
- editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
- createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
>
<ContactsDataKind
diff --git a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
index b900c72..48e079a 100644
--- a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
@@ -17,18 +17,15 @@
*/
-->
-<!-- This sample doesn't currently support groups or stream items. viewGroupActivity and
- viewStreamItemActivity and viewStreamItemPhotoActivity or just here for reference -->
<ContactsAccountType
xmlns:android="http://schemas.android.com/apk/res/android"
- editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
- createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
- inviteContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
+ inviteContactActivity="com.example.android.samplesync.activities.InviteContactActivity"
inviteContactActionLabel="@string/invite_action_label"
viewContactNotifyService="com.example.android.samplesync.notifier.NotifierService"
- viewGroupActivity="com.example.android.samplesync.viewer.ViewGroupActivity"
- viewStreamItemActivity="com.example.android.samplesync.viewer.ViewStreamItemActivity"
- viewStreamItemPhotoActivity="com.example.android.samplesync.viewer.ViewStreamItemPhotoActivity"
+ viewGroupActivity="com.example.android.samplesync.activities.ViewGroupActivity"
+ viewGroupActionLabel="@string/view_group_action_label"
+ viewStreamItemActivity="com.example.android.samplesync.activities.ViewStreamItemActivity"
+ viewStreamItemPhotoActivity="com.example.android.samplesync.activities.ViewStreamItemPhotoActivity"
>
<ContactsDataKind
diff --git a/samples/SampleSyncAdapter/res/xml/contacts.xml b/samples/SampleSyncAdapter/res/xml/contacts.xml
index b46257d..06ecf6a 100644
--- a/samples/SampleSyncAdapter/res/xml/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml/contacts.xml
@@ -19,8 +19,6 @@
<ContactsSource
xmlns:android="http://schemas.android.com/apk/res/android"
- editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
- createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
>
<ContactsDataKind
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/InviteContactActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/InviteContactActivity.java
new file mode 100644
index 0000000..1923fc2
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/InviteContactActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to handle the invite-intent. In a real app, this would look up the user on the network
+ * and either connect ("add as friend", "follow") or invite them to the network
+ */
+public class InviteContactActivity extends Activity {
+ private static final String TAG = "InviteContactActivity";
+
+ private TextView mUriTextView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.invite_contact_activity);
+
+ mUriTextView = (TextView) findViewById(R.id.invite_contact_uri);
+ mUriTextView.setText(getIntent().getDataString());
+ }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewGroupActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewGroupActivity.java
new file mode 100644
index 0000000..1b32784
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewGroupActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to handle the view-group action. In a real app, this would show a rich view of the
+ * group, like members, updates etc.
+ */
+public class ViewGroupActivity extends Activity {
+ private static final String TAG = "ViewGroupActivity";
+
+ private TextView mUriTextView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_group_activity);
+
+ mUriTextView = (TextView) findViewById(R.id.view_group_uri);
+ mUriTextView.setText(getIntent().getDataString());
+ }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
new file mode 100644
index 0000000..6d54f31
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to handle view a stream-item. In a real app, this would show a rich view of the
+ * item.
+ */
+public class ViewStreamItemActivity extends Activity {
+ private static final String TAG = "ViewStreamItemActivity";
+
+ private TextView mUriTextView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_stream_item_activity);
+
+ mUriTextView = (TextView) findViewById(R.id.view_stream_item_uri);
+ mUriTextView.setText(getIntent().getDataString());
+ }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
new file mode 100644
index 0000000..962bc70
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to view a stream-item-photo. In a real app, this would show a fullscreen view of the
+ * photo, potentially with ways to interact with it
+ */
+public class ViewStreamItemPhotoActivity extends Activity {
+ private static final String TAG = "ViewStreamItemPhotoActivity";
+
+ private TextView mUriTextView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_stream_item_photo_activity);
+
+ mUriTextView = (TextView) findViewById(R.id.view_stream_item_photo_uri);
+ mUriTextView.setText(getIntent().getDataString());
+ }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
index 2a3c0fc..5649f6d 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
@@ -110,7 +110,7 @@
mMessage = (TextView) findViewById(R.id.message);
mUsernameEdit = (EditText) findViewById(R.id.username_edit);
mPasswordEdit = (EditText) findViewById(R.id.password_edit);
- mUsernameEdit.setText(mUsername);
+ if (!TextUtils.isEmpty(mUsername)) mUsernameEdit.setText(mUsername);
mMessage.setText(getMessage());
}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
index bebcd72..c2ebd19 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
@@ -16,16 +16,6 @@
package com.example.android.samplesync.client;
-import android.accounts.Account;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Handler;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.example.android.samplesync.authenticator.AuthenticatorActivity;
-
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
@@ -41,9 +31,15 @@
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
-import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.accounts.Account;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.text.TextUtils;
+import android.util.Log;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
@@ -54,11 +50,8 @@
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
-import java.util.TimeZone;
/**
* Provides utility methods for communicating with the server.
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java
deleted file mode 100644
index efda0cc..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * 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.example.android.samplesync.editor;
-
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.R;
-import com.example.android.samplesync.client.RawContact;
-import com.example.android.samplesync.platform.BatchOperation;
-import com.example.android.samplesync.platform.ContactManager;
-import com.example.android.samplesync.platform.ContactManager.ContactQuery;
-import com.example.android.samplesync.platform.ContactManager.EditorQuery;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.widget.EditText;
-import android.widget.TextView;
-
-/**
- * Implements a sample editor for a contact that belongs to a remote contact service.
- * The editor can be invoked for an existing SampleSyncAdapter contact, or it can
- * be used to create a brand new SampleSyncAdapter contact. We look at the Intent
- * object to figure out whether this is a "new" or "edit" operation.
- */
-public class ContactEditorActivity extends Activity {
- private static final String TAG = "SampleSyncAdapter";
-
- // Keep track of whether we're inserting a new contact or editing an
- // existing contact.
- private boolean mIsInsert;
-
- // The name of the external account we're syncing this contact to.
- private String mAccountName;
-
- // For existing contacts, this is the URI to the contact data.
- private Uri mRawContactUri;
-
- // The raw clientId for this contact
- private long mRawContactId;
-
- // Make sure we only attempt to save the contact once if the
- // user presses the "done" button multiple times...
- private boolean mSaveInProgress = false;
-
- // Keep track of the controls used to edit contact values, so we can get/set
- // those values easily.
- private EditText mNameEditText;
- private EditText mHomePhoneEditText;
- private EditText mMobilePhoneEditText;
- private EditText mWorkPhoneEditText;
- private EditText mEmailEditText;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.editor);
-
- mNameEditText = (EditText)findViewById(R.id.editor_name);
- mHomePhoneEditText = (EditText)findViewById(R.id.editor_phone_home);
- mMobilePhoneEditText = (EditText)findViewById(R.id.editor_phone_mobile);
- mWorkPhoneEditText = (EditText)findViewById(R.id.editor_phone_work);
- mEmailEditText = (EditText)findViewById(R.id.editor_email);
-
- // Figure out whether we're creating a new contact (ACTION_INSERT), editing
- // an existing contact, or adding a new one to existing contact (INVITE_CONTACT).
- Intent intent = getIntent();
- String action = intent.getAction();
- if (Intent.ACTION_INSERT.equals(action)) {
- // We're inserting a new contact, so save off the external account name
- // which should have been added to the intent we were passed.
- mIsInsert = true;
- String accountName = intent.getStringExtra(RawContacts.ACCOUNT_NAME);
- if (accountName == null) {
- Log.e(TAG, "Account name is required");
- finish();
- }
- setAccountName(accountName);
- } else if (ContactsContract.Intents.INVITE_CONTACT.equals(action)) {
- // Adding to an existing contact.
- mIsInsert = true;
- // Use the first account found.
- Account[] myAccounts = AccountManager.get(this).getAccountsByType(
- Constants.ACCOUNT_TYPE);
- if (myAccounts.length == 0) {
- Log.e(TAG, "Account not configured");
- finish();
- }
- setAccountName(myAccounts[0].name);
-
- Uri lookupUri = intent.getData();
- if (lookupUri == null) {
- Log.e(TAG, "Contact lookup URI is required");
- finish();
- }
- startLoadContactEntity(lookupUri);
- } else {
- // We're editing an existing contact. Load in the data from the contact
- // so that the user can edit it.
- mIsInsert = false;
- mRawContactUri = intent.getData();
- if (mRawContactUri == null) {
- Log.e(TAG, "Raw contact URI is required");
- finish();
- }
- startLoadRawContactEntity();
- }
- }
-
- @Override
- public void onBackPressed() {
- // This method will have been called if the user presses the "Back" button
- // in the ActionBar. We treat that the same way as the "Done" button in
- // the ActionBar.
- save();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // This method gets called so that we can place items in the main Options menu -
- // for example, the ActionBar items. We add our menus from the res/menu/edit.xml
- // file.
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.edit, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- case R.id.menu_done:
- // The user pressed the "Home" button or our "Done" button - both
- // in the ActionBar. In both cases, we want to save the contact
- // and exit.
- save();
- return true;
- case R.id.menu_cancel:
- // The user pressed the Cancel menu item in the ActionBar.
- // Close the editor without saving any changes.
- finish();
- return true;
- }
- return false;
- }
-
- /**
- * Create an AsyncTask to load the contact from the Contacts data provider
- */
- private void startLoadRawContactEntity() {
- Uri uri = Uri.withAppendedPath(mRawContactUri, RawContacts.Entity.CONTENT_DIRECTORY);
- new LoadRawContactTask().execute(uri);
- }
-
- /**
- * Called by the LoadRawContactTask when the contact information has been
- * successfully loaded from the Contacts data provider.
- */
- public void onRawContactEntityLoaded(Cursor cursor) {
- if (cursor.moveToFirst()) {
- String mimetype = cursor.getString(EditorQuery.COLUMN_MIMETYPE);
- if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
- setAccountName(cursor.getString(EditorQuery.COLUMN_ACCOUNT_NAME));
- mRawContactId = cursor.getLong(EditorQuery.COLUMN_RAW_CONTACT_ID);
- mNameEditText.setText(cursor.getString(EditorQuery.COLUMN_FULL_NAME));
- } else if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
- final int type = cursor.getInt(EditorQuery.COLUMN_PHONE_TYPE);
- if (type == Phone.TYPE_HOME) {
- mHomePhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
- } else if (type == Phone.TYPE_MOBILE) {
- mMobilePhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
- } else if (type == Phone.TYPE_WORK) {
- mWorkPhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
- }
- } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
- mEmailEditText.setText(cursor.getString(EditorQuery.COLUMN_DATA1));
- }
- }
- }
-
- /**
- * Create an AsyncTask to load the contact from the Contacts data provider
- */
- private void startLoadContactEntity(Uri lookupUri) {
- new LoadContactTask().execute(lookupUri);
- }
-
- /**
- * Called by the LoadContactTask when the contact information has been
- * successfully loaded from the Contacts data provider.
- */
- public void onContactEntityLoaded(Cursor cursor) {
- if (cursor.moveToFirst()) {
- mNameEditText.setText(cursor.getString(ContactQuery.COLUMN_DISPLAY_NAME));
- }
- }
-
- /**
- * Save the updated contact data. We actually take two different actions
- * depending on whether we are creating a new contact or editing an
- * existing contact.
- */
- public void save() {
- // If we're already saving this contact, don't kick-off yet
- // another save - the user probably just pressed the "Done"
- // button multiple times...
- if (mSaveInProgress) {
- return;
- }
-
- mSaveInProgress = true;
- if (mIsInsert) {
- saveNewContact();
- } else {
- saveChanges();
- }
- }
-
- /**
- * Save off the external contacts provider account name. We show the account name
- * in the header section of the edit panel, and we also need it later when we
- * save off a brand new contact.
- */
- private void setAccountName(String accountName) {
- mAccountName = accountName;
- Log.i(TAG, "account=" + mAccountName);
- if (accountName != null) {
- TextView accountNameLabel = (TextView)findViewById(R.id.header_account_name);
- if (accountNameLabel != null) {
- accountNameLabel.setText(accountName);
- }
- }
- }
-
- /**
- * Save a new contact using the Contacts content provider. The actual insertion
- * is performed in an AsyncTask.
- */
- @SuppressWarnings("unchecked")
- private void saveNewContact() {
- new InsertContactTask().execute(buildRawContact());
- }
-
- /**
- * Save changes to an existing contact. The actual update is performed in
- * an AsyncTask.
- */
- @SuppressWarnings("unchecked")
- private void saveChanges() {
- new UpdateContactTask().execute(buildRawContact());
- }
-
- /**
- * Build a RawContact object from the data in the user-editable form
- * @return a new RawContact object representing the edited user
- */
- private RawContact buildRawContact() {
- return RawContact.create(mNameEditText.getText().toString(),
- null,
- null,
- mMobilePhoneEditText.getText().toString(),
- mWorkPhoneEditText.getText().toString(),
- mHomePhoneEditText.getText().toString(),
- mEmailEditText.getText().toString(),
- null,
- false,
- mRawContactId,
- -1);
- }
-
- /**
- * Called after a contact is saved - both for edited contacts and new contacts.
- * We set the final result of the activity to be "ok", and then close the activity
- * by calling finish().
- */
- public void onContactSaved(Uri result) {
- if (result != null) {
- Intent intent = new Intent();
- intent.setData(result);
- setResult(RESULT_OK, intent);
- finish();
- }
- mSaveInProgress = false;
- }
-
- /**
- * Represents an asynchronous task used to load a contact from
- * the Contacts content provider.
- *
- */
- public class LoadRawContactTask extends AsyncTask<Uri, Void, Cursor> {
-
- @Override
- protected Cursor doInBackground(Uri... params) {
- // Our background task is to load the contact from the Contacts provider
- return getContentResolver().query(params[0], EditorQuery.PROJECTION, null, null, null);
- }
-
- @Override
- protected void onPostExecute(Cursor cursor) {
- if (cursor == null) return;
- // After we've successfully loaded the contact, call back into
- // the ContactEditorActivity so we can update the UI
- try {
- onRawContactEntityLoaded(cursor);
- } finally {
- cursor.close();
- }
- }
- }
-
- /**
- * Represents an asynchronous task used to save a new contact
- * into the contacts database.
- */
- public class InsertContactTask extends AsyncTask<RawContact, Void, Uri> {
-
- @Override
- protected Uri doInBackground(RawContact... params) {
- try {
- final RawContact rawContact = params[0];
- final Context context = getApplicationContext();
- final ContentResolver resolver = getContentResolver();
- final BatchOperation batchOperation = new BatchOperation(context, resolver);
- ContactManager.addContact(context, mAccountName, rawContact, false, batchOperation);
- Uri rawContactUri = batchOperation.execute();
-
- // Convert the raw contact URI to a contact URI
- if (rawContactUri != null) {
- return RawContacts.getContactLookupUri(resolver, rawContactUri);
- } else {
- Log.e(TAG, "Could not save new contact");
- return null;
- }
- } catch (Exception e) {
- Log.e(TAG, "An error occurred while saving new contact", e);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Uri result) {
- // Tell the UI that the contact has been successfully saved
- onContactSaved(result);
- }
- }
-
-
- /**
- * Represents an asynchronous task used to save an updated contact
- * into the contacts database.
- */
- public class UpdateContactTask extends AsyncTask<RawContact, Void, Uri> {
-
- @Override
- protected Uri doInBackground(RawContact... params) {
- try {
- final RawContact rawContact = params[0];
- final Context context = getApplicationContext();
- final ContentResolver resolver = getContentResolver();
- final BatchOperation batchOperation = new BatchOperation(context, resolver);
- ContactManager.updateContact(context, resolver, rawContact, false, false, false,
- false, rawContact.getRawContactId(), batchOperation);
- batchOperation.execute();
-
- // Convert the raw contact URI to a contact URI
- return RawContacts.getContactLookupUri(resolver, mRawContactUri);
- } catch (Exception e) {
- Log.e(TAG, "Could not save changes", e);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Uri result) {
- // Tell the UI that the contact has been successfully saved
- onContactSaved(result);
- }
- }
-
- /**
- * Loads contact information by a lookup URI.
- */
- public class LoadContactTask extends AsyncTask<Uri, Void, Cursor> {
-
- @Override
- protected Cursor doInBackground(Uri... params) {
- return getContentResolver().query(params[0], ContactQuery.PROJECTION, null, null, null);
- }
-
- @Override
- protected void onPostExecute(Cursor cursor) {
- if (cursor == null) return;
- try {
- onContactEntityLoaded(cursor);
- } finally {
- cursor.close();
- }
- }
- }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
index 035c976..6b2dfb1 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
@@ -34,6 +34,7 @@
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.Settings;
import android.provider.ContactsContract.StatusUpdates;
@@ -54,6 +55,41 @@
private static final String TAG = "ContactManager";
+ public static final String SAMPLE_GROUP_NAME = "Sample Group";
+
+ public static long ensureSampleGroupExists(Context context, Account account) {
+ final ContentResolver resolver = context.getContentResolver();
+
+ // Lookup the sample group
+ long groupId = 0;
+ final Cursor cursor = resolver.query(Groups.CONTENT_URI, new String[] { Groups._ID },
+ Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=? AND " +
+ Groups.TITLE + "=?",
+ new String[] { account.name, account.type, SAMPLE_GROUP_NAME }, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ groupId = cursor.getLong(0);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ if (groupId == 0) {
+ // Sample group doesn't exist yet, so create it
+ final ContentValues contentValues = new ContentValues();
+ contentValues.put(Groups.ACCOUNT_NAME, account.name);
+ contentValues.put(Groups.ACCOUNT_TYPE, account.type);
+ contentValues.put(Groups.TITLE, SAMPLE_GROUP_NAME);
+ contentValues.put(Groups.GROUP_IS_READ_ONLY, true);
+
+ final Uri newGroupUri = resolver.insert(Groups.CONTENT_URI, contentValues);
+ groupId = ContentUris.parseId(newGroupUri);
+ }
+ return groupId;
+ }
+
/**
* Take a list of updated contacts and apply those changes to the
* contacts database. Typically this list of contacts would have been
@@ -67,7 +103,7 @@
* sync request.
*/
public static synchronized long updateContacts(Context context, String account,
- List<RawContact> rawContacts, long lastSyncMarker) {
+ List<RawContact> rawContacts, long groupId, long lastSyncMarker) {
long currentSyncMarker = lastSyncMarker;
final ContentResolver resolver = context.getContentResolver();
@@ -112,7 +148,7 @@
Log.d(TAG, "In addContact");
if (!rawContact.isDeleted()) {
newUsers.add(rawContact);
- addContact(context, account, rawContact, true, batchOperation);
+ addContact(context, account, rawContact, groupId, true, batchOperation);
}
}
// A sync adapter should batch operations on multiple contacts,
@@ -235,12 +271,13 @@
* @param context the Authenticator Activity context
* @param accountName the account the contact belongs to
* @param rawContact the sample SyncAdapter User object
+ * @param groupId the id of the sample group
* @param inSync is the add part of a client-server sync?
* @param batchOperation allow us to batch together multiple operations
* into a single provider call
*/
public static void addContact(Context context, String accountName, RawContact rawContact,
- boolean inSync, BatchOperation batchOperation) {
+ long groupId, boolean inSync, BatchOperation batchOperation) {
// Put the data in the contacts provider
final ContactOperations contactOp = ContactOperations.createNewContact(
@@ -252,6 +289,7 @@
.addPhone(rawContact.getCellPhone(), Phone.TYPE_MOBILE)
.addPhone(rawContact.getHomePhone(), Phone.TYPE_HOME)
.addPhone(rawContact.getOfficePhone(), Phone.TYPE_WORK)
+ .addGroupMembership(groupId)
.addAvatar(rawContact.getAvatarUrl());
// If we have a serverId, then go ahead and create our status profile.
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
index cb8e97b..1445e55 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
@@ -25,6 +25,7 @@
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
@@ -185,6 +186,20 @@
return this;
}
+ /**
+ * Adds a group membership
+ *
+ * @param id The id of the group to assign
+ * @return instance of ContactOperations
+ */
+ public ContactOperations addGroupMembership(long groupId) {
+ mValues.clear();
+ mValues.put(GroupMembership.GROUP_ROW_ID, groupId);
+ mValues.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
+ addInsertOp();
+ return this;
+ }
+
public ContactOperations addAvatar(String avatarUrl) {
if (avatarUrl != null) {
byte[] avatarBuffer = NetworkUtilities.downloadAvatar(avatarUrl);
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
index 0ca8dee..0f570cd 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
@@ -15,6 +15,15 @@
*/
package com.example.android.samplesync.syncadapter;
+import com.example.android.samplesync.Constants;
+import com.example.android.samplesync.client.NetworkUtilities;
+import com.example.android.samplesync.client.RawContact;
+import com.example.android.samplesync.platform.ContactManager;
+
+import org.apache.http.ParseException;
+import org.apache.http.auth.AuthenticationException;
+import org.json.JSONException;
+
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
@@ -27,18 +36,7 @@
import android.text.TextUtils;
import android.util.Log;
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.client.NetworkUtilities;
-import com.example.android.samplesync.client.RawContact;
-import com.example.android.samplesync.platform.ContactManager;
-
-import org.apache.http.ParseException;
-import org.apache.http.auth.AuthenticationException;
-import org.json.JSONException;
-
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
/**
@@ -91,6 +89,9 @@
final String authtoken = mAccountManager.blockingGetAuthToken(account,
Constants.AUTHTOKEN_TYPE, NOTIFY_AUTH_FAILURE);
+ // Make sure that the sample group exists
+ final long groupId = ContactManager.ensureSampleGroupExists(mContext, account);
+
// Find the local 'dirty' contacts that we need to tell the server about...
// Find the local users that need to be sync'd to the server...
dirtyContacts = ContactManager.getDirtyContacts(mContext, account);
@@ -106,6 +107,7 @@
long newSyncState = ContactManager.updateContacts(mContext,
account.name,
updatedContacts,
+ groupId,
lastSyncMarker);
// This is a demo of how you can update IM-style status messages
diff --git a/tools/emulator/opengl/Android.mk b/tools/emulator/opengl/Android.mk
index 8147395..2c1cb64 100644
--- a/tools/emulator/opengl/Android.mk
+++ b/tools/emulator/opengl/Android.mk
@@ -9,11 +9,6 @@
#
ifeq (true,$(BUILD_EMULATOR_OPENGL))
-# By default, NEVER build the gralloc.goldfish support library because
-# the code has not been ported to Honeycomb / IceCreamSandwich yet and
-# will fail to build properly.
-BUILD_EMULATOR_OPENGL_DRIVER ?= true
-
# Top-level for all modules
EMUGL_PATH := $(call my-dir)
@@ -71,13 +66,8 @@
include $(EMUGL_PATH)/system/GLESv1/Android.mk
include $(EMUGL_PATH)/system/GLESv2/Android.mk
-ifeq (false,$(BUILD_EMULATOR_OPENGL_DRIVER))
- include $(EMUGL_PATH)/tests/ut_rendercontrol_enc/Android.mk
- include $(EMUGL_PATH)/tests/gles_android_wrapper/Android.mk
-else
- include $(EMUGL_PATH)/system/gralloc/Android.mk
- include $(EMUGL_PATH)/system/egl/Android.mk
-endif
+include $(EMUGL_PATH)/system/gralloc/Android.mk
+include $(EMUGL_PATH)/system/egl/Android.mk
# Host static libraries
include $(EMUGL_PATH)/host/libs/GLESv1_dec/Android.mk
@@ -95,12 +85,7 @@
# Host executables
include $(EMUGL_PATH)/host/renderer/Android.mk
-# Host unit-test for the renderer. this one uses its own small
-# EGL host wrapper.
-include $(EMUGL_PATH)/tests/event_injector/Android.mk
-include $(EMUGL_PATH)/tests/EGL_host_wrapper/Android.mk
-include $(EMUGL_PATH)/tests/emulator_test_renderer/Android.mk
-include $(EMUGL_PATH)/tests/ut_renderer/Android.mk
+# Host unit-test for the renderer.
include $(EMUGL_PATH)/tests/translator_tests/MacCommon/Android.mk
include $(EMUGL_PATH)/tests/translator_tests/GLES_CM/Android.mk
diff --git a/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h b/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h
index 41d8023..445ec17 100644
--- a/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h
+++ b/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h
@@ -34,6 +34,7 @@
virtual int commitBuffer(size_t size) = 0;
virtual const unsigned char *readFully( void *buf, size_t len) = 0;
virtual const unsigned char *read( void *buf, size_t *inout_len) = 0;
+ virtual int writeFully(const void* buf, size_t len) = 0;
virtual ~IOStream() {
@@ -82,6 +83,7 @@
return readFully(buf, len);
}
+
private:
unsigned char *m_buf;
size_t m_bufsize;
diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
index 9e95604..4265301 100644
--- a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
+++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -21,6 +21,15 @@
#include <errno.h>
#include <sys/types.h>
+/* Define this to 1 to enable support for the 'isLarge' variable flag
+ * that instructs the encoder to send large data buffers by a direct
+ * write through the pipe (i.e. without copying it into a temporary
+ * buffer. This has definite performance benefits when using a QEMU Pipe.
+ *
+ * Set to 0 otherwise.
+ */
+#define WITH_LARGE_SUPPORT 1
+
EntryPoint * ApiGen::findEntryByName(const std::string & name)
{
EntryPoint * entry = NULL;
@@ -338,6 +347,104 @@
return 0;
}
+// Format the byte length expression for a given variable into a user-provided buffer
+// If the variable type is not a pointer, this is simply its size as a decimal constant
+// If the variable is a pointer, this will be an expression provided by the .attrib file
+// through the 'len' attribute.
+//
+// Returns 1 if the variable is a pointer, 0 otherwise
+//
+static int getVarEncodingSizeExpression(Var& var, EntryPoint* e, char* buff, size_t bufflen)
+{
+ int ret = 0;
+ if (!var.isPointer()) {
+ snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
+ } else {
+ ret = 1;
+ const char* lenExpr = var.lenExpression().c_str();
+ const char* varname = var.name().c_str();
+ if (e != NULL && lenExpr[0] == '\0') {
+ fprintf(stderr, "%s: data len is undefined for '%s'\n",
+ e->name().c_str(), varname);
+ }
+ if (var.nullAllowed()) {
+ snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
+ } else {
+ snprintf(buff, bufflen, "%s", lenExpr);
+ }
+ }
+ return ret;
+}
+
+static int writeVarEncodingSize(Var& var, FILE* fp)
+{
+ int ret = 0;
+ if (!var.isPointer()) {
+ fprintf(fp, "%u", (unsigned int) var.type()->bytes());
+ } else {
+ ret = 1;
+ fprintf(fp, "__size_%s", var.name().c_str());
+ }
+ return ret;
+}
+
+
+
+static void writeVarEncodingExpression(Var& var, FILE* fp)
+{
+ const char* varname = var.name().c_str();
+
+ if (var.isPointer()) {
+ // encode a pointer header
+ fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname);
+
+ Var::PointerDir dir = var.pointerDir();
+ if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
+ if (var.nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ", varname);
+ } else {
+ fprintf(fp, "\t");
+ }
+
+ if (var.packExpression().size() != 0) {
+ fprintf(fp, "%s;", var.packExpression().c_str());
+ } else {
+ fprintf(fp, "memcpy(ptr, %s, __size_%s);",
+ varname, varname);
+ }
+
+ fprintf(fp, "ptr += __size_%s;\n", varname);
+ }
+ } else {
+ // encode a non pointer variable
+ if (!var.isVoid()) {
+ fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
+ var.type()->name().c_str(), varname,
+ (uint) var.type()->bytes());
+ }
+ }
+}
+
+#if WITH_LARGE_SUPPORT
+static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
+{
+ const char* varname = var.name().c_str();
+
+ fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
+ if (var.nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ", varname);
+ } else {
+ fprintf(fp, "\t");
+ }
+ if (var.writeExpression() != "") {
+ fprintf(fp, "%s", var.writeExpression().c_str());
+ } else {
+ fprintf(fp, "stream->writeFully(%s, __size_%s)", varname, varname);
+ }
+ fprintf(fp, ";\n");
+}
+#endif /* WITH_LARGE_SUPPORT */
+
int ApiGen::genEncoderImpl(const std::string &filename)
{
FILE *fp = fopen(filename.c_str(), "wt");
@@ -368,46 +475,139 @@
fprintf(fp, "{\n");
// fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
- fprintf(fp, "\n\t%s *ctx = (%s *)self;\n\n",
+ fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
classname.c_str(),
classname.c_str());
-
- // size calculation ;
- fprintf(fp, "\t size_t packetSize = ");
-
+ fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n");
VarsArray & evars = e->vars();
+ size_t maxvars = evars.size();
+ size_t j;
+
+ char buff[256];
+
+ // Define the __size_XXX variables that contain the size of data
+ // associated with pointers.
+ for (j = 0; j < maxvars; j++) {
+ Var& var = evars[j];
+
+ if (!var.isPointer())
+ continue;
+
+ const char* varname = var.name().c_str();
+ fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
+
+ getVarEncodingSizeExpression(var, e, buff, sizeof(buff));
+ fprintf(fp, "%s;\n", buff);
+ }
+
+#if WITH_LARGE_SUPPORT
+ // We need to take care of 'isLarge' variable in a special way
+ // Anything before an isLarge variable can be packed into a single
+ // buffer, which is then commited. Each isLarge variable is a pointer
+ // to data that can be written to directly through the pipe, which
+ // will be instant when using a QEMU pipe
+
+ size_t nvars = 0;
+ size_t npointers = 0;
+
+ // First, compute the total size, 8 bytes for the opcode + payload size
+ fprintf(fp, "\t unsigned char *ptr;\n");
+ fprintf(fp, "\t const size_t packetSize = 8");
+
+ for (j = 0; j < maxvars; j++) {
+ fprintf(fp, " + ");
+ npointers += writeVarEncodingSize(evars[j], fp);
+ }
+ if (npointers > 0) {
+ fprintf(fp, " + %u*4", npointers);
+ }
+ fprintf(fp, ";\n");
+
+ // We need to divide the packet into fragments. Each fragment contains
+ // either copied arguments to a temporary buffer, or direct writes for
+ // large variables.
+ //
+ // The first fragment must also contain the opcode+payload_size
+ //
+ nvars = 0;
+ while (nvars < maxvars || maxvars == 0) {
+
+ // Skip over non-large fields
+ for (j = nvars; j < maxvars; j++) {
+ if (evars[j].isLarge())
+ break;
+ }
+
+ // Write a fragment if needed.
+ if (nvars == 0 || j > nvars) {
+ const char* plus = "";
+
+ if (nvars == 0 && j == maxvars) {
+ // Simple shortcut for the common case where we don't have large variables;
+ fprintf(fp, "\tptr = stream->alloc(packetSize);\n");
+
+ } else {
+ // allocate buffer from the stream until the first large variable
+ fprintf(fp, "\tptr = stream->alloc(");
+ plus = "";
+
+ if (nvars == 0) {
+ fprintf(fp,"8"); plus = " + ";
+ }
+ if (j > nvars) {
+ npointers = 0;
+ for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+ fprintf(fp, "%s", plus); plus = " + ";
+ npointers += writeVarEncodingSize(evars[j], fp);
+ }
+ if (npointers > 0) {
+ fprintf(fp, "%s%u*4", plus, npointers); plus = " + ";
+ }
+ }
+ fprintf(fp,");\n");
+ }
+
+ // encode packet header if needed.
+ if (nvars == 0) {
+ fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
+ fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n");
+ }
+
+ if (maxvars == 0)
+ break;
+
+ // encode non-large fields in this fragment
+ for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+ writeVarEncodingExpression(evars[j],fp);
+ }
+
+ // Ensure the fragment is commited if it is followed by a large variable
+ if (j < maxvars) {
+ fprintf(fp, "\tstream->flush();\n");
+ }
+ }
+
+ // If we have one or more large variables, write them directly.
+ // As size + data
+ for ( ; j < maxvars && evars[j].isLarge(); j++) {
+ writeVarLargeEncodingExpression(evars[j], fp);
+ }
+
+ nvars = j;
+ }
+
+#else /* !WITH_LARGE_SUPPORT */
size_t nvars = evars.size();
size_t npointers = 0;
+ fprintf(fp, "\t const size_t packetSize = 8");
for (size_t j = 0; j < nvars; j++) {
- fprintf(fp, "%s ", j == 0 ? "" : " +");
- if (evars[j].isPointer()) {
- npointers++;
-
- if (evars[j].lenExpression() == "") {
- fprintf(stderr, "%s: data len is undefined for '%s'\n",
- e->name().c_str(), evars[j].name().c_str());
- }
-
- if (evars[j].nullAllowed()) {
- fprintf(fp, "(%s != NULL ? %s : 0)",
- evars[j].name().c_str(),
- evars[j].lenExpression().c_str());
- } else {
- if (evars[j].pointerDir() == Var::POINTER_IN ||
- evars[j].pointerDir() == Var::POINTER_INOUT) {
- fprintf(fp, "%s", evars[j].lenExpression().c_str());
- } else {
- fprintf(fp, "0");
- }
- }
- } else {
- fprintf(fp, "%u", (unsigned int) evars[j].type()->bytes());
- }
+ npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff));
+ fprintf(fp, " + %s", buff);
}
- fprintf(fp, " %s 8 + %u * 4;\n", nvars != 0 ? "+" : "", (unsigned int) npointers);
+ fprintf(fp, " + %u * 4;\n", (unsigned int) npointers);
// allocate buffer from the stream;
- fprintf(fp, "\t unsigned char *ptr = ctx->m_stream->alloc(packetSize);\n\n");
+ fprintf(fp, "\t unsigned char *ptr = stream->alloc(packetSize);\n\n");
// encode into the stream;
fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
@@ -415,62 +615,23 @@
// out variables
for (size_t j = 0; j < nvars; j++) {
- if (evars[j].isPointer()) {
- // encode a pointer header
- if (evars[j].nullAllowed()) {
- fprintf(fp, "\t*(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n",
- evars[j].name().c_str(), evars[j].lenExpression().c_str());
- } else {
- fprintf(fp, "\t*(unsigned int *)(ptr) = %s; ptr += 4; \n",
- evars[j].lenExpression().c_str());
- }
-
- Var::PointerDir dir = evars[j].pointerDir();
- if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
- if (evars[j].nullAllowed()) {
- fprintf(fp, "\tif (%s != NULL) ", evars[j].name().c_str());
- } else {
- fprintf(fp, "\t");
- }
-
- if (evars[j].packExpression().size() != 0) {
- fprintf(fp, "%s;", evars[j].packExpression().c_str());
- } else {
- fprintf(fp, "memcpy(ptr, %s, %s);",
- evars[j].name().c_str(),
- evars[j].lenExpression().c_str());
- }
-
- if (evars[j].nullAllowed()) {
- fprintf(fp, "ptr += %s == NULL ? 0 : %s; \n", evars[j].name().c_str(), evars[j].lenExpression().c_str());
- } else {
- fprintf(fp, "ptr += %s;\n", evars[j].lenExpression().c_str());
- }
- }
- } else {
- // encode a non pointer variable
- if (!evars[j].isVoid()) {
- fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
- evars[j].type()->name().c_str(), evars[j].name().c_str(),
- (uint) evars[j].type()->bytes());
- }
- }
+ writeVarEncodingExpression(evars[j], fp);
}
+#endif /* !WITH_LARGE_SUPPORT */
+
// in variables;
for (size_t j = 0; j < nvars; j++) {
if (evars[j].isPointer()) {
Var::PointerDir dir = evars[j].pointerDir();
if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
+ const char* varname = evars[j].name().c_str();
if (evars[j].nullAllowed()) {
- fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n",
- evars[j].name().c_str(),
- evars[j].name().c_str(),
- evars[j].lenExpression().c_str());
+ fprintf(fp, "\tif (%s != NULL) ",varname);
} else {
- fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n",
- evars[j].name().c_str(),
- evars[j].lenExpression().c_str());
+ fprintf(fp, "\t");
}
+ fprintf(fp, "stream->readback(%s, __size_%s);\n",
+ varname, varname);
}
}
}
@@ -482,7 +643,7 @@
fprintf(fp, "\t return NULL;\n");
} else if (e->retval().type()->name() != "void") {
fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
- fprintf(fp, "\tctx->m_stream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
+ fprintf(fp, "\tstream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
fprintf(fp, "\treturn retval;\n");
}
fprintf(fp, "}\n\n");
diff --git a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
index 413b56a..43b904b 100644
--- a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
+++ b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
@@ -119,7 +119,7 @@
fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
}
- m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""));
+ m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""), std::string(""));
// function name
m_name = getNextToken(linestr, pos, &last, ",)");
@@ -146,7 +146,7 @@
varname = oss.str();
}
- m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, ""));
+ m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", ""));
}
pos = last + 1;
}
@@ -286,22 +286,36 @@
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
- pos = last;
- std::string flag = getNextToken(line, pos, &last, WHITESPACE);
- if (flag.size() == 0) {
- fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
- return -3;
- }
-
- if (flag == "nullAllowed") {
- if (v->isPointer()) {
- v->setNullAllowed(true);
- } else {
- fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
- (unsigned int) lc, v->name().c_str());
+ int count = 0;
+ for (;;) {
+ pos = last;
+ std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+ if (flag.size() == 0) {
+ if (count == 0) {
+ fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+ return -3;
+ }
+ break;
}
- } else {
- fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+ count++;
+
+ if (flag == "nullAllowed") {
+ if (v->isPointer()) {
+ v->setNullAllowed(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
+ (unsigned int) lc, v->name().c_str());
+ }
+ } else if (flag == "isLarge") {
+ if (v->isPointer()) {
+ v->setIsLarge(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n",
+ (unsigned int) lc, v->name().c_str());
+ }
+ } else {
+ fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+ }
}
} else if (token == "custom_pack") {
pos = last;
@@ -320,6 +334,23 @@
// set the size expression into var
pos = last;
v->setPackExpression(line.substr(pos));
+ } else if (token == "custom_write") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_write' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setWriteExpression(line.substr(pos));
} else if (token == "flag") {
pos = last;
std::string flag = getNextToken(line, pos, &last, WHITESPACE);
diff --git a/tools/emulator/opengl/host/tools/emugen/README b/tools/emulator/opengl/host/tools/emugen/README
index 4d2c28d..5df11a3 100644
--- a/tools/emulator/opengl/host/tools/emugen/README
+++ b/tools/emulator/opengl/host/tools/emugen/README
@@ -313,7 +313,10 @@
var_flag
description : set variable flags
- format: var_flag <varname> < nullAllowed | ... >
+ format: var_flag <varname> < nullAllowed | isLarge | ... >
+
+ nullAllowed -> for pointer variables, indicates that NULL is a valid value
+ isLarge -> for pointer variables, indicates that the data should be sent without an intermediate copy
flag
description: set entry point flag;
diff --git a/tools/emulator/opengl/host/tools/emugen/Var.h b/tools/emulator/opengl/host/tools/emugen/Var.h
index c9735c7..322c66a 100644
--- a/tools/emulator/opengl/host/tools/emugen/Var.h
+++ b/tools/emulator/opengl/host/tools/emugen/Var.h
@@ -30,7 +30,9 @@
m_lenExpression(""),
m_pointerDir(POINTER_IN),
m_nullAllowed(false),
+ m_isLarge(false),
m_packExpression(""),
+ m_writeExpression(""),
m_paramCheckExpression("")
{
@@ -40,26 +42,33 @@
const VarType * vartype,
const std::string & lenExpression,
PointerDir dir,
- const std::string &packExpression) :
+ const std::string &packExpression,
+ const std::string &writeExpression) :
m_name(name),
m_type(const_cast<VarType *>(vartype)),
m_lenExpression(lenExpression),
m_pointerDir(dir),
m_nullAllowed(false),
+ m_isLarge(false),
m_packExpression(packExpression),
- m_paramCheckExpression("")
+ m_writeExpression(writeExpression),
+ m_paramCheckExpression("")
{
}
void init(const std::string name, const VarType * vartype,
std::string lenExpression,
- PointerDir dir, std::string packExpression) {
+ PointerDir dir,
+ std::string packExpression,
+ std::string writeExpression) {
m_name = name;
m_type = vartype;
m_lenExpression = lenExpression;
m_packExpression = packExpression;
+ m_writeExpression = writeExpression;
m_pointerDir = dir;
m_nullAllowed = false;
+ m_isLarge = false;
}
@@ -69,14 +78,18 @@
bool isVoid() const { return ((m_type->bytes() == 0) && (!m_type->isPointer())); }
const std::string & lenExpression() const { return m_lenExpression; }
const std::string & packExpression() const { return(m_packExpression); }
+ const std::string & writeExpression() const { return(m_writeExpression); }
const std::string & paramCheckExpression() const { return m_paramCheckExpression; }
void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
+ void setWriteExpression(const std::string & writeExpression) { m_writeExpression = writeExpression; }
void setParamCheckExpression(const std::string & paramCheckExpression) { m_paramCheckExpression = paramCheckExpression; }
void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
PointerDir pointerDir() { return m_pointerDir; }
void setNullAllowed(bool state) { m_nullAllowed = state; }
+ void setIsLarge(bool state) { m_isLarge = state; }
bool nullAllowed() const { return m_nullAllowed; }
+ bool isLarge() const { return m_isLarge; }
void printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); }
void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
@@ -87,7 +100,9 @@
std::string m_lenExpression; // an expression to calcualte a pointer data size
PointerDir m_pointerDir;
bool m_nullAllowed;
+ bool m_isLarge;
std::string m_packExpression; // an expression to pack data into the stream
+ std::string m_writeExpression; // an expression to write data into the stream
std::string m_paramCheckExpression; //an expression to check parameter value
};
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp
index 244cfbb..ddc56d0 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp
@@ -85,13 +85,18 @@
int SocketStream::commitBuffer(size_t size)
{
+ return writeFully(m_buf, size);
+}
+
+int SocketStream::writeFully(const void* buffer, size_t size)
+{
if (!valid()) return -1;
size_t res = size;
int retval = 0;
while (res > 0) {
- ssize_t stat = ::send(m_sock, (const char *)(m_buf) + (size - res), res, 0);
+ ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0);
if (stat < 0) {
if (errno != EINTR) {
retval = stat;
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h
index c54dea7..3a501b4 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h
@@ -37,6 +37,7 @@
bool valid() { return m_sock >= 0; }
virtual int recv(void *buf, size_t len);
+ virtual int writeFully(const void *buf, size_t len);
protected:
int m_sock;
@@ -44,7 +45,6 @@
unsigned char *m_buf;
SocketStream(int sock, size_t bufSize);
- int writeFully(const void *buf, size_t len);
};
#endif /* __SOCKET_STREAM_H */
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
index b0702a7..ae70598 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
@@ -16,6 +16,7 @@
#include "glUtils.h"
#include <string.h>
#include "ErrorLog.h"
+#include <IOStream.h>
size_t glSizeof(GLenum type)
{
@@ -344,6 +345,25 @@
}
}
+void glUtilsWritePackPointerData(void* _stream, unsigned char *src,
+ int size, GLenum type, unsigned int stride,
+ unsigned int datalen)
+{
+ IOStream* stream = reinterpret_cast<IOStream*>(_stream);
+
+ unsigned int vsize = size * glSizeof(type);
+ if (stride == 0) stride = vsize;
+
+ if (stride == vsize) {
+ stream->writeFully(src, datalen);
+ } else {
+ for (unsigned int i = 0; i < datalen; i += vsize) {
+ stream->writeFully(src, (size_t)vsize);
+ src += stride;
+ }
+ }
+}
+
int glUtilsPixelBitSize(GLenum format, GLenum type)
{
int components = 0;
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
index c66c568..f8857f1 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
@@ -51,6 +51,9 @@
void glUtilsPackPointerData(unsigned char *dst, unsigned char *str,
int size, GLenum type, unsigned int stride,
unsigned int datalen);
+ void glUtilsWritePackPointerData(void* stream, unsigned char *src,
+ int size, GLenum type, unsigned int stride,
+ unsigned int datalen);
int glUtilsPixelBitSize(GLenum format, GLenum type);
void glUtilsPackStrings(char *ptr, char **strings, GLint *length, GLsizei count);
int glUtilsCalcShaderSourceLen(char **strings, GLint *length, GLsizei count);
diff --git a/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp b/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp
index 6d12fe3..43391f0 100644
--- a/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp
+++ b/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp
@@ -544,7 +544,7 @@
m_glBufferData_enc = set_glBufferData(s_glBufferData);
m_glBufferSubData_enc = set_glBufferSubData(s_glBufferSubData);
m_glDeleteBuffers_enc = set_glDeleteBuffers(s_glDeleteBuffers);
-
+
m_glEnableClientState_enc = set_glEnableClientState(s_glEnableClientState);
m_glDisableClientState_enc = set_glDisableClientState(s_glDisableClientState);
m_glIsEnabled_enc = set_glIsEnabled(s_glIsEnabled);
@@ -558,7 +558,7 @@
GLEncoder::~GLEncoder()
{
- delete m_compressedTextureFormats;
+ delete [] m_compressedTextureFormats;
}
size_t GLEncoder::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack)
diff --git a/tools/emulator/opengl/system/GLESv1_enc/gl.attrib b/tools/emulator/opengl/system/GLESv1_enc/gl.attrib
index fed0f7a..9b84f89 100644
--- a/tools/emulator/opengl/system/GLESv1_enc/gl.attrib
+++ b/tools/emulator/opengl/system/GLESv1_enc/gl.attrib
@@ -240,7 +240,7 @@
glTexImage2D
dir pixels in
len pixels pixelDataSize(self, width, height, format, type, 0)
- var_flag pixels nullAllowed
+ var_flag pixels nullAllowed isLarge
#void glTexParameteriv(GLenum target, GLenum pname, GLint *params)
glTexParameteriv
@@ -253,6 +253,7 @@
#void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
glTexSubImage2D
len pixels pixelDataSize(self, width, height, format, type, 0)
+ var_flag pixels isLarge
#void glVertexPointer(GLint size, GLenum type, GLsizei stride, GLvoid *pointer)
# we treat the pointer as an offset to a VBO
diff --git a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
index 538c453..7fe9a66 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
+++ b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
@@ -9,20 +9,22 @@
#void glBufferData(GLenum target, GLsizeiptr size, GLvoid *data, GLenum usage)
glBufferData
len data size
- var_flag data nullAllowed
+ var_flag data nullAllowed isLarge
#void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data)
glBufferSubData
len data size
+ var_flag data isLarge
#void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLvoid *data)
glCompressedTexImage2D
len data imageSize
- var_flag data nullAllowed
+ var_flag data nullAllowed isLarge
#void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLvoid *data)
glCompressedTexSubImage2D
len data imageSize
+ var_flag data isLarge
#void glDeleteBuffers(GLsizei n, GLuint *buffers)
glDeleteBuffers
@@ -243,7 +245,7 @@
glTexImage2D
dir pixels in
len pixels pixelDataSize(self, width, height, format, type, 0)
- var_flag pixels nullAllowed
+ var_flag pixels nullAllowed isLarge
#void glTexParameterfv(GLenum target, GLenum pname, GLfloat *params)
glTexParameterfv
@@ -255,6 +257,7 @@
#void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
glTexSubImage2D
len pixels pixelDataSize(self, width, height, format, type, 0)
+ var_flag pixels isLarge
#void glUniform1fv(GLint location, GLsizei count, GLfloat *v)
glUniform1fv
@@ -333,20 +336,23 @@
#void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid *pixels)
glTexImage3DOES
- len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
- var_flag pixels nullAllowed
+ len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
+ var_flag pixels nullAllowed isLarge
#void glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *pixels)
glTexSubImage3DOES
len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
+ var_flag pixels isLarge
#void glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLvoid *data)
glCompressedTexImage3DOES
len data imageSize
+ var_flag data isLarge
#void glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLvoid *data)
glCompressedTexSubImage3DOES
len data imageSize
+ var_flag data isLarge
#void glDeleteVertexArraysOES(GLsizei n, GLuint *arrays)
glDeleteVertexArraysOES
diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h
index db36286..57ee399 100644
--- a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h
+++ b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h
@@ -39,8 +39,7 @@
bool valid() { return m_sock >= 0; }
int recv(void *buf, size_t len);
-private:
- int writeFully(const void *buf, size_t len);
+ virtual int writeFully(const void *buf, size_t len);
private:
int m_sock;
diff --git a/tools/emulator/opengl/system/egl/ClientAPIExts.cpp b/tools/emulator/opengl/system/egl/ClientAPIExts.cpp
index 888c231..5e81afe 100644
--- a/tools/emulator/opengl/system/egl/ClientAPIExts.cpp
+++ b/tools/emulator/opengl/system/egl/ClientAPIExts.cpp
@@ -129,7 +129,7 @@
#define API_ENTRY_RET(rtype,fname,params,args) \
API_ENTRY(fname,params,args)
-static struct _client_ext_funcs {
+static const struct _client_ext_funcs {
const char *fname;
void* proc;
} s_client_ext_funcs[] = {
diff --git a/tools/emulator/opengl/system/egl/ClientAPIExts.in b/tools/emulator/opengl/system/egl/ClientAPIExts.in
index c3162eb..5850701 100644
--- a/tools/emulator/opengl/system/egl/ClientAPIExts.in
+++ b/tools/emulator/opengl/system/egl/ClientAPIExts.in
@@ -2,7 +2,7 @@
// Each extension function should have one of the following
// macro definitions:
// API_ENTRY(funcname, paramlist, arglist)
-// -or- (in case funciton has return value)
+// -or- (if the function has a return value)
// API_ENTRY_RET(return_type,funcname, paramlist, arglist)
//
API_ENTRY(glEGLImageTargetTexture2DOES,
diff --git a/tools/emulator/opengl/system/egl/eglDisplay.cpp b/tools/emulator/opengl/system/egl/eglDisplay.cpp
index 78025b1..7beeb8e 100644
--- a/tools/emulator/opengl/system/egl/eglDisplay.cpp
+++ b/tools/emulator/opengl/system/egl/eglDisplay.cpp
@@ -19,17 +19,17 @@
static const int systemEGLVersionMajor = 1;
static const int systemEGLVersionMinor = 4;
-static const char *systemEGLVendor = "Google Android emulator";
+static const char systemEGLVendor[] = "Google Android emulator";
// list of extensions supported by this EGL implementation
// NOTE that each extension name should be suffixed with space
-static const char *systemStaticEGLExtensions =
+static const char systemStaticEGLExtensions[] =
"EGL_ANDROID_image_native_buffer ";
// list of extensions supported by this EGL implementation only if supported
// on the host implementation.
// NOTE that each extension name should be suffixed with space
-static const char *systemDynamicEGLExtensions =
+static const char systemDynamicEGLExtensions[] =
"EGL_KHR_image_base "
"EGL_KHR_gl_texture_2d_image ";
@@ -70,6 +70,11 @@
pthread_mutex_init(&m_lock, NULL);
}
+eglDisplay::~eglDisplay()
+{
+ pthread_mutex_destroy(&m_lock);
+}
+
bool eglDisplay::initialize(EGLClient_eglInterface *eglIface)
{
pthread_mutex_lock(&m_lock);
diff --git a/tools/emulator/opengl/system/egl/eglDisplay.h b/tools/emulator/opengl/system/egl/eglDisplay.h
index 934c699..9d979d9 100644
--- a/tools/emulator/opengl/system/egl/eglDisplay.h
+++ b/tools/emulator/opengl/system/egl/eglDisplay.h
@@ -33,6 +33,7 @@
{
public:
eglDisplay();
+ ~eglDisplay();
bool initialize(EGLClient_eglInterface *eglIface);
void terminate();
diff --git a/tools/emulator/opengl/system/egl/egl_ftable.h b/tools/emulator/opengl/system/egl/egl_ftable.h
index ee40585..2c9d19a 100644
--- a/tools/emulator/opengl/system/egl/egl_ftable.h
+++ b/tools/emulator/opengl/system/egl/egl_ftable.h
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-static struct _egl_funcs_by_name {
+static const struct _egl_funcs_by_name {
const char *name;
void *proc;
} egl_funcs_by_name[] = {
@@ -63,4 +63,4 @@
{"eglSetSwapRectangleANDROID", (void *)eglSetSwapRectangleANDROID}
};
-static int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name);
+static const int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name);
diff --git a/tools/emulator/opengl/system/gralloc/gralloc.cpp b/tools/emulator/opengl/system/gralloc/gralloc.cpp
index 9c3df97..b27eaa3 100644
--- a/tools/emulator/opengl/system/gralloc/gralloc.cpp
+++ b/tools/emulator/opengl/system/gralloc/gralloc.cpp
@@ -31,6 +31,21 @@
#include <cutils/log.h>
#include <cutils/properties.h>
+/* Set to 1 or 2 to enable debug traces */
+#define DEBUG 0
+
+#if DEBUG >= 1
+# define D(...) LOGD(__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+#if DEBUG >= 2
+# define DD(...) LOGD(__VA_ARGS__)
+#else
+# define DD(...) ((void)0)
+#endif
+
#define DBG_FUNC DBG("%s\n", __FUNCTION__)
//
// our private gralloc module structure
@@ -115,7 +130,7 @@
int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride)
{
- LOGD("gralloc_alloc w=%d h=%d usage=0x%x\n", w, h, usage);
+ D("gralloc_alloc w=%d h=%d usage=0x%x\n", w, h, usage);
gralloc_device_t *grdev = (gralloc_device_t *)dev;
if (!grdev || !pHandle || !pStride)
@@ -182,7 +197,7 @@
*pStride = bpr / bpp;
}
- LOGD("gralloc_alloc ashmem_size=%d, tid %d\n", ashmem_size, gettid());
+ D("gralloc_alloc ashmem_size=%d, tid %d\n", ashmem_size, gettid());
//
// Allocate space in ashmem if needed
@@ -194,7 +209,7 @@
fd = ashmem_create_region("gralloc-buffer", ashmem_size);
if (fd < 0) {
- LOGE("gralloc_alloc failed to create ashmem region err=%d\n", errno);
+ LOGE("gralloc_alloc failed to create ashmem region: %s\n", strerror(errno));
return -errno;
}
}
@@ -224,7 +239,7 @@
DEFINE_HOST_CONNECTION;
if (hostCon && rcEnc) {
cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat);
- LOGD("Created host ColorBuffer 0x%x\n", cb->hostHandle);
+ D("Created host ColorBuffer 0x%x\n", cb->hostHandle);
}
if (!cb->hostHandle) {
@@ -264,7 +279,7 @@
if (cb->hostHandle != 0) {
DEFINE_AND_VALIDATE_HOST_CONNECTION;
-
+ D("Destroying host ColorBuffer 0x%x\n", cb->hostHandle);
rcEnc->rcDestroyColorBuffer(rcEnc, cb->hostHandle);
}
@@ -370,7 +385,7 @@
DEFINE_AND_VALIDATE_HOST_CONNECTION;
// send request to host
- // XXX - should be implemented
+ // TODO: XXX - should be implemented
//rcEnc->rc_XXX
return 0;
@@ -399,9 +414,7 @@
{
fb_device_t *fbdev = (fb_device_t *)dev;
- if (fbdev) {
- delete fbdev;
- }
+ delete fbdev;
return 0;
}
@@ -418,11 +431,12 @@
return sFallback->registerBuffer(sFallback, handle);
}
+ D("gralloc_register_buffer(%p) called", handle);
private_module_t *gr = (private_module_t *)module;
cb_handle_t *cb = (cb_handle_t *)handle;
if (!gr || !cb_handle_t::validate(cb)) {
- ERR("gralloc_register_buffer: invalid buffer");
+ ERR("gralloc_register_buffer(%p): invalid buffer", cb);
return -EINVAL;
}
@@ -434,7 +448,7 @@
void *vaddr;
int err = map_buffer(cb, &vaddr);
if (err) {
- ERR("gralloc_register_buffer: map failed");
+ ERR("gralloc_register_buffer(%p): map failed: %s", cb, strerror(-err));
return -err;
}
cb->mappedPid = getpid();
@@ -453,7 +467,7 @@
private_module_t *gr = (private_module_t *)module;
cb_handle_t *cb = (cb_handle_t *)handle;
if (!gr || !cb_handle_t::validate(cb)) {
- ERR("gralloc_unregister_buffer: invalid buffer");
+ ERR("gralloc_unregister_buffer(%p): invalid buffer", cb);
return -EINVAL;
}
@@ -465,13 +479,15 @@
void *vaddr;
int err = munmap((void *)cb->ashmemBase, cb->ashmemSize);
if (err) {
- ERR("gralloc_unregister_buffer: unmap failed");
+ ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
return -EINVAL;
}
cb->ashmemBase = NULL;
cb->mappedPid = 0;
}
+ D("gralloc_unregister_buffer(%p) done\n", cb);
+
return 0;
}
@@ -640,7 +656,7 @@
{
int status = -EINVAL;
- LOGD("gralloc_device_open %s\n", name);
+ D("gralloc_device_open %s\n", name);
pthread_once( &sFallbackOnce, fallback_init );
if (sFallback != NULL) {
@@ -689,16 +705,21 @@
//
// Query the host for Framebuffer attributes
//
- LOGD("gralloc: query Frabuffer attribs\n");
+ D("gralloc: query Frabuffer attribs\n");
EGLint width = rcEnc->rcGetFBParam(rcEnc, FB_WIDTH);
- LOGD("gralloc: width=%d\n", width);
+ D("gralloc: width=%d\n", width);
EGLint height = rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT);
- LOGD("gralloc: height=%d\n", height);
+ D("gralloc: height=%d\n", height);
EGLint xdpi = rcEnc->rcGetFBParam(rcEnc, FB_XDPI);
+ D("gralloc: xdpi=%d\n", xdpi);
EGLint ydpi = rcEnc->rcGetFBParam(rcEnc, FB_YDPI);
+ D("gralloc: ydpi=%d\n", ydpi);
EGLint fps = rcEnc->rcGetFBParam(rcEnc, FB_FPS);
+ D("gralloc: fps=%d\n", fps);
EGLint min_si = rcEnc->rcGetFBParam(rcEnc, FB_MIN_SWAP_INTERVAL);
+ D("gralloc: min_swap=%d\n", min_si);
EGLint max_si = rcEnc->rcGetFBParam(rcEnc, FB_MAX_SWAP_INTERVAL);
+ D("gralloc: max_swap=%d\n", max_si);
//
// Allocate memory for the framebuffer device
diff --git a/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib b/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib
index c51ae0e..8b9972f 100644
--- a/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib
+++ b/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib
@@ -26,10 +26,10 @@
rcChooseConfig
dir attribs in
- len attribs attribs_size
- dir configs out
+ len attribs attribs_size
+ dir configs out
var_flag configs nullAllowed
- len configs configs_size*sizeof(uint32_t)
+ len configs configs_size*sizeof(uint32_t)
rcReadColorBuffer
dir pixels out
@@ -38,3 +38,4 @@
rcUpdateColorBuffer
dir pixels in
len pixels (((glUtilsPixelBitSize(format, type) * width) >> 3) * height)
+ var_flag pixels isLarge
diff --git a/tools/emulator/system/camera/Android.mk b/tools/emulator/system/camera/Android.mk
index 47f425a..2e5c19c 100755
--- a/tools/emulator/system/camera/Android.mk
+++ b/tools/emulator/system/camera/Android.mk
@@ -28,6 +28,16 @@
libcamera_client \
libui \
+# JPEG conversion libraries and includes.
+LOCAL_SHARED_LIBRARIES += \
+ libjpeg \
+ libskia \
+ libandroid_runtime \
+
+LOCAL_C_INCLUDES += external/jpeg \
+ external/skia/include/core/ \
+ frameworks/base/core/jni/android/graphics
+
LOCAL_SRC_FILES := \
EmulatedCameraHal.cpp \
EmulatedCameraFactory.cpp \
@@ -40,7 +50,8 @@
Converters.cpp \
PreviewWindow.cpp \
CallbackNotifier.cpp \
- QemuClient.cpp
+ QemuClient.cpp \
+ JpegCompressor.cpp
ifeq ($(TARGET_PRODUCT),vbox_x86)
LOCAL_MODULE := camera.vbox_x86
diff --git a/tools/emulator/system/camera/CallbackNotifier.cpp b/tools/emulator/system/camera/CallbackNotifier.cpp
index 188bf3a..a877b40 100755
--- a/tools/emulator/system/camera/CallbackNotifier.cpp
+++ b/tools/emulator/system/camera/CallbackNotifier.cpp
@@ -25,6 +25,7 @@
#include <media/stagefright/MetadataBufferType.h>
#include "EmulatedCameraDevice.h"
#include "CallbackNotifier.h"
+#include "JpegCompressor.h"
namespace android {
@@ -92,7 +93,9 @@
mLastFrameTimestamp(0),
mFrameRefreshFreq(0),
mMessageEnabler(0),
- mVideoRecEnabled(false)
+ mJpegQuality(90),
+ mVideoRecEnabled(false),
+ mTakingPicture(false)
{
}
@@ -194,7 +197,9 @@
mCBOpaque = NULL;
mLastFrameTimestamp = 0;
mFrameRefreshFreq = 0;
+ mJpegQuality = 90;
mVideoRecEnabled = false;
+ mTakingPicture = false;
}
void CallbackNotifier::onNextFrameAvailable(const void* frame,
@@ -213,6 +218,51 @@
LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
}
}
+
+ if (mTakingPicture) {
+ /* This happens just once. */
+ mTakingPicture = false;
+ /* The sequence of callbacks during picture taking is:
+ * - CAMERA_MSG_SHUTTER
+ * - CAMERA_MSG_RAW_IMAGE_NOTIFY
+ * - CAMERA_MSG_COMPRESSED_IMAGE
+ */
+ if (isMessageEnabled(CAMERA_MSG_SHUTTER)) {
+ mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque);
+ }
+ if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
+ mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCBOpaque);
+ }
+ if (isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE)) {
+ /* Compress the frame to JPEG. Note that when taking pictures, we
+ * have requested camera device to provide us with NV21 frames. */
+ NV21JpegCompressor compressor;
+ status_t res =
+ compressor.compressRawImage(frame, camera_dev->getFrameWidth(),
+ camera_dev->getFrameHeight(),
+ mJpegQuality);
+ if (res == NO_ERROR) {
+ camera_memory_t* jpeg_buff =
+ mGetMemoryCB(-1, compressor.getCompressedSize(), 1, NULL);
+ if (NULL != jpeg_buff && NULL != jpeg_buff->data) {
+ compressor.getCompressedImage(jpeg_buff->data);
+ mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCBOpaque);
+ jpeg_buff->release(jpeg_buff);
+ } else {
+ LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
+ }
+ } else {
+ LOGE("%s: Compression failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
+ }
+ }
+ }
+}
+
+void CallbackNotifier::onCameraDeviceError(int err)
+{
+ if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) {
+ mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCBOpaque);
+ }
}
/****************************************************************************
diff --git a/tools/emulator/system/camera/CallbackNotifier.h b/tools/emulator/system/camera/CallbackNotifier.h
index 0a595ef..63301d2 100755
--- a/tools/emulator/system/camera/CallbackNotifier.h
+++ b/tools/emulator/system/camera/CallbackNotifier.h
@@ -114,7 +114,7 @@
*/
inline int isMessageEnabled(uint msg_type)
{
- return mMessageEnabler & ~msg_type;
+ return mMessageEnabler & msg_type;
}
/* Checks id video recording is enabled.
@@ -159,6 +159,27 @@
nsecs_t timestamp,
EmulatedCameraDevice* camera_dev);
+ /* Entry point for notifications that occur in camera device.
+ * Param:
+ * err - CAMERA_ERROR_XXX error code.
+ */
+ void onCameraDeviceError(int err);
+
+ /* Sets, or resets taking picture state.
+ * This state control whether or not to notify the framework about compressed
+ * image, shutter, and other picture related events.
+ */
+ void setTakingPicture(bool taking)
+ {
+ mTakingPicture = taking;
+ }
+
+ /* Sets JPEG quality used to compress frame during picture taking. */
+ void setJpegQuality(int jpeg_quality)
+ {
+ mJpegQuality = jpeg_quality;
+ }
+
/****************************************************************************
* Private API
***************************************************************************/
@@ -197,8 +218,14 @@
/* Message enabler. */
uint32_t mMessageEnabler;
+ /* JPEG quality used to compress frame during picture taking. */
+ int mJpegQuality;
+
/* Video recording status. */
bool mVideoRecEnabled;
+
+ /* Picture taking status. */
+ bool mTakingPicture;
};
}; /* namespace android */
diff --git a/tools/emulator/system/camera/Converters.cpp b/tools/emulator/system/camera/Converters.cpp
index 797d652..f63f67f 100755
--- a/tools/emulator/system/camera/Converters.cpp
+++ b/tools/emulator/system/camera/Converters.cpp
@@ -25,24 +25,25 @@
namespace android {
-void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
+static void _YUV420SToRGB565(const uint8_t* Y,
+ const uint8_t* U,
+ const uint8_t* V,
+ int dUV,
+ uint16_t* rgb,
+ int width,
+ int height)
{
- const int pix_total = width * height;
- uint16_t* rgb_buf = reinterpret_cast<uint16_t*>(rgb);
- const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
- const uint8_t* U_pos = Y + pix_total;
- const uint8_t* V_pos = U_pos + pix_total / 4;
- const uint8_t* U = U_pos;
- const uint8_t* V = V_pos;
+ const uint8_t* U_pos = U;
+ const uint8_t* V_pos = V;
for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x += 2) {
- const uint8_t nU = *U; U++;
- const uint8_t nV = *V; V++;
- *rgb_buf = YUVToRGB565(*Y, nU, nV);
- Y++; rgb_buf++;
- *rgb_buf = YUVToRGB565(*Y, nU, nV);
- Y++; rgb_buf++;
+ for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
+ const uint8_t nU = *U;
+ const uint8_t nV = *V;
+ *rgb = YUVToRGB565(*Y, nU, nV);
+ Y++; rgb++;
+ *rgb = YUVToRGB565(*Y, nU, nV);
+ Y++; rgb++;
}
if (y & 0x1) {
U_pos = U;
@@ -54,24 +55,25 @@
}
}
-void YV12ToRGB32(const void* yv12, void* rgb, int width, int height)
+static void _YUV420SToRGB32(const uint8_t* Y,
+ const uint8_t* U,
+ const uint8_t* V,
+ int dUV,
+ uint32_t* rgb,
+ int width,
+ int height)
{
- const int pix_total = width * height;
- uint32_t* rgb_buf = reinterpret_cast<uint32_t*>(rgb);
- const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
- const uint8_t* U_pos = Y + pix_total;
- const uint8_t* V_pos = U_pos + pix_total / 4;
- const uint8_t* U = U_pos;
- const uint8_t* V = V_pos;
+ const uint8_t* U_pos = U;
+ const uint8_t* V_pos = V;
for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x += 2) {
- const uint8_t nU = *U; U++;
- const uint8_t nV = *V; V++;
- *rgb_buf = YUVToRGB32(*Y, nU, nV);
- Y++; rgb_buf++;
- *rgb_buf = YUVToRGB32(*Y, nU, nV);
- Y++; rgb_buf++;
+ for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
+ const uint8_t nU = *U;
+ const uint8_t nV = *V;
+ *rgb = YUVToRGB32(*Y, nU, nV);
+ Y++; rgb++;
+ *rgb = YUVToRGB32(*Y, nU, nV);
+ Y++; rgb++;
}
if (y & 0x1) {
U_pos = U;
@@ -83,4 +85,89 @@
}
}
+void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
+ const uint8_t* U = Y + pix_total;
+ const uint8_t* V = U + pix_total / 4;
+ _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb), width, height);
+}
+
+void YV12ToRGB32(const void* yv12, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
+ const uint8_t* V = Y + pix_total;
+ const uint8_t* U = V + pix_total / 4;
+ _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+void YU12ToRGB32(const void* yu12, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* Y = reinterpret_cast<const uint8_t*>(yu12);
+ const uint8_t* U = Y + pix_total;
+ const uint8_t* V = U + pix_total / 4;
+ _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+/* Common converter for YUV 4:2:0 interleaved to RGB565.
+ * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
+ */
+static void _NVXXToRGB565(const uint8_t* Y,
+ const uint8_t* U,
+ const uint8_t* V,
+ uint16_t* rgb,
+ int width,
+ int height)
+{
+ _YUV420SToRGB565(Y, U, V, 2, rgb, width, height);
+}
+
+/* Common converter for YUV 4:2:0 interleaved to RGB32.
+ * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
+ */
+static void _NVXXToRGB32(const uint8_t* Y,
+ const uint8_t* U,
+ const uint8_t* V,
+ uint32_t* rgb,
+ int width,
+ int height)
+{
+ _YUV420SToRGB32(Y, U, V, 2, rgb, width, height);
+}
+
+void NV12ToRGB565(const void* nv12, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
+ _NVXXToRGB565(y, y + pix_total, y + pix_total + 1,
+ reinterpret_cast<uint16_t*>(rgb), width, height);
+}
+
+void NV12ToRGB32(const void* nv12, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
+ _NVXXToRGB32(y, y + pix_total, y + pix_total + 1,
+ reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+void NV21ToRGB565(const void* nv21, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
+ _NVXXToRGB565(y, y + pix_total + 1, y + pix_total,
+ reinterpret_cast<uint16_t*>(rgb), width, height);
+}
+
+void NV21ToRGB32(const void* nv21, void* rgb, int width, int height)
+{
+ const int pix_total = width * height;
+ const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
+ _NVXXToRGB32(y, y + pix_total + 1, y + pix_total,
+ reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
}; /* namespace android */
diff --git a/tools/emulator/system/camera/Converters.h b/tools/emulator/system/camera/Converters.h
index 5cdcea2..13e2a85 100755
--- a/tools/emulator/system/camera/Converters.h
+++ b/tools/emulator/system/camera/Converters.h
@@ -17,7 +17,7 @@
#ifndef HW_EMULATOR_CAMERA_CONVERTERS_H
#define HW_EMULATOR_CAMERA_CONVERTERS_H
-#include <sys/endian.h>
+#include <endian.h>
#ifndef __BYTE_ORDER
#error "could not determine byte order"
@@ -269,6 +269,46 @@
*/
void YV12ToRGB32(const void* yv12, void* rgb, int width, int height);
+/* Converts an YU12 framebuffer to RGB32 framebuffer.
+ * Param:
+ * yu12 - YU12 framebuffer.
+ * rgb - RGB32 framebuffer.
+ * width, height - Dimensions for both framebuffers.
+ */
+void YU12ToRGB32(const void* yu12, void* rgb, int width, int height);
+
+/* Converts an NV12 framebuffer to RGB565 framebuffer.
+ * Param:
+ * nv12 - NV12 framebuffer.
+ * rgb - RGB565 framebuffer.
+ * width, height - Dimensions for both framebuffers.
+ */
+void NV12ToRGB565(const void* nv12, void* rgb, int width, int height);
+
+/* Converts an NV12 framebuffer to RGB32 framebuffer.
+ * Param:
+ * nv12 - NV12 framebuffer.
+ * rgb - RGB32 framebuffer.
+ * width, height - Dimensions for both framebuffers.
+ */
+void NV12ToRGB32(const void* nv12, void* rgb, int width, int height);
+
+/* Converts an NV21 framebuffer to RGB565 framebuffer.
+ * Param:
+ * nv21 - NV21 framebuffer.
+ * rgb - RGB565 framebuffer.
+ * width, height - Dimensions for both framebuffers.
+ */
+void NV21ToRGB565(const void* nv21, void* rgb, int width, int height);
+
+/* Converts an NV21 framebuffer to RGB32 framebuffer.
+ * Param:
+ * nv21 - NV21 framebuffer.
+ * rgb - RGB32 framebuffer.
+ * width, height - Dimensions for both framebuffers.
+ */
+void NV21ToRGB32(const void* nv21, void* rgb, int width, int height);
+
}; /* namespace android */
#endif /* HW_EMULATOR_CAMERA_CONVERTERS_H */
diff --git a/tools/emulator/system/camera/EmulatedCamera.cpp b/tools/emulator/system/camera/EmulatedCamera.cpp
index 12b9792..9cabe75 100755
--- a/tools/emulator/system/camera/EmulatedCamera.cpp
+++ b/tools/emulator/system/camera/EmulatedCamera.cpp
@@ -92,11 +92,6 @@
* Fake required parameters.
*/
- /* Only RGBX are supported by the framework for preview window in the emulator! */
- mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_RGBA8888);
- mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, "60,50,25,15,10");
- mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(10,60)");
- mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "10,60");
mParameters.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, "320x240,0x0");
mParameters.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "6");
mParameters.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-6");
@@ -109,8 +104,13 @@
mParameters.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "42.5");
mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90");
- /* Only RGB formats are supported by preview window in emulator. */
- mParameters.setPreviewFormat(CameraParameters::PIXEL_FORMAT_RGBA8888);
+ /* Preview format settings used here are related to panoramic view only. It's
+ * not related to the preview window that works only with RGB frames, which
+ * is explicitly stated when set_buffers_geometry is called on the preview
+ * window object. */
+ mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
+ CameraParameters::PIXEL_FORMAT_YUV420SP);
+ mParameters.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
/* We don't relay on the actual frame rates supported by the camera device,
* since we will emulate them through timeouts in the emulated camera device
@@ -125,8 +125,8 @@
mParameters.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
CameraParameters::PIXEL_FORMAT_YUV420P);
mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
- CameraParameters::PIXEL_FORMAT_YUV420P);
- mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_YUV420P);
+ CameraParameters::PIXEL_FORMAT_JPEG);
+ mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
/*
* Not supported features
@@ -149,6 +149,12 @@
mCallbackNotifier.onNextFrameAvailable(frame, timestamp, camera_dev);
}
+void EmulatedCamera::onCameraDeviceError(int err)
+{
+ /* Errors are reported through the callback notifier */
+ mCallbackNotifier.onCameraDeviceError(err);
+}
+
/****************************************************************************
* Camera API implementation.
***************************************************************************/
@@ -302,22 +308,77 @@
{
LOGV("%s", __FUNCTION__);
+ status_t res;
+ int width, height;
+ uint32_t org_fmt;
+
+ /* Collect frame info for the picture. */
+ mParameters.getPictureSize(&width, &height);
+ const char* pix_fmt = mParameters.getPictureFormat();
+ if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
+ org_fmt = V4L2_PIX_FMT_YUV420;
+ } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
+ org_fmt = V4L2_PIX_FMT_RGB32;
+ } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
+ org_fmt = V4L2_PIX_FMT_NV21;
+ } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_JPEG) == 0) {
+ /* We only have JPEG converted for NV21 format. */
+ org_fmt = V4L2_PIX_FMT_NV21;
+ } else {
+ LOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
+ return EINVAL;
+ }
+ /* Get JPEG quality. */
+ int jpeg_quality = mParameters.getInt(CameraParameters::KEY_JPEG_QUALITY);
+ if (jpeg_quality <= 0) {
+ jpeg_quality = 90; /* Fall back to default. */
+ }
+
/*
- * Before taking picture, pause the camera (pause worker thread), and pause
- * the preview.
+ * Make sure preview is not running, and device is stopped before taking
+ * picture.
*/
+ const bool preview_on = mPreviewWindow.isPreviewEnabled();
+ if (preview_on) {
+ doStopPreview();
+ }
+
+ /* Camera device should have been stopped when the shutter message has been
+ * enabled. */
+ EmulatedCameraDevice* const camera_dev = getCameraDevice();
+ if (camera_dev->isStarted()) {
+ LOGW("%s: Camera device is started", __FUNCTION__);
+ camera_dev->stopDeliveringFrames();
+ camera_dev->stopDevice();
+ }
+
/*
* Take the picture now.
*/
- /*
- * After picture has been taken, resume the preview, and the camera (if any
- * has been paused.
- */
+ /* Start camera device for the picture frame. */
+ LOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
+ reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
+ res = camera_dev->startDevice(width, height, org_fmt);
+ if (res != NO_ERROR) {
+ if (preview_on) {
+ doStartPreview();
+ }
+ return res;
+ }
-
- return NO_ERROR;
+ /* Deliver one frame only. */
+ mCallbackNotifier.setJpegQuality(jpeg_quality);
+ mCallbackNotifier.setTakingPicture(true);
+ res = camera_dev->startDeliveringFrames(true);
+ if (res != NO_ERROR) {
+ mCallbackNotifier.setTakingPicture(false);
+ if (preview_on) {
+ doStartPreview();
+ }
+ }
+ return res;
}
status_t EmulatedCamera::cancelPicture()
@@ -454,17 +515,70 @@
{
LOGV("%s", __FUNCTION__);
- status_t res = mPreviewWindow.startPreview();
+ EmulatedCameraDevice* camera_dev = getCameraDevice();
+ if (camera_dev->isStarted()) {
+ camera_dev->stopDeliveringFrames();
+ camera_dev->stopDevice();
+ }
- /* Start the camera. */
- if (res == NO_ERROR && !getCameraDevice()->isCapturing()) {
- res = startCamera();
+ status_t res = mPreviewWindow.startPreview();
+ if (res != NO_ERROR) {
+ return res;
+ }
+
+ /* Make sure camera device is connected. */
+ if (!camera_dev->isConnected()) {
+ res = camera_dev->connectDevice();
if (res != NO_ERROR) {
- /* If camera didn't start, disable the preview window. */
mPreviewWindow.stopPreview();
+ return res;
}
}
+ int width, height;
+ /* Lets see what should we use for frame width, and height. */
+ if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != NULL) {
+ mParameters.getVideoSize(&width, &height);
+ } else {
+ mParameters.getPreviewSize(&width, &height);
+ }
+ /* Lets see what should we use for the frame pixel format. */
+ const char* pix_fmt =
+ mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
+ if (pix_fmt == NULL) {
+ pix_fmt = mParameters.getPreviewFormat();
+ }
+ if (pix_fmt == NULL) {
+ LOGE("%s: Unable to obtain video format", __FUNCTION__);
+ mPreviewWindow.stopPreview();
+ return EINVAL;
+ }
+ uint32_t org_fmt;
+ if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
+ org_fmt = V4L2_PIX_FMT_YUV420;
+ } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
+ org_fmt = V4L2_PIX_FMT_RGB32;
+ } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
+ org_fmt = V4L2_PIX_FMT_NV21;
+ } else {
+ LOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
+ mPreviewWindow.stopPreview();
+ return EINVAL;
+ }
+ LOGD("Starting camera: %dx%d -> %.4s(%s)",
+ width, height, reinterpret_cast<const char*>(&org_fmt), pix_fmt);
+ res = camera_dev->startDevice(width, height, org_fmt);
+ if (res != NO_ERROR) {
+ mPreviewWindow.stopPreview();
+ return res;
+ }
+
+ res = camera_dev->startDeliveringFrames(false);
+ if (res != NO_ERROR) {
+ camera_dev->stopDevice();
+ mPreviewWindow.stopPreview();
+ }
+
return res;
}
@@ -473,89 +587,22 @@
LOGV("%s", __FUNCTION__);
status_t res = NO_ERROR;
- /* Stop the camera. */
- if (getCameraDevice()->isCapturing()) {
- res = stopCamera();
- }
+ if (mPreviewWindow.isPreviewEnabled()) {
+ /* Stop the camera. */
+ if (getCameraDevice()->isStarted()) {
+ getCameraDevice()->stopDeliveringFrames();
+ res = getCameraDevice()->stopDevice();
+ }
- if (res == NO_ERROR) {
- /* Disable preview as well. */
- mPreviewWindow.stopPreview();
+ if (res == NO_ERROR) {
+ /* Disable preview as well. */
+ mPreviewWindow.stopPreview();
+ }
}
return NO_ERROR;
}
-status_t EmulatedCamera::startCamera()
-{
- LOGV("%s", __FUNCTION__);
-
- status_t res = EINVAL;
- EmulatedCameraDevice* camera_dev = getCameraDevice();
- if (camera_dev != NULL) {
- if (!camera_dev->isConnected()) {
- res = camera_dev->connectDevice();
- if (res != NO_ERROR) {
- return res;
- }
- }
- if (!camera_dev->isCapturing()) {
- int width, height;
- /* Lets see what should we use for frame width, and height. */
- if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != NULL) {
- mParameters.getVideoSize(&width, &height);
- } else {
- mParameters.getPreviewSize(&width, &height);
- }
- /* Lets see what should we use for the frame pixel format. */
- const char* pix_fmt =
- mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
- if (pix_fmt == NULL) {
- pix_fmt = mParameters.getPreviewFormat();
- }
- if (pix_fmt == NULL) {
- LOGE("%s: Unable to obtain video format", __FUNCTION__);
- return EINVAL;
- }
- uint32_t org_fmt;
- if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
- org_fmt = V4L2_PIX_FMT_YVU420;
- } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
- org_fmt = V4L2_PIX_FMT_RGB32;
- } else {
- LOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
- return EINVAL;
- }
- LOGD("Starting camera: %dx%d -> %s", width, height, pix_fmt);
- res = camera_dev->startCapturing(width, height, org_fmt);
- if (res != NO_ERROR) {
- return res;
- }
- }
- }
-
- return res;
-}
-
-status_t EmulatedCamera::stopCamera()
-{
- LOGV("%s", __FUNCTION__);
-
- status_t res = NO_ERROR;
- EmulatedCameraDevice* const camera_dev = getCameraDevice();
- if (camera_dev != NULL) {
- if (camera_dev->isCapturing()) {
- res = camera_dev->stopCapturing();
- if (res != NO_ERROR) {
- return res;
- }
- }
- }
-
- return res;
-}
-
-
/****************************************************************************
* Private API.
***************************************************************************/
@@ -573,8 +620,9 @@
/* Stop and disconnect the camera device. */
EmulatedCameraDevice* const camera_dev = getCameraDevice();
if (camera_dev != NULL) {
- if (camera_dev->isCapturing()) {
- res = camera_dev->stopCapturing();
+ if (camera_dev->isStarted()) {
+ camera_dev->stopDeliveringFrames();
+ res = camera_dev->stopDevice();
if (res != NO_ERROR) {
return -res;
}
diff --git a/tools/emulator/system/camera/EmulatedCamera.h b/tools/emulator/system/camera/EmulatedCamera.h
index 77d16c9..8afdd83 100755
--- a/tools/emulator/system/camera/EmulatedCamera.h
+++ b/tools/emulator/system/camera/EmulatedCamera.h
@@ -94,6 +94,12 @@
nsecs_t timestamp,
EmulatedCameraDevice* camera_dev);
+ /* Entry point for notifications that occur in camera device.
+ * Param:
+ * err - CAMERA_ERROR_XXX error code.
+ */
+ virtual void onCameraDeviceError(int err);
+
/****************************************************************************
* Camera API implementation
***************************************************************************/
@@ -290,18 +296,6 @@
*/
virtual status_t doStopPreview();
- /* Starts capturing frames
- * Return:
- * NO_ERROR on success, or an appropriate error status on failure.
- */
- virtual status_t startCamera();
-
- /* Stops capturing frames.
- * Return:
- * NO_ERROR on success, or an appropriate error status on failure.
- */
- virtual status_t stopCamera();
-
/****************************************************************************
* Private API.
***************************************************************************/
diff --git a/tools/emulator/system/camera/EmulatedCameraDevice.cpp b/tools/emulator/system/camera/EmulatedCameraDevice.cpp
index fb9c1da..e09bead 100755
--- a/tools/emulator/system/camera/EmulatedCameraDevice.cpp
+++ b/tools/emulator/system/camera/EmulatedCameraDevice.cpp
@@ -72,16 +72,82 @@
return NO_ERROR;
}
-status_t EmulatedCameraDevice::startCapturing(int width,
- int height,
- uint32_t pix_fmt)
+status_t EmulatedCameraDevice::startDeliveringFrames(bool one_burst)
{
LOGV("%s", __FUNCTION__);
- Mutex::Autolock locker(&mObjectLock);
+ if (!isStarted()) {
+ LOGE("%s: Device is not started", __FUNCTION__);
+ return EINVAL;
+ }
+
+ /* Frames will be delivered from the thread routine. */
+ const status_t res = startWorkerThread(one_burst);
+ LOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
+ return res;
+}
+
+status_t EmulatedCameraDevice::stopDeliveringFrames()
+{
+ LOGV("%s", __FUNCTION__);
+
+ if (!isStarted()) {
+ LOGW("%s: Device is not started", __FUNCTION__);
+ return NO_ERROR;
+ }
+
+ const status_t res = stopWorkerThread();
+ LOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
+ return res;
+}
+
+status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer)
+{
+ if (!isStarted()) {
+ LOGE("%s: Device is not started", __FUNCTION__);
+ return EINVAL;
+ }
+ if (mCurrentFrame == NULL || buffer == NULL) {
+ LOGE("%s: No framebuffer", __FUNCTION__);
+ return EINVAL;
+ }
+
+ /* In emulation the framebuffer is never RGB. */
+ switch (mPixelFormat) {
+ case V4L2_PIX_FMT_YVU420:
+ YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+ return NO_ERROR;
+ case V4L2_PIX_FMT_YUV420:
+ YU12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+ return NO_ERROR;
+ case V4L2_PIX_FMT_NV21:
+ NV21ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+ return NO_ERROR;
+ case V4L2_PIX_FMT_NV12:
+ NV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+ return NO_ERROR;
+
+ default:
+ LOGE("%s: Unknown pixel format %.4s",
+ __FUNCTION__, reinterpret_cast<const char*>(&mPixelFormat));
+ return EINVAL;
+ }
+}
+
+/****************************************************************************
+ * Emulated camera device private API
+ ***************************************************************************/
+
+status_t EmulatedCameraDevice::commonStartDevice(int width,
+ int height,
+ uint32_t pix_fmt)
+{
/* Validate pixel format, and calculate framebuffer size at the same time. */
switch (pix_fmt) {
case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV12:
mFrameBufferSize = (width * height * 12) / 8;
break;
@@ -103,78 +169,20 @@
LOGE("%s: Unable to allocate framebuffer", __FUNCTION__);
return ENOMEM;
}
- /* Calculate U/V panes inside the framebuffer. */
- mFrameU = mCurrentFrame + mTotalPixels;
- mFrameV = mFrameU + mTotalPixels / 4;
-
- /* Start the camera. */
- const status_t res = startDevice();
- if (res == NO_ERROR) {
- LOGD("Camera device is started:\n"
- " Framebuffer dimensions: %dx%d.\n"
- " Pixel format: %.4s",
- mFrameWidth, mFrameHeight,
- reinterpret_cast<const char*>(&mPixelFormat));
- } else {
- delete[] mCurrentFrame;
- mCurrentFrame = NULL;
- }
-
- return res;
-}
-
-status_t EmulatedCameraDevice::stopCapturing()
-{
- LOGV("%s", __FUNCTION__);
-
- Mutex::Autolock locker(&mObjectLock);
- /* Stop the camera. */
- const status_t res = stopDevice();
- if (res == NO_ERROR) {
- /* Release resources allocated for capturing. */
- if (mCurrentFrame != NULL) {
- delete[] mCurrentFrame;
- mCurrentFrame = NULL;
- }
- }
-
- return res;
-}
-
-status_t EmulatedCameraDevice::getCurrentFrame(void* buffer)
-{
- Mutex::Autolock locker(&mObjectLock);
-
- if (!isCapturing() || mCurrentFrame == NULL) {
- LOGE("%s is called on a device that is not in the capturing state",
- __FUNCTION__);
- return EINVAL;
- }
-
- memcpy(buffer, mCurrentFrame, mFrameBufferSize);
-
+ LOGV("%s: Allocated %p %d bytes for %d pixels in %.4s[%dx%d] frame",
+ __FUNCTION__, mCurrentFrame, mFrameBufferSize, mTotalPixels,
+ reinterpret_cast<const char*>(&mPixelFormat), mFrameWidth, mFrameHeight);
return NO_ERROR;
}
-status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer)
+void EmulatedCameraDevice::commonStopDevice()
{
- Mutex::Autolock locker(&mObjectLock);
+ mFrameWidth = mFrameHeight = mTotalPixels = 0;
+ mPixelFormat = 0;
- if (!isCapturing() || mCurrentFrame == NULL) {
- LOGE("%s is called on a device that is not in the capturing state",
- __FUNCTION__);
- return EINVAL;
- }
-
- /* In emulation the framebuffer is never RGB. */
- switch (mPixelFormat) {
- case V4L2_PIX_FMT_YVU420:
- YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
- return NO_ERROR;
-
- default:
- LOGE("%s: Unknown pixel format %d", __FUNCTION__, mPixelFormat);
- return EINVAL;
+ if (mCurrentFrame != NULL) {
+ delete[] mCurrentFrame;
+ mCurrentFrame = NULL;
}
}
@@ -182,7 +190,7 @@
* Worker thread management.
***************************************************************************/
-status_t EmulatedCameraDevice::startWorkerThread()
+status_t EmulatedCameraDevice::startWorkerThread(bool one_burst)
{
LOGV("%s", __FUNCTION__);
@@ -191,11 +199,9 @@
return EINVAL;
}
- const status_t ret = getWorkerThread()->startThread();
- LOGE_IF(ret != NO_ERROR, "%s: Unable to start worker thread: %d -> %s",
- __FUNCTION__, ret, strerror(ret));
-
- return ret;
+ const status_t res = getWorkerThread()->startThread(one_burst);
+ LOGE_IF(res != NO_ERROR, "%s: Unable to start worker thread", __FUNCTION__);
+ return res;
}
status_t EmulatedCameraDevice::stopWorkerThread()
@@ -207,14 +213,15 @@
return EINVAL;
}
- getWorkerThread()->stopThread();
-
- return NO_ERROR;
+ const status_t res = getWorkerThread()->stopThread();
+ LOGE_IF(res != NO_ERROR, "%s: Unable to stop worker thread", __FUNCTION__);
+ return res;
}
bool EmulatedCameraDevice::inWorkerThread()
{
- /* This will end the thread loop, and will terminate the thread. */
+ /* This will end the thread loop, and will terminate the thread. Derived
+ * classes must override this method. */
return false;
}
@@ -268,10 +275,10 @@
LOGV("Emulated camera device's worker thread has been stopped.");
} else {
LOGE("%s: requestExitAndWait failed: %d -> %s",
- __FUNCTION__, res, strerror(res));
+ __FUNCTION__, res, strerror(-res));
}
} else {
- LOGE("%s: Unable to send THREAD_STOP: %d -> %s",
+ LOGE("%s: Unable to send THREAD_STOP message: %d -> %s",
__FUNCTION__, errno, strerror(errno));
res = errno ? errno : EINVAL;
}
diff --git a/tools/emulator/system/camera/EmulatedCameraDevice.h b/tools/emulator/system/camera/EmulatedCameraDevice.h
index b73b863..88e2dd2 100755
--- a/tools/emulator/system/camera/EmulatedCameraDevice.h
+++ b/tools/emulator/system/camera/EmulatedCameraDevice.h
@@ -69,28 +69,30 @@
* NO_ERROR on success, or an appropriate error status. If this method is
* called for already disconnected, or uninitialized instance of this class,
* a successful status must be returned from this method. If this method is
- * called for an instance that is in "capturing" state, this method must
+ * called for an instance that is in the "started" state, this method must
* return a failure.
*/
virtual status_t disconnectDevice() = 0;
-protected:
- /* Starts capturing frames from the camera device.
- *
- * Typically, this method initializes the camera device with the settings
- * requested by the framework through the camera HAL, and starts a worker
- * thread that will listen to the physical device for available frames. When
- * new frame becomes available, it will be cached in current_framebuffer_,
- * and the containing emulated camera object will be notified via call to
- * its onNextFrameAvailable method. This method must be called on a
- * connected instance of this class. If it is called on a disconnected
- * instance, this method must return a failure.
+ /* Starts the camera device.
+ * This method tells the camera device to start capturing frames of the given
+ * dimensions for the given pixel format. Note that this method doesn't start
+ * the delivery of the captured frames to the emulated camera. Call
+ * startDeliveringFrames method to start delivering frames. This method must
+ * be called on a connected instance of this class. If it is called on a
+ * disconnected instance, this method must return a failure.
+ * Param:
+ * width, height - Frame dimensions to use when capturing video frames.
+ * pix_fmt - Pixel format to use when capturing video frames.
* Return:
* NO_ERROR on success, or an appropriate error status.
*/
- virtual status_t startDevice() = 0;
+ virtual status_t startDevice(int width, int height, uint32_t pix_fmt) = 0;
- /* Stops capturing frames from the camera device.
+ /* Stops the camera device.
+ * This method tells the camera device to stop capturing frames. Note that
+ * this method doesn't stop delivering frames to the emulated camera. Always
+ * call stopDeliveringFrames prior to calling this method.
* Return:
* NO_ERROR on success, or an appropriate error status. If this method is
* called for an object that is not capturing frames, or is disconnected,
@@ -114,79 +116,95 @@
*/
virtual status_t Initialize();
- /* Starts capturing frames from the camera device.
- *
- * Typically, this method caches desired frame parameters, and calls
- * startDevice method to start capturing video frames from the camera
- * device. This method must be called on a connected instance of this class.
- * If it is called on a disconnected instance, this method must return a
- * failure.
+ /* Starts delivering frames captured from the camera device.
+ * This method will start the worker thread that would be pulling frames from
+ * the camera device, and will deliver the pulled frames back to the emulated
+ * camera via onNextFrameAvailable callback. This method must be called on a
+ * connected instance of this class with a started camera device. If it is
+ * called on a disconnected instance, or camera device has not been started,
+ * this method must return a failure.
+ * Param:
+ * one_burst - Controls how many frames should be delivered. If this
+ * parameter is 'true', only one captured frame will be delivered to the
+ * emulated camera. If this parameter is 'false', frames will keep
+ * coming until stopDeliveringFrames method is called. Typically, this
+ * parameter is set to 'true' only in order to obtain a single frame
+ * that will be used as a "picture" in takePicture method of the
+ * emulated camera.
* Return:
* NO_ERROR on success, or an appropriate error status.
*/
- virtual status_t startCapturing(int width, int height, uint32_t pix_fmt);
+ virtual status_t startDeliveringFrames(bool one_burst);
- /* Stops capturing frames from the camera device.
- *
- * Typically, this method calls stopDevice method of this class, and
- * uninitializes frame properties, saved in StartCapturing method of this
- * class.
- * This method must be called on a connected instance of this class. If it
- * is called on a disconnected instance, this method must return a failure.
+ /* Stops delivering frames captured from the camera device.
+ * This method will stop the worker thread started by startDeliveringFrames.
* Return:
* NO_ERROR on success, or an appropriate error status.
*/
- virtual status_t stopCapturing();
+ virtual status_t stopDeliveringFrames();
- /* Gets current fame into provided buffer.
- * Typically, this method is called by the emulated camera (HAL) in response
- * to a callback from the emulated camera device that gets invoked when new
- * captured frame is available.
- * This method must be called on an instance that is capturing frames from
- * the physical device. If this method is called on an instance that is not
- * capturing frames from the physical device, it must return a failure.
+ /* Gets current framebuffer, converted into preview frame format.
+ * This method must be called on a connected instance of this class with a
+ * started camera device. If it is called on a disconnected instance, or
+ * camera device has not been started, this method must return a failure.
+ * Note that this method should be called only after at least one frame has
+ * been captured and delivered. Otherwise it will return garbage in the
+ * preview frame buffer. Typically, this method shuld be called from
+ * onNextFrameAvailable callback.
* Param:
- * buffer - A buffer where to return the frame. Note that the buffer must be
- * large enough to contain the entire frame, as defined by frame's width,
- * height, and pixel format that are current for the camera device.
- */
- virtual status_t getCurrentFrame(void* buffer);
-
- /* Gets current preview fame into provided buffer.
- * Param:
- * buffer - A buffer where to return the preview frame. Note that the buffer
- * must be large enough to contain the entire preview frame, as defined
- * by frame's width, height, and preview pixel format. Note also, that
- * due to the the limitations of the camera framework in emulator, the
- * preview frame is always formatted with RGBA8888.
+ * buffer - Buffer, large enough to contain the entire preview frame.
+ * Return:
+ * NO_ERROR on success, or an appropriate error status.
*/
virtual status_t getCurrentPreviewFrame(void* buffer);
- /* Gets width of the frame obtained from the physical device. */
+ /* Gets width of the frame obtained from the physical device.
+ * Return:
+ * Width of the frame obtained from the physical device. Note that value
+ * returned from this method is valid only in case if camera device has been
+ * started.
+ */
inline int getFrameWidth() const
{
+ LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
return mFrameWidth;
}
- /* Gets height of the frame obtained from the physical device. */
+ /* Gets height of the frame obtained from the physical device.
+ * Return:
+ * Height of the frame obtained from the physical device. Note that value
+ * returned from this method is valid only in case if camera device has been
+ * started.
+ */
inline int getFrameHeight() const
{
+ LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
return mFrameHeight;
}
- /* Gets byte size of the current frame buffer. */
+ /* Gets byte size of the current frame buffer.
+ * Return:
+ * Byte size of the frame buffer. Note that value returned from this method
+ * is valid only in case if camera device has been started.
+ */
inline size_t getFrameBufferSize() const
{
+ LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
return mFrameBufferSize;
}
- /* Gets number of pixels in the current frame buffer. */
+ /* Gets number of pixels in the current frame buffer.
+ * Return:
+ * Number of pixels in the frame buffer. Note that value returned from this
+ * method is valid only in case if camera device has been started.
+ */
inline int getPixelNum() const
{
+ LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
return mTotalPixels;
}
- /* Gets pixel format of the frame that physical device streams.
+ /* Gets pixel format of the frame that camera device streams to this class.
* Throughout camera framework, there are three different forms of pixel
* format representation:
* - Original format, as reported by the actual camera device. Values for
@@ -198,17 +216,17 @@
* pixel format in the original form. And that's the pixel format
* representation that will be returned from this method. HAL components will
* need to translate value returned from this method to the appropriate form.
- * This method must be called only on connected instance of this class, since
- * it's applicable only when physical device is ready to stream frames. If
- * this method is called on an instance that is not connected, it must return
- * a failure.
+ * This method must be called only on started instance of this class, since
+ * it's applicable only when camera device is ready to stream frames.
* Param:
* pix_fmt - Upon success contains the original pixel format.
* Return:
- * Current framebuffer's pixel format.
+ * Current framebuffer's pixel format. Note that value returned from this
+ * method is valid only in case if camera device has been started.
*/
inline uint32_t getOriginalPixelFormat() const
{
+ LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
return mPixelFormat;
}
@@ -222,16 +240,32 @@
return mWorkerThread.get() != NULL && mState != ECDS_CONSTRUCTED;
}
inline bool isConnected() const {
- /* Instance is connected when it is initialized and its status is either
- * "connected", or "capturing". */
- return isInitialized() &&
- (mState == ECDS_CONNECTED || mState == ECDS_CAPTURING);
+ /* Instance is connected when its status is either"connected", or
+ * "started". */
+ return mState == ECDS_CONNECTED || mState == ECDS_STARTED;
}
- inline bool isCapturing() const {
- return isInitialized() && mState == ECDS_CAPTURING;
+ inline bool isStarted() const {
+ return mState == ECDS_STARTED;
}
/****************************************************************************
+ * Emulated camera device private API
+ ***************************************************************************/
+protected:
+ /* Performs common validation and calculation of startDevice parameters.
+ * Param:
+ * width, height, pix_fmt - Parameters passed to the startDevice method.
+ * Return:
+ * NO_ERROR on success, or an appropriate error status.
+ */
+ virtual status_t commonStartDevice(int width, int height, uint32_t pix_fmt);
+
+ /* Performs common cleanup on stopDevice.
+ * This method will undo what commonStartDevice had done.
+ */
+ virtual void commonStopDevice();
+
+ /****************************************************************************
* Worker thread management.
* Typicaly when emulated camera device starts capturing frames from the
* actual device, it does that in a worker thread created in StartCapturing,
@@ -242,15 +276,22 @@
protected:
/* Starts the worker thread.
- * Typically, worker thread is started from StartCamera method of this
- * class.
+ * Typically, worker thread is started from startDeliveringFrames method of
+ * this class.
+ * Param:
+ * one_burst - Controls how many times thread loop should run. If this
+ * parameter is 'true', thread routine will run only once If this
+ * parameter is 'false', thread routine will run until stopWorkerThread
+ * method is called. See startDeliveringFrames for more info.
* Return:
* NO_ERROR on success, or an appropriate error status.
*/
- virtual status_t startWorkerThread();
+ virtual status_t startWorkerThread(bool one_burst);
/* Stops the worker thread.
* Note that this method will always wait for the worker thread to terminate.
+ * Typically, worker thread is started from stopDeliveringFrames method of
+ * this class.
* Return:
* NO_ERROR on success, or an appropriate error status.
*/
@@ -260,7 +301,7 @@
* In the default implementation of the worker thread routine we simply
* return 'false' forcing the thread loop to exit, and the thread to
* terminate. Derived class should override that method to provide there the
- * actual frame capturing functionality.
+ * actual frame delivery.
* Return:
* true To continue thread loop (this method will be called again), or false
* to exit the thread loop and to terminate the thread.
@@ -298,9 +339,19 @@
}
}
- /* Starts the thread */
- inline status_t startThread()
+ /* Starts the thread
+ * Param:
+ * one_burst - Controls how many times thread loop should run. If
+ * this parameter is 'true', thread routine will run only once
+ * If this parameter is 'false', thread routine will run until
+ * stopThread method is called. See startWorkerThread for more
+ * info.
+ * Return:
+ * NO_ERROR on success, or an appropriate error status.
+ */
+ inline status_t startThread(bool one_burst)
{
+ mOneBurst = one_burst;
return run(NULL, ANDROID_PRIORITY_URGENT_DISPLAY, 0);
}
@@ -343,10 +394,15 @@
private:
/* Implements abstract method of the base Thread class. */
- inline bool threadLoop()
+ bool threadLoop()
{
/* Simply dispatch the call to the containing camera device. */
- return mCameraDevice->inWorkerThread();
+ if (mCameraDevice->inWorkerThread()) {
+ /* Respect "one burst" parameter (see startThread). */
+ return !mOneBurst;
+ } else {
+ return false;
+ }
}
/* Containing camera device object. */
@@ -358,6 +414,10 @@
/* FD that thread uses to receive control messages. */
int mControlFD;
+ /* Controls number of times the thread loop runs.
+ * See startThread for more information. */
+ bool mOneBurst;
+
/* Enumerates control messages that can be sent into the thread. */
enum ControlMessage {
/* Stop the thread. */
@@ -391,12 +451,6 @@
/* Framebuffer containing the current frame. */
uint8_t* mCurrentFrame;
- /* U panel inside the framebuffer. */
- uint8_t* mFrameU;
-
- /* V panel inside the framebuffer. */
- uint8_t* mFrameV;
-
/*
* Framebuffer properties.
*/
@@ -426,8 +480,8 @@
ECDS_INITIALIZED,
/* Object has been connected to the physical device. */
ECDS_CONNECTED,
- /* Frames are being captured. */
- ECDS_CAPTURING,
+ /* Camera device has been started. */
+ ECDS_STARTED,
};
/* Object state. */
diff --git a/tools/emulator/system/camera/EmulatedCameraFactory.cpp b/tools/emulator/system/camera/EmulatedCameraFactory.cpp
index d6ba9b4..5c5c5de 100755
--- a/tools/emulator/system/camera/EmulatedCameraFactory.cpp
+++ b/tools/emulator/system/camera/EmulatedCameraFactory.cpp
@@ -22,6 +22,7 @@
#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_Factory"
#include <cutils/log.h>
+#include <cutils/properties.h>
#include "EmulatedQemuCamera.h"
#include "EmulatedFakeCamera.h"
#include "EmulatedCameraFactory.h"
@@ -43,9 +44,8 @@
mConstructedOK(false)
{
- /* If qemu camera emulation is on, try to connect to the factory service in
- * the emulator. */
- if (isQemuCameraEmulationOn() && mQemuClient.connectClient(NULL) == NO_ERROR) {
+ /* Connect to the factory service in the emulator, and create Qemu cameras. */
+ if (mQemuClient.connectClient(NULL) == NO_ERROR) {
/* Connection has succeeded. Create emulated cameras for each camera
* device, reported by the service. */
createQemuCameras();
@@ -82,6 +82,8 @@
mFakeCameraID = -1;
LOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
}
+ } else {
+ LOGD("Fake camera emulation is disabled.");
}
LOGV("%d cameras are being emulated. Fake camera ID is %d",
@@ -121,7 +123,7 @@
return -EINVAL;
}
- if (camera_id >= getEmulatedCameraNum()) {
+ if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
LOGE("%s: Camera id %d is out of bounds (%d)",
__FUNCTION__, camera_id, getEmulatedCameraNum());
return -EINVAL;
@@ -139,7 +141,7 @@
return -EINVAL;
}
- if (camera_id >= getEmulatedCameraNum()) {
+ if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
LOGE("%s: Camera id %d is out of bounds (%d)",
__FUNCTION__, camera_id, getEmulatedCameraNum());
return -EINVAL;
@@ -197,6 +199,8 @@
static const char lListNameToken[] = "name=";
/* Frame dimensions token. */
static const char lListDimsToken[] = "framedims=";
+/* Facing direction token. */
+static const char lListDirToken[] = "dir=";
void EmulatedCameraFactory::createQemuCameras()
{
@@ -252,13 +256,15 @@
next_entry++; // Start of the next entry.
}
- /* Find 'name', and 'framedims' tokens that are required here. */
+ /* Find 'name', 'framedims', and 'dir' tokens that are required here. */
char* name_start = strstr(cur_entry, lListNameToken);
char* dim_start = strstr(cur_entry, lListDimsToken);
- if (name_start != NULL && dim_start != NULL) {
+ char* dir_start = strstr(cur_entry, lListDirToken);
+ if (name_start != NULL && dim_start != NULL && dir_start != NULL) {
/* Advance to the token values. */
name_start += strlen(lListNameToken);
dim_start += strlen(lListDimsToken);
+ dir_start += strlen(lListDirToken);
/* Terminate token values with zero. */
char* s = strchr(name_start, ' ');
@@ -269,12 +275,16 @@
if (s != NULL) {
*s = '\0';
}
+ s = strchr(dir_start, ' ');
+ if (s != NULL) {
+ *s = '\0';
+ }
/* Create and initialize qemu camera. */
EmulatedQemuCamera* qemu_cam =
new EmulatedQemuCamera(index, &HAL_MODULE_INFO_SYM.common);
if (NULL != qemu_cam) {
- res = qemu_cam->Initialize(name_start, dim_start);
+ res = qemu_cam->Initialize(name_start, dim_start, dir_start);
if (res == NO_ERROR) {
mEmulatedCameras[index] = qemu_cam;
index++;
@@ -295,16 +305,17 @@
mEmulatedCameraNum = index;
}
-bool EmulatedCameraFactory::isQemuCameraEmulationOn()
-{
- /* TODO: Have a boot property that controls that! */
- return true;
-}
-
bool EmulatedCameraFactory::isFakeCameraEmulationOn()
{
- /* TODO: Have a boot property that controls that! */
- return true;
+ /* Defined by 'qemu.sf.fake_camera' boot property: If property is there
+ * and contains 'off', fake camera emulation is disabled. */
+ char prop[PROPERTY_VALUE_MAX];
+ if (property_get("qemu.sf.fake_camera", prop, NULL) <= 0 ||
+ strcmp(prop, "off")) {
+ return true;
+ } else {
+ return false;
+ }
}
/********************************************************************************
diff --git a/tools/emulator/system/camera/EmulatedCameraFactory.h b/tools/emulator/system/camera/EmulatedCameraFactory.h
index 1e40d82..19745a3 100755
--- a/tools/emulator/system/camera/EmulatedCameraFactory.h
+++ b/tools/emulator/system/camera/EmulatedCameraFactory.h
@@ -94,11 +94,6 @@
***************************************************************************/
public:
- /* Gets fake camera facing. */
- int getFakeCameraFacing() {
- /* TODO: Have a boot property that controls that. */
- return CAMERA_FACING_BACK;
- }
/* Gets fake camera orientation. */
int getFakeCameraOrientation() {
@@ -106,12 +101,6 @@
return 90;
}
- /* Gets qemu camera facing. */
- int getQemuCameraFacing() {
- /* TODO: Have a boot property that controls that. */
- return CAMERA_FACING_FRONT;
- }
-
/* Gets qemu camera orientation. */
int getQemuCameraOrientation() {
/* TODO: Have a boot property that controls that. */
@@ -142,9 +131,6 @@
*/
void createQemuCameras();
- /* Checks if qemu camera emulation is on. */
- bool isQemuCameraEmulationOn();
-
/* Checks if fake camera emulation is on. */
bool isFakeCameraEmulationOn();
diff --git a/tools/emulator/system/camera/EmulatedFakeCamera.cpp b/tools/emulator/system/camera/EmulatedFakeCamera.cpp
index 84828cf..d82fd78 100755
--- a/tools/emulator/system/camera/EmulatedFakeCamera.cpp
+++ b/tools/emulator/system/camera/EmulatedFakeCamera.cpp
@@ -22,6 +22,7 @@
#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_FakeCamera"
#include <cutils/log.h>
+#include <cutils/properties.h>
#include "EmulatedFakeCamera.h"
#include "EmulatedCameraFactory.h"
@@ -48,11 +49,13 @@
return res;
}
- const char* facing = EmulatedCamera::FACING_BACK;
- if (gEmulatedCameraFactory.getFakeCameraOrientation() == CAMERA_FACING_FRONT) {
- facing = EmulatedCamera::FACING_FRONT;
- }
+ /* Fake camera facing is defined by the qemu.sf.fake_camera boot property. */
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("qemu.sf.fake_camera", prop, EmulatedCamera::FACING_BACK);
+ const char* facing = prop;
+
mParameters.set(EmulatedCamera::FACING_KEY, facing);
+ LOGD("%s: Fake camera is facing %s", __FUNCTION__, facing);
mParameters.set(EmulatedCamera::ORIENTATION_KEY,
gEmulatedCameraFactory.getFakeCameraOrientation());
diff --git a/tools/emulator/system/camera/EmulatedFakeCamera.h b/tools/emulator/system/camera/EmulatedFakeCamera.h
index f8a8099..3debe9e 100755
--- a/tools/emulator/system/camera/EmulatedFakeCamera.h
+++ b/tools/emulator/system/camera/EmulatedFakeCamera.h
@@ -45,11 +45,7 @@
***************************************************************************/
public:
- /* Initializes EmulatedFakeCamera instance.
- * The contained EmulatedFakeCameraDevice will be initialized in this method.
- * Return:
- * NO_ERROR on success, or an appropriate error statsu on failure.
- */
+ /* Initializes EmulatedFakeCamera instance. */
status_t Initialize();
/****************************************************************************
diff --git a/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp b/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
index a6c97c6..53a5b1b 100755
--- a/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
+++ b/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
@@ -34,9 +34,15 @@
mRedYUV(kRed8),
mGreenYUV(kGreen8),
mBlueYUV(kBlue8),
+ mLastRedrawn(0),
mCheckX(0),
mCheckY(0),
mCcounter(0)
+#if EFCD_ROTATE_FRAME
+ , mLastRotatedAt(0),
+ mCurrentFrameType(0),
+ mCurrentColor(&mWhiteYUV)
+#endif // EFCD_ROTATE_FRAME
{
}
@@ -62,6 +68,7 @@
return NO_ERROR;
}
+ /* There is no device to connect to. */
mState = ECDS_CONNECTED;
return NO_ERROR;
@@ -76,57 +83,99 @@
LOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
return NO_ERROR;
}
- if (isCapturing()) {
- LOGE("%s: Cannot disconnect while in the capturing state.", __FUNCTION__);
+ if (isStarted()) {
+ LOGE("%s: Cannot disconnect from the started device.", __FUNCTION__);
return EINVAL;
}
+ /* There is no device to disconnect from. */
mState = ECDS_INITIALIZED;
return NO_ERROR;
}
-status_t EmulatedFakeCameraDevice::startDevice()
+status_t EmulatedFakeCameraDevice::startDevice(int width,
+ int height,
+ uint32_t pix_fmt)
{
LOGV("%s", __FUNCTION__);
+ Mutex::Autolock locker(&mObjectLock);
if (!isConnected()) {
LOGE("%s: Fake camera device is not connected.", __FUNCTION__);
return EINVAL;
}
- if (isCapturing()) {
- LOGW("%s: Fake camera device is already capturing.", __FUNCTION__);
- return NO_ERROR;
+ if (isStarted()) {
+ LOGE("%s: Fake camera device is already started.", __FUNCTION__);
+ return EINVAL;
}
- /* Used in calculating U/V position when drawing the square. */
- mHalfWidth = mFrameWidth / 2;
+ /* Initialize the base class. */
+ const status_t res =
+ EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
+ if (res == NO_ERROR) {
+ /* Calculate U/V panes inside the framebuffer. */
+ switch (mPixelFormat) {
+ case V4L2_PIX_FMT_YVU420:
+ mFrameV = mCurrentFrame + mTotalPixels;
+ mFrameU = mFrameU + mTotalPixels / 4;
+ mUVStep = 1;
+ mUVTotalNum = mTotalPixels / 4;
+ break;
- /* Just start the worker thread: there is no real device to deal with. */
- const status_t ret = startWorkerThread();
- if (ret == NO_ERROR) {
- mState = ECDS_CAPTURING;
+ case V4L2_PIX_FMT_YUV420:
+ mFrameU = mCurrentFrame + mTotalPixels;
+ mFrameV = mFrameU + mTotalPixels / 4;
+ mUVStep = 1;
+ mUVTotalNum = mTotalPixels / 4;
+ break;
+
+ case V4L2_PIX_FMT_NV21:
+ /* Interleaved UV pane, V first. */
+ mFrameV = mCurrentFrame + mTotalPixels;
+ mFrameU = mFrameV + 1;
+ mUVStep = 2;
+ mUVTotalNum = mTotalPixels / 4;
+ break;
+
+ case V4L2_PIX_FMT_NV12:
+ /* Interleaved UV pane, U first. */
+ mFrameU = mCurrentFrame + mTotalPixels;
+ mFrameV = mFrameU + 1;
+ mUVStep = 2;
+ mUVTotalNum = mTotalPixels / 4;
+ break;
+
+ default:
+ LOGE("%s: Unknown pixel format %.4s", __FUNCTION__,
+ reinterpret_cast<const char*>(&mPixelFormat));
+ return EINVAL;
+ }
+ /* Number of items in a single row inside U/V panes. */
+ mUVInRow = (width / 2) * mUVStep;
+ mState = ECDS_STARTED;
+ } else {
+ LOGE("%s: commonStartDevice failed", __FUNCTION__);
}
- return ret;
+ return res;
}
status_t EmulatedFakeCameraDevice::stopDevice()
{
LOGV("%s", __FUNCTION__);
- if (!isCapturing()) {
- LOGW("%s: Fake camera device is not capturing.", __FUNCTION__);
+ Mutex::Autolock locker(&mObjectLock);
+ if (!isStarted()) {
+ LOGW("%s: Fake camera device is not started.", __FUNCTION__);
return NO_ERROR;
}
- /* Just stop the worker thread: there is no real device to deal with. */
- const status_t ret = stopWorkerThread();
- if (ret == NO_ERROR) {
- mState = ECDS_CONNECTED;
- }
+ mFrameU = mFrameV = NULL;
+ EmulatedCameraDevice::commonStopDevice();
+ mState = ECDS_CONNECTED;
- return ret;
+ return NO_ERROR;
}
/****************************************************************************
@@ -144,23 +193,31 @@
}
/* Lets see if we need to generate a new frame. */
- if ((systemTime(SYSTEM_TIME_MONOTONIC) - mCurFrameTimestamp) >= mRedrawAfter) {
+ if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRedrawn) >= mRedrawAfter) {
/*
* Time to generate a new frame.
*/
+#if EFCD_ROTATE_FRAME
+ const int frame_type = rotateFrame();
+ switch (frame_type) {
+ case 0:
+ drawCheckerboard();
+ break;
+ case 1:
+ drawStripes();
+ break;
+ case 2:
+ drawSolid(mCurrentColor);
+ break;
+ }
+#else
/* Draw the checker board. */
drawCheckerboard();
- /* Run the square. */
- int x = ((mCcounter * 3) & 255);
- if(x > 128) x = 255 - x;
- int y = ((mCcounter * 5) & 255);
- if(y > 128) y = 255 - y;
- const int size = mFrameWidth / 10;
- drawSquare(x * size / 32, y * size / 32, (size * 5) >> 1,
- (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
- mCcounter++;
+#endif // EFCD_ROTATE_FRAME
+
+ mLastRedrawn = systemTime(SYSTEM_TIME_MONOTONIC);
}
/* Timestamp the current frame, and notify the camera HAL about new frame. */
@@ -202,7 +259,7 @@
mWhiteYUV.get(Y, U, V);
}
Y[1] = *Y;
- Y += 2; U++; V++;
+ Y += 2; U += mUVStep; V += mUVStep;
countx += 2;
if(countx >= size) {
countx = 0;
@@ -223,6 +280,16 @@
}
mCheckX += 3;
mCheckY++;
+
+ /* Run the square. */
+ int sqx = ((mCcounter * 3) & 255);
+ if(sqx > 128) sqx = 255 - sqx;
+ int sqy = ((mCcounter * 5) & 255);
+ if(sqy > 128) sqy = 255 - sqy;
+ const int sqsize = mFrameWidth / 10;
+ drawSquare(sqx * sqsize / 32, sqy * sqsize / 32, (sqsize * 5) >> 1,
+ (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
+ mCcounter++;
}
void EmulatedFakeCameraDevice::drawSquare(int x,
@@ -230,24 +297,115 @@
int size,
const YUVPixel* color)
{
- const int half_x = x / 2;
- const int square_xstop = min(mFrameWidth, x+size);
- const int square_ystop = min(mFrameHeight, y+size);
+ const int square_xstop = min(mFrameWidth, x + size);
+ const int square_ystop = min(mFrameHeight, y + size);
uint8_t* Y_pos = mCurrentFrame + y * mFrameWidth + x;
// Draw the square.
for (; y < square_ystop; y++) {
- const int iUV = (y / 2) * mHalfWidth + half_x;
+ const int iUV = (y / 2) * mUVInRow + (x / 2) * mUVStep;
uint8_t* sqU = mFrameU + iUV;
uint8_t* sqV = mFrameV + iUV;
uint8_t* sqY = Y_pos;
for (int i = x; i < square_xstop; i += 2) {
color->get(sqY, sqU, sqV);
sqY[1] = *sqY;
- sqY += 2; sqU++; sqV++;
+ sqY += 2; sqU += mUVStep; sqV += mUVStep;
}
Y_pos += mFrameWidth;
}
}
+#if EFCD_ROTATE_FRAME
+
+void EmulatedFakeCameraDevice::drawSolid(YUVPixel* color)
+{
+ /* All Ys are the same. */
+ memset(mCurrentFrame, color->Y, mTotalPixels);
+
+ /* Fill U, and V panes. */
+ uint8_t* U = mFrameU;
+ uint8_t* V = mFrameV;
+ for (int k = 0; k < mUVTotalNum; k++, U += mUVStep, V += mUVStep) {
+ *U = color->U;
+ *V = color->V;
+ }
+}
+
+void EmulatedFakeCameraDevice::drawStripes()
+{
+ /* Divide frame into 4 stripes. */
+ const int change_color_at = mFrameHeight / 4;
+ const int each_in_row = mUVInRow / mUVStep;
+ uint8_t* pY = mCurrentFrame;
+ for (int y = 0; y < mFrameHeight; y++, pY += mFrameWidth) {
+ /* Select the color. */
+ YUVPixel* color;
+ const int color_index = y / change_color_at;
+ if (color_index == 0) {
+ /* White stripe on top. */
+ color = &mWhiteYUV;
+ } else if (color_index == 1) {
+ /* Then the red stripe. */
+ color = &mRedYUV;
+ } else if (color_index == 2) {
+ /* Then the green stripe. */
+ color = &mGreenYUV;
+ } else {
+ /* And the blue stripe at the bottom. */
+ color = &mBlueYUV;
+ }
+
+ /* All Ys at the row are the same. */
+ memset(pY, color->Y, mFrameWidth);
+
+ /* Offset of the current row inside U/V panes. */
+ const int uv_off = (y / 2) * mUVInRow;
+ /* Fill U, and V panes. */
+ uint8_t* U = mFrameU + uv_off;
+ uint8_t* V = mFrameV + uv_off;
+ for (int k = 0; k < each_in_row; k++, U += mUVStep, V += mUVStep) {
+ *U = color->U;
+ *V = color->V;
+ }
+ }
+}
+
+int EmulatedFakeCameraDevice::rotateFrame()
+{
+ if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRotatedAt) >= mRotateFreq) {
+ mLastRotatedAt = systemTime(SYSTEM_TIME_MONOTONIC);
+ mCurrentFrameType++;
+ if (mCurrentFrameType > 2) {
+ mCurrentFrameType = 0;
+ }
+ if (mCurrentFrameType == 2) {
+ LOGD("********** Rotated to the SOLID COLOR frame **********");
+ /* Solid color: lets rotate color too. */
+ if (mCurrentColor == &mWhiteYUV) {
+ LOGD("----- Painting a solid RED frame -----");
+ mCurrentColor = &mRedYUV;
+ } else if (mCurrentColor == &mRedYUV) {
+ LOGD("----- Painting a solid GREEN frame -----");
+ mCurrentColor = &mGreenYUV;
+ } else if (mCurrentColor == &mGreenYUV) {
+ LOGD("----- Painting a solid BLUE frame -----");
+ mCurrentColor = &mBlueYUV;
+ } else {
+ /* Back to white. */
+ LOGD("----- Painting a solid WHITE frame -----");
+ mCurrentColor = &mWhiteYUV;
+ }
+ } else if (mCurrentFrameType == 0) {
+ LOGD("********** Rotated to the CHECKERBOARD frame **********");
+ } else {
+ LOGD("********** Rotated to the STRIPED frame **********");
+ }
+ }
+
+ return mCurrentFrameType;
+}
+
+#endif // EFCD_ROTATE_FRAME
+
}; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedFakeCameraDevice.h b/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
index c9f13ea..f54127e 100755
--- a/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
+++ b/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
@@ -25,6 +25,15 @@
#include "Converters.h"
#include "EmulatedCameraDevice.h"
+/* This is used for debugging format / conversion issues. If EFCD_ROTATE_FRAME is
+ * set to 0, the frame content will be always the "checkerboard". Otherwise, if
+ * EFCD_ROTATE_FRAME is set to a non-zero value, the frame content will "rotate"
+ * from a "checkerboard" frame to a "white/red/green/blue stripes" frame, to a
+ * "white/red/green/blue" frame. Frame content rotation helps finding bugs in
+ * format conversions.
+ */
+#define EFCD_ROTATE_FRAME 1
+
namespace android {
class EmulatedFakeCamera;
@@ -62,19 +71,15 @@
*/
status_t disconnectDevice();
-protected:
- /* Starts capturing frames from the camera device.
- * Since there is no real device to control, this method simply starts the
- * worker thread, and changes the state.
- */
- status_t startDevice();
+ /* Starts the camera device. */
+ status_t startDevice(int width, int height, uint32_t pix_fmt);
- /* Stops capturing frames from the camera device.
- * Since there is no real device to control, this method simply stops the
- * worker thread, and changes the state.
- */
+ /* Stops the camera device. */
status_t stopDevice();
+ /* Gets current preview fame into provided buffer. */
+ status_t getPreviewFrame(void* buffer);
+
/***************************************************************************
* Worker thread management overrides.
* See declarations of these methods in EmulatedCameraDevice class for
@@ -83,8 +88,8 @@
protected:
/* Implementation of the worker thread routine.
- * This method simply sleeps for a period of time defined by FPS property of
- * the fake camera (simulating frame frequency), and then calls emulated
+ * This method simply sleeps for a period of time defined by the FPS property
+ * of the fake camera (simulating frame frequency), and then calls emulated
* camera's onNextFrameAvailable method.
*/
bool inWorkerThread();
@@ -105,6 +110,12 @@
*/
void drawSquare(int x, int y, int size, const YUVPixel* color);
+#if EFCD_ROTATE_FRAME
+ void drawSolid(YUVPixel* color);
+ void drawStripes();
+ int rotateFrame();
+#endif // EFCD_ROTATE_FRAME
+
/****************************************************************************
* Fake camera device data members
***************************************************************************/
@@ -120,14 +131,37 @@
YUVPixel mGreenYUV;
YUVPixel mBlueYUV;
+ /* Last time the frame has been redrawn. */
+ nsecs_t mLastRedrawn;
+
/*
- * Drawing related stuff
+ * Precalculated values related to U/V panes.
+ */
+
+ /* U pane inside the framebuffer. */
+ uint8_t* mFrameU;
+
+ /* V pane inside the framebuffer. */
+ uint8_t* mFrameV;
+
+ /* Defines byte distance between adjacent U, and V values. */
+ int mUVStep;
+
+ /* Defines number of Us and Vs in a row inside the U/V panes.
+ * Note that if U/V panes are interleaved, this value reflects the total
+ * number of both, Us and Vs in a single row in the interleaved UV pane. */
+ int mUVInRow;
+
+ /* Total number of each, U, and V elements in the framebuffer. */
+ int mUVTotalNum;
+
+ /*
+ * Checkerboard drawing related stuff
*/
int mCheckX;
int mCheckY;
int mCcounter;
- int mHalfWidth;
/* Emulated FPS (frames per second).
* We will emulate 50 FPS. */
@@ -136,6 +170,25 @@
/* Defines time (in nanoseconds) between redrawing the checker board.
* We will redraw the checker board every 15 milliseconds. */
static const nsecs_t mRedrawAfter = 15000000LL;
+
+#if EFCD_ROTATE_FRAME
+ /* Frame rotation frequency in nanosec (currently - 3 sec) */
+ static const nsecs_t mRotateFreq = 3000000000LL;
+
+ /* Last time the frame has rotated. */
+ nsecs_t mLastRotatedAt;
+
+ /* Type of the frame to display in the current rotation:
+ * 0 - Checkerboard.
+ * 1 - White/Red/Green/Blue horisontal stripes
+ * 2 - Solid color. */
+ int mCurrentFrameType;
+
+ /* Color to use to paint the solid color frame. Colors will rotate between
+ * white, red, gree, and blue each time rotation comes to the solid color
+ * frame. */
+ YUVPixel* mCurrentColor;
+#endif // EFCD_ROTATE_FRAME
};
}; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedQemuCamera.cpp b/tools/emulator/system/camera/EmulatedQemuCamera.cpp
index 5c98ae6..611b6b5 100755
--- a/tools/emulator/system/camera/EmulatedQemuCamera.cpp
+++ b/tools/emulator/system/camera/EmulatedQemuCamera.cpp
@@ -42,8 +42,11 @@
***************************************************************************/
status_t EmulatedQemuCamera::Initialize(const char* device_name,
- const char* frame_dims)
+ const char* frame_dims,
+ const char* facing_dir)
{
+ LOGV("%s:\n Name=%s\n Facing '%s'\n Dimensions=%s",
+ __FUNCTION__, device_name, facing_dir, frame_dims);
/* Save dimensions. */
mFrameDims = frame_dims;
@@ -63,11 +66,7 @@
* Set customizable parameters.
*/
- const char* facing = EmulatedCamera::FACING_FRONT;
- if (gEmulatedCameraFactory.getQemuCameraOrientation() == CAMERA_FACING_BACK) {
- facing = EmulatedCamera::FACING_BACK;
- }
- mParameters.set(EmulatedCamera::FACING_KEY, facing);
+ mParameters.set(EmulatedCamera::FACING_KEY, facing_dir);
mParameters.set(EmulatedCamera::ORIENTATION_KEY,
gEmulatedCameraFactory.getQemuCameraOrientation());
mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, frame_dims);
@@ -84,7 +83,7 @@
if (c == NULL) {
strncpy(first_dim, frame_dims, sizeof(first_dim));
first_dim[sizeof(first_dim)-1] = '\0';
- } else if ((c - frame_dims) < sizeof(first_dim)) {
+ } else if (static_cast<size_t>(c - frame_dims) < sizeof(first_dim)) {
memcpy(first_dim, frame_dims, c - frame_dims);
first_dim[c - frame_dims] = '\0';
} else {
diff --git a/tools/emulator/system/camera/EmulatedQemuCamera.h b/tools/emulator/system/camera/EmulatedQemuCamera.h
index f00076b..1b826c7 100755
--- a/tools/emulator/system/camera/EmulatedQemuCamera.h
+++ b/tools/emulator/system/camera/EmulatedQemuCamera.h
@@ -42,12 +42,10 @@
**************************************************************************/
public:
- /* Initializes EmulatedQemuCamera instance.
- * The contained EmulatedQemuCameraDevice will be initialized in this method.
- * Return:
- * NO_ERROR on success, or an appropriate error status.
- */
- status_t Initialize(const char* device_name, const char* frame_dims);
+ /* Initializes EmulatedQemuCamera instance. */
+ status_t Initialize(const char* device_name,
+ const char* frame_dims,
+ const char* facing_dir);
/***************************************************************************
* EmulatedCamera abstract API implementation.
diff --git a/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp b/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
index 1342b95..57dbc98 100755
--- a/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
+++ b/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
@@ -82,16 +82,20 @@
return EINVAL;
}
if (isConnected()) {
- LOGW("%s: Qemu camera device is already connected.", __FUNCTION__);
+ LOGW("%s: Qemu camera device '%s' is already connected.",
+ __FUNCTION__, (const char*)mDeviceName);
return NO_ERROR;
}
+ /* Connect to the camera device via emulator. */
const status_t res = mQemuClient.queryConnect();
if (res == NO_ERROR) {
- LOGV("%s: Connected", __FUNCTION__);
+ LOGV("%s: Connected to device '%s'",
+ __FUNCTION__, (const char*)mDeviceName);
mState = ECDS_CONNECTED;
} else {
- LOGE("%s: Connection failed", __FUNCTION__);
+ LOGE("%s: Connection to device '%s' failed",
+ __FUNCTION__, (const char*)mDeviceName);
}
return res;
@@ -103,62 +107,76 @@
Mutex::Autolock locker(&mObjectLock);
if (!isConnected()) {
- LOGW("%s: Qemu camera device is already disconnected.", __FUNCTION__);
+ LOGW("%s: Qemu camera device '%s' is already disconnected.",
+ __FUNCTION__, (const char*)mDeviceName);
return NO_ERROR;
}
- if (isCapturing()) {
- LOGE("%s: Cannot disconnect while in the capturing state.", __FUNCTION__);
+ if (isStarted()) {
+ LOGE("%s: Cannot disconnect from the started device '%s.",
+ __FUNCTION__, (const char*)mDeviceName);
return EINVAL;
}
+ /* Disconnect from the camera device via emulator. */
const status_t res = mQemuClient.queryDisconnect();
if (res == NO_ERROR) {
- LOGV("%s: Disonnected", __FUNCTION__);
+ LOGV("%s: Disonnected from device '%s'",
+ __FUNCTION__, (const char*)mDeviceName);
mState = ECDS_INITIALIZED;
} else {
- LOGE("%s: Disconnection failed", __FUNCTION__);
+ LOGE("%s: Disconnection from device '%s' failed",
+ __FUNCTION__, (const char*)mDeviceName);
}
return res;
}
-status_t EmulatedQemuCameraDevice::startDevice()
+status_t EmulatedQemuCameraDevice::startDevice(int width,
+ int height,
+ uint32_t pix_fmt)
{
LOGV("%s", __FUNCTION__);
+ Mutex::Autolock locker(&mObjectLock);
if (!isConnected()) {
- LOGE("%s: Qemu camera device is not connected.", __FUNCTION__);
+ LOGE("%s: Qemu camera device '%s' is not connected.",
+ __FUNCTION__, (const char*)mDeviceName);
return EINVAL;
}
- if (isCapturing()) {
- LOGW("%s: Qemu camera device is already capturing.", __FUNCTION__);
+ if (isStarted()) {
+ LOGW("%s: Qemu camera device '%s' is already started.",
+ __FUNCTION__, (const char*)mDeviceName);
return NO_ERROR;
}
+ status_t res = EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
+ if (res != NO_ERROR) {
+ LOGE("%s: commonStartDevice failed", __FUNCTION__);
+ return res;
+ }
+
/* Allocate preview frame buffer. */
/* TODO: Watch out for preview format changes! At this point we implement
* RGB32 only.*/
- mPreviewFrame = new uint16_t[mTotalPixels * 4];
+ mPreviewFrame = new uint32_t[mTotalPixels];
if (mPreviewFrame == NULL) {
LOGE("%s: Unable to allocate %d bytes for preview frame",
- __FUNCTION__, mTotalPixels * 4);
+ __FUNCTION__, mTotalPixels);
return ENOMEM;
}
- memset(mPreviewFrame, 0, mTotalPixels * 4);
/* Start the actual camera device. */
- status_t res =
- mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
+ res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
if (res == NO_ERROR) {
- /* Start the worker thread. */
- res = startWorkerThread();
- if (res == NO_ERROR) {
- mState = ECDS_CAPTURING;
- } else {
- mQemuClient.queryStop();
- }
+ LOGV("%s: Qemu camera device '%s' is started for %.4s[%dx%d] frames",
+ __FUNCTION__, (const char*)mDeviceName,
+ reinterpret_cast<const char*>(&mPixelFormat),
+ mFrameWidth, mFrameHeight);
+ mState = ECDS_STARTED;
} else {
- LOGE("%s: Start failed", __FUNCTION__);
+ LOGE("%s: Unable to start device '%s' for %.4s[%dx%d] frames",
+ __FUNCTION__, (const char*)mDeviceName,
+ reinterpret_cast<const char*>(&pix_fmt), width, height);
}
return res;
@@ -168,28 +186,27 @@
{
LOGV("%s", __FUNCTION__);
- if (!isCapturing()) {
- LOGW("%s: Qemu camera device is not capturing.", __FUNCTION__);
+ Mutex::Autolock locker(&mObjectLock);
+ if (!isStarted()) {
+ LOGW("%s: Qemu camera device '%s' is not started.",
+ __FUNCTION__, (const char*)mDeviceName);
return NO_ERROR;
}
- /* Stop the worker thread first. */
- status_t res = stopWorkerThread();
+ /* Stop the actual camera device. */
+ status_t res = mQemuClient.queryStop();
if (res == NO_ERROR) {
- /* Stop the actual camera device. */
- res = mQemuClient.queryStop();
- if (res == NO_ERROR) {
- if (mPreviewFrame == NULL) {
- delete[] mPreviewFrame;
- mPreviewFrame = NULL;
- }
- mState = ECDS_CONNECTED;
- LOGV("%s: Stopped", __FUNCTION__);
- } else {
- LOGE("%s: Stop failed", __FUNCTION__);
+ if (mPreviewFrame == NULL) {
+ delete[] mPreviewFrame;
+ mPreviewFrame = NULL;
}
+ EmulatedCameraDevice::commonStopDevice();
+ mState = ECDS_CONNECTED;
+ LOGV("%s: Qemu camera device '%s' is stopped",
+ __FUNCTION__, (const char*)mDeviceName);
} else {
- LOGE("%s: Unable to stop worker thread", __FUNCTION__);
+ LOGE("%s: Unable to stop device '%s'",
+ __FUNCTION__, (const char*)mDeviceName);
}
return res;
@@ -232,12 +249,13 @@
/* Timestamp the current frame, and notify the camera HAL. */
mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
+ return true;
} else {
LOGE("%s: Unable to get current video frame: %s",
__FUNCTION__, strerror(query_res));
+ mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+ return false;
}
-
- return true;
}
}; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedQemuCameraDevice.h b/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
index 2030869..8ef562b 100755
--- a/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
+++ b/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
@@ -67,15 +67,16 @@
/* Disconnects from the camera device. */
status_t disconnectDevice();
-protected:
/* Starts capturing frames from the camera device. */
- status_t startDevice();
+ status_t startDevice(int width, int height, uint32_t pix_fmt);
/* Stops capturing frames from the camera device. */
status_t stopDevice();
/***************************************************************************
* EmulatedCameraDevice virtual overrides
+ * See declarations of these methods in EmulatedCameraDevice class for
+ * information on each of these methods.
**************************************************************************/
public:
@@ -108,7 +109,7 @@
String8 mDeviceName;
/* Current preview framebuffer. */
- uint16_t* mPreviewFrame;
+ uint32_t* mPreviewFrame;
/* Emulated FPS (frames per second).
* We will emulate 50 FPS. */
diff --git a/tools/emulator/system/camera/JpegCompressor.cpp b/tools/emulator/system/camera/JpegCompressor.cpp
new file mode 100644
index 0000000..0e538a1
--- /dev/null
+++ b/tools/emulator/system/camera/JpegCompressor.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*
+ * Contains implementation of a class NV21JpegCompressor that encapsulates a
+ * converter between NV21, and JPEG formats.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_JPEG"
+#include <cutils/log.h>
+#include "JpegCompressor.h"
+
+namespace android {
+
+NV21JpegCompressor::NV21JpegCompressor()
+ : Yuv420SpToJpegEncoder(mStrides)
+{
+}
+
+NV21JpegCompressor::~NV21JpegCompressor()
+{
+}
+
+/****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+status_t NV21JpegCompressor::compressRawImage(const void* image,
+ int width,
+ int height,
+ int quality)
+{
+ LOGV("%s: %p[%dx%d]", __FUNCTION__, image, width, height);
+ void* pY = const_cast<void*>(image);
+ int offsets[2];
+ offsets[0] = 0;
+ offsets[1] = width * height;
+ mStrides[0] = width;
+ mStrides[1] = width;
+ if (encode(&mStream, pY, width, height, offsets, quality)) {
+ LOGV("%s: Compressed JPEG: %d[%dx%d] -> %d bytes",
+ __FUNCTION__, (width * height * 12) / 8, width, height, mStream.getOffset());
+ return NO_ERROR;
+ } else {
+ LOGE("%s: JPEG compression failed", __FUNCTION__);
+ return errno ? errno : EINVAL;
+ }
+}
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/JpegCompressor.h b/tools/emulator/system/camera/JpegCompressor.h
new file mode 100644
index 0000000..1f97ae4
--- /dev/null
+++ b/tools/emulator/system/camera/JpegCompressor.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H
+#define HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H
+
+/*
+ * Contains declaration of a class NV21JpegCompressor that encapsulates a
+ * converter between YV21, and JPEG formats.
+ */
+
+#include <YuvToJpegEncoder.h>
+
+namespace android {
+
+/* Encapsulates a converter between YV12, and JPEG formats.
+ */
+class NV21JpegCompressor : protected Yuv420SpToJpegEncoder
+{
+public:
+ /* Constructs JpegCompressor instance. */
+ NV21JpegCompressor();
+ /* Destructs JpegCompressor instance. */
+ ~NV21JpegCompressor();
+
+ /****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+public:
+ /* Compresses raw NV21 image into a JPEG.
+ * The compressed image will be saved in mStream member of this class. Use
+ * getCompressedSize method to obtain buffer size of the compressed image,
+ * and getCompressedImage to copy out the compressed image.
+ * Param:
+ * image - Raw NV21 image.
+ * width, height - Image dimensions.
+ * quality - JPEG quality.
+ * Return:
+ * NO_ERROR on success, or an appropriate error status.
+ *
+ */
+ status_t compressRawImage(const void* image,
+ int width,
+ int height,
+ int quality);
+
+ /* Get size of the compressed JPEG buffer.
+ * This method must be called only after a successful completion of
+ * compressRawImage call.
+ * Return:
+ * Size of the compressed JPEG buffer.
+ */
+ size_t getCompressedSize() const
+ {
+ return mStream.getOffset();
+ }
+
+ /* Copies out compressed JPEG buffer.
+ * This method must be called only after a successful completion of
+ * compressRawImage call.
+ * Param:
+ * buff - Buffer where to copy the JPEG. Must be large enough to contain the
+ * entire image.
+ */
+ void getCompressedImage(void* buff) const
+ {
+ mStream.copyTo(buff);
+ }
+
+ /****************************************************************************
+ * Class data
+ ***************************************************************************/
+
+protected:
+ /* Memory stream where converted JPEG is saved. */
+ SkDynamicMemoryWStream mStream;
+ /* Strides for Y (the first element), and UV (the second one) panes. */
+ int mStrides[2];
+};
+
+}; /* namespace android */
+
+#endif /* HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H */
diff --git a/tools/emulator/system/camera/PreviewWindow.cpp b/tools/emulator/system/camera/PreviewWindow.cpp
index c96a807..fb708d5 100755
--- a/tools/emulator/system/camera/PreviewWindow.cpp
+++ b/tools/emulator/system/camera/PreviewWindow.cpp
@@ -121,9 +121,9 @@
__FUNCTION__, mPreviewWindow, mPreviewFrameWidth,
mPreviewFrameHeight);
res = mPreviewWindow->set_buffers_geometry(mPreviewWindow,
- mPreviewFrameWidth,
- mPreviewFrameHeight,
- HAL_PIXEL_FORMAT_RGBA_8888);
+ mPreviewFrameWidth,
+ mPreviewFrameHeight,
+ HAL_PIXEL_FORMAT_RGBA_8888);
if (res != NO_ERROR) {
LOGE("%s: Error in set_buffers_geometry %d -> %s",
__FUNCTION__, -res, strerror(-res));
@@ -180,6 +180,10 @@
grbuffer_mapper.unlock(*buffer);
}
+/***************************************************************************
+ * Private API
+ **************************************************************************/
+
bool PreviewWindow::adjustPreviewDimensions(EmulatedCameraDevice* camera_dev)
{
/* Match the cached frame dimensions against the actual ones. */
diff --git a/tools/emulator/system/camera/QemuClient.cpp b/tools/emulator/system/camera/QemuClient.cpp
index 49307bb..fd49585 100755
--- a/tools/emulator/system/camera/QemuClient.cpp
+++ b/tools/emulator/system/camera/QemuClient.cpp
@@ -19,7 +19,7 @@
* services in the emulator via qemu pipe.
*/
-#define LOG_NDEBUG 0
+#define LOG_NDEBUG 1
#define LOG_TAG "EmulatedCamera_QemuClient"
#include <cutils/log.h>
#include "EmulatedCamera.h"
@@ -40,7 +40,7 @@
QemuQuery::QemuQuery()
: mQuery(mQueryPrealloc),
- mQueryStatus(NO_ERROR),
+ mQueryDeliveryStatus(NO_ERROR),
mReplyBuffer(NULL),
mReplyData(NULL),
mReplySize(0),
@@ -52,26 +52,26 @@
QemuQuery::QemuQuery(const char* query_string)
: mQuery(mQueryPrealloc),
- mQueryStatus(NO_ERROR),
+ mQueryDeliveryStatus(NO_ERROR),
mReplyBuffer(NULL),
mReplyData(NULL),
mReplySize(0),
mReplyDataSize(0),
mReplyStatus(0)
{
- mQueryStatus = QemuQuery::createQuery(query_string, NULL);
+ mQueryDeliveryStatus = QemuQuery::createQuery(query_string, NULL);
}
QemuQuery::QemuQuery(const char* query_name, const char* query_param)
: mQuery(mQueryPrealloc),
- mQueryStatus(NO_ERROR),
+ mQueryDeliveryStatus(NO_ERROR),
mReplyBuffer(NULL),
mReplyData(NULL),
mReplySize(0),
mReplyDataSize(0),
mReplyStatus(0)
{
- mQueryStatus = QemuQuery::createQuery(query_name, query_param);
+ mQueryDeliveryStatus = QemuQuery::createQuery(query_name, query_param);
}
QemuQuery::~QemuQuery()
@@ -88,6 +88,7 @@
if (name == NULL || *name == '\0') {
LOGE("%s: NULL or an empty string is passed as query name.",
__FUNCTION__);
+ mQueryDeliveryStatus = EINVAL;
return EINVAL;
}
@@ -101,7 +102,7 @@
if (mQuery == NULL) {
LOGE("%s: Unable to allocate %d bytes for query buffer",
__FUNCTION__, required);
- mQueryStatus = ENOMEM;
+ mQueryDeliveryStatus = ENOMEM;
return ENOMEM;
}
}
@@ -119,9 +120,9 @@
status_t QemuQuery::completeQuery(status_t status)
{
/* Save query completion status. */
- mQueryStatus = status;
- if (mQueryStatus != NO_ERROR) {
- return mQueryStatus;
+ mQueryDeliveryStatus = status;
+ if (mQueryDeliveryStatus != NO_ERROR) {
+ return mQueryDeliveryStatus;
}
/* Make sure reply buffer contains at least 'ok', or 'ko'.
@@ -131,7 +132,7 @@
* zero-terminated, and the terminator will be inculded in the reply. */
if (mReplyBuffer == NULL || mReplySize < 3) {
LOGE("%s: Invalid reply to the query", __FUNCTION__);
- mQueryStatus = EINVAL;
+ mQueryDeliveryStatus = EINVAL;
return EINVAL;
}
@@ -142,7 +143,7 @@
mReplyStatus = 0;
} else {
LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
- mQueryStatus = EINVAL;
+ mQueryDeliveryStatus = EINVAL;
return EINVAL;
}
@@ -152,7 +153,7 @@
* with a ':' */
if (mReplyBuffer[2] != ':') {
LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
- mQueryStatus = EINVAL;
+ mQueryDeliveryStatus = EINVAL;
return EINVAL;
}
mReplyData = mReplyBuffer + 3;
@@ -162,7 +163,7 @@
* zero-terminator. */
if (mReplyBuffer[2] != '\0') {
LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
- mQueryStatus = EINVAL;
+ mQueryDeliveryStatus = EINVAL;
return EINVAL;
}
}
@@ -176,14 +177,13 @@
delete[] mQuery;
}
mQuery = mQueryPrealloc;
- mQueryStatus = NO_ERROR;
+ mQueryDeliveryStatus = NO_ERROR;
if (mReplyBuffer != NULL) {
free(mReplyBuffer);
mReplyBuffer = NULL;
}
mReplyData = NULL;
- mReplySize = 0;
- mReplyDataSize = 0;
+ mReplySize = mReplyDataSize = 0;
mReplyStatus = 0;
}
@@ -270,9 +270,9 @@
if (written == data_size) {
return NO_ERROR;
} else {
- LOGE("%s: Error sending data via qemu pipe: %s",
+ LOGE("%s: Error sending data via qemu pipe: '%s'",
__FUNCTION__, strerror(errno));
- return errno != NO_ERROR ? errno : EIO;
+ return errno ? errno : EIO;
}
}
@@ -331,9 +331,9 @@
status_t QemuClient::doQuery(QemuQuery* query)
{
/* Make sure that query has been successfuly constructed. */
- if (query->mQueryStatus != NO_ERROR) {
+ if (query->mQueryDeliveryStatus != NO_ERROR) {
LOGE("%s: Query is invalid", __FUNCTION__);
- return query->mQueryStatus;
+ return query->mQueryDeliveryStatus;
}
LOGQ("Send query '%s'", query->mQuery);
@@ -357,7 +357,11 @@
}
/* Complete the query, and return its completion handling status. */
- return query->completeQuery(res);
+ const status_t res1 = query->completeQuery(res);
+ LOGE_IF(res1 != NO_ERROR && res1 != res,
+ "%s: Error %d in query '%s' completion",
+ __FUNCTION__, res1, query->mQuery);
+ return res1;
}
/****************************************************************************
@@ -385,8 +389,9 @@
LOGV("%s", __FUNCTION__);
QemuQuery query(mQueryList);
- doQuery(&query);
- if (!query.isQuerySucceeded()) {
+ if (doQuery(&query) || !query.isQuerySucceeded()) {
+ LOGE("%s: List cameras query failed: %s", __FUNCTION__,
+ query.mReplyData ? query.mReplyData : "No error message");
return query.getCompletionStatus();
}
@@ -445,9 +450,9 @@
QemuQuery query(mQueryConnect);
doQuery(&query);
const status_t res = query.getCompletionStatus();
- LOGE_IF(res != NO_ERROR, "%s failed: %s",
+ LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
__FUNCTION__, query.mReplyData ? query.mReplyData :
- "No error message");
+ "No error message");
return res;
}
@@ -458,9 +463,9 @@
QemuQuery query(mQueryDisconnect);
doQuery(&query);
const status_t res = query.getCompletionStatus();
- LOGE_IF(res != NO_ERROR, "%s failed: %s",
+ LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
__FUNCTION__, query.mReplyData ? query.mReplyData :
- "No error message");
+ "No error message");
return res;
}
@@ -476,9 +481,9 @@
QemuQuery query(query_str);
doQuery(&query);
const status_t res = query.getCompletionStatus();
- LOGE_IF(res != NO_ERROR, "%s failed: %s",
+ LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
__FUNCTION__, query.mReplyData ? query.mReplyData :
- "No error message");
+ "No error message");
return res;
}
@@ -489,9 +494,9 @@
QemuQuery query(mQueryStop);
doQuery(&query);
const status_t res = query.getCompletionStatus();
- LOGE_IF(res != NO_ERROR, "%s failed: %s",
+ LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
__FUNCTION__, query.mReplyData ? query.mReplyData :
- "No error message");
+ "No error message");
return res;
}
@@ -500,6 +505,8 @@
size_t vframe_size,
size_t pframe_size)
{
+ LOGV("%s", __FUNCTION__);
+
char query_str[256];
snprintf(query_str, sizeof(query_str), "%s video=%d preview=%d",
mQueryFrame, (vframe && vframe_size) ? vframe_size : 0,
@@ -507,39 +514,41 @@
QemuQuery query(query_str);
doQuery(&query);
const status_t res = query.getCompletionStatus();
- LOGE_IF(res != NO_ERROR, "%s failed: %s",
- __FUNCTION__, query.mReplyData ? query.mReplyData :
+ if( res != NO_ERROR) {
+ LOGE("%s: Query failed: %s",
+ __FUNCTION__, query.mReplyData ? query.mReplyData :
"No error message");
- if (res == NO_ERROR) {
- /* Copy requested frames. */
- size_t cur_offset = 0;
- const uint8_t* frame = reinterpret_cast<const uint8_t*>(query.mReplyData);
- /* Video frame is always first. */
- if (vframe != NULL && vframe_size != 0) {
- /* Make sure that video frame is in. */
- if ((query.mReplyDataSize - cur_offset) >= vframe_size) {
- memcpy(vframe, frame, vframe_size);
- cur_offset += vframe_size;
- } else {
- LOGE("%s: Reply (%d bytes) is to small to contain video frame (%d bytes)",
- __FUNCTION__, query.mReplyDataSize - cur_offset, vframe_size);
- return EINVAL;
- }
+ return res;
+ }
+
+ /* Copy requested frames. */
+ size_t cur_offset = 0;
+ const uint8_t* frame = reinterpret_cast<const uint8_t*>(query.mReplyData);
+ /* Video frame is always first. */
+ if (vframe != NULL && vframe_size != 0) {
+ /* Make sure that video frame is in. */
+ if ((query.mReplyDataSize - cur_offset) >= vframe_size) {
+ memcpy(vframe, frame, vframe_size);
+ cur_offset += vframe_size;
+ } else {
+ LOGE("%s: Reply %d bytes is to small to contain %d bytes video frame",
+ __FUNCTION__, query.mReplyDataSize - cur_offset, vframe_size);
+ return EINVAL;
}
- if (pframe != NULL && pframe_size != 0) {
- /* Make sure that preview frame is in. */
- if ((query.mReplyDataSize - cur_offset) >= pframe_size) {
- memcpy(pframe, frame + cur_offset, pframe_size);
- cur_offset += pframe_size;
- } else {
- LOGE("%s: Reply (%d bytes) is to small to contain preview frame (%d bytes)",
- __FUNCTION__, query.mReplyDataSize - cur_offset, pframe_size);
- return EINVAL;
- }
+ }
+ if (pframe != NULL && pframe_size != 0) {
+ /* Make sure that preview frame is in. */
+ if ((query.mReplyDataSize - cur_offset) >= pframe_size) {
+ memcpy(pframe, frame + cur_offset, pframe_size);
+ cur_offset += pframe_size;
+ } else {
+ LOGE("%s: Reply %d bytes is to small to contain %d bytes preview frame",
+ __FUNCTION__, query.mReplyDataSize - cur_offset, pframe_size);
+ return EINVAL;
}
}
- return res;
+ return NO_ERROR;
}
}; /* namespace android */
diff --git a/tools/emulator/system/camera/QemuClient.h b/tools/emulator/system/camera/QemuClient.h
index 9614a4d..c0b8e61 100755
--- a/tools/emulator/system/camera/QemuClient.h
+++ b/tools/emulator/system/camera/QemuClient.h
@@ -57,7 +57,9 @@
* - '=' are allowed only to divide parameter names from parameter values.
*
* Emulator replies to each query in two chunks:
- * - 4 bytes encoding the payload size
+ * - 8 bytes encoding the payload size as a string containing hexadecimal
+ * representation of the payload size value. This is done in order to simplify
+ * dealing with different endianness on the host, and on the guest.
* - Payload, whose size is defined by the first chunk.
*
* Every payload always begins with two characters, encoding the result of the
@@ -66,7 +68,9 @@
* - 'ko' Encoding a failure.
* After that payload may have optional data. If payload has more data following
* the query result, there is a ':' character separating them. If payload carries
- * only the result, it always ends with a zero-terminator.
+ * only the result, it always ends with a zero-terminator. So, payload 'ok'/'ko'
+ * prefix is always 3 bytes long: it either includes a zero-terminator, if there
+ * is no data, or a ':' separator.
*/
class QemuQuery {
public:
@@ -81,7 +85,7 @@
*/
explicit QemuQuery(const char* query_string);
- /* Constructs and initializes QemuQuery instance for a query.
+ /* Constructs and initializes QemuQuery instance for a query with parameters.
* Param:
* query_name - Query name.
* query_param - Query parameters. Can be NULL.
@@ -96,7 +100,8 @@
***************************************************************************/
/* Creates new query.
- * This method will reset this instance prior to creating a new query.
+ * Note: this method will reset this instance prior to creating a new query
+ * in order to discard possible "leftovers" from the previous query.
* Param:
* query_name - Query name.
* query_param - Query parameters. Can be NULL.
@@ -108,19 +113,19 @@
/* Completes the query after a reply from the emulator.
* This method will parse the reply buffer, and calculate the final query
* status, which depends not only on the transport success / failure, but
- * also on 'ok' / 'ko' in the query reply.
+ * also on 'ok' / 'ko' in the reply buffer.
* Param:
* status - Query delivery status. This status doesn't necessarily reflects
- * the final query status (which is defined by 'ok'/'ko' in the reply buffer).
- * This status simply states whether or not the query has been sent, and a
- * reply has been received successfuly. However, if status indicates a
- * failure, the entire query has failed. If status indicates a success, the
- * reply will be checked here to calculate the final query status.
+ * the final query status (which is defined by 'ok'/'ko' prefix in the
+ * reply buffer). This status simply states whether or not the query has
+ * been sent, and a reply has been received successfuly. However, if
+ * this status indicates a failure, it means that the entire query has
+ * failed.
* Return:
* NO_ERROR on success, or an appropriate error status on failure. Note that
* status returned here just signals whether or not the method has succeeded.
- * Use isQuerySucceeded() / getCompletionStatus() methods to check the final
- * query status.
+ * Use isQuerySucceeded() / getCompletionStatus() methods of this class to
+ * check the final query status.
*/
status_t completeQuery(status_t status);
@@ -132,19 +137,26 @@
* class has been executed.
*/
inline bool isQuerySucceeded() const {
- return mQueryStatus == NO_ERROR && mReplyStatus != 0;
+ return mQueryDeliveryStatus == NO_ERROR && mReplyStatus != 0;
}
/* Gets final completion status of the query.
* Note that this method must be called after completeQuery() method of this
* class has been executed.
- * NO_ERROR on success, or an appropriate error status on failure.
+ * Return:
+ * NO_ERROR if query has succeeded, or an appropriate error status on query
+ * failure.
*/
inline status_t getCompletionStatus() const {
- if (isQuerySucceeded()) {
- return NO_ERROR;
+ if (mQueryDeliveryStatus == NO_ERROR) {
+ if (mReplyStatus) {
+ return NO_ERROR;
+ } else {
+ return EINVAL;
+ }
+ } else {
+ return mQueryDeliveryStatus;
}
- return (mQueryStatus != NO_ERROR) ? mQueryStatus : EINVAL;
}
/****************************************************************************
@@ -154,8 +166,8 @@
public:
/* Query string. */
char* mQuery;
- /* Query status. */
- status_t mQueryStatus;
+ /* Query delivery status. */
+ status_t mQueryDeliveryStatus;
/* Reply buffer */
char* mReplyBuffer;
/* Reply data (past 'ok'/'ko'). If NULL, there were no data in reply. */
@@ -208,7 +220,7 @@
* the 'factory' service, while connection with parameters means
* connection to an 'emulated camera' service, where camera is identified
* by one of the connection parameters. So, passing NULL, or an empty
- * string to this method will establish connection with a 'factory'
+ * string to this method will establish a connection with the 'factory'
* service, while not empty string passed here will establish connection
* with an 'emulated camera' service. Parameters defining the emulated
* camera must be formatted as such:
@@ -216,10 +228,10 @@
* "name=<device name> [inp_channel=<input channel #>]",
*
* where 'device name' is a required parameter defining name of the
- * camera device, 'input channel' is an optional parameter (positive
- * integer), defining input channel to use on the camera device. Note
- * that device name passed here must have been previously obtained from
- * the factory service.
+ * camera device, and 'input channel' is an optional parameter (positive
+ * integer), defining the input channel to use on the camera device.
+ * Note that device name passed here must have been previously obtained
+ * from the factory service using 'list' query.
* Return:
* NO_ERROR on success, or an appropriate error status.
*/
@@ -259,11 +271,11 @@
* Return:
* NO_ERROR on success, or an appropriate error status on failure. Note that
* status returned here is not the final query status. Use isQuerySucceeded(),
- * or getCompletionStatus() method on the query to see if it has succeeded.
- * However, if this method returns a failure, it means that the query has
- * failed, and there is no guarantee that its data members are properly
- * initialized (except for the 'mQueryStatus', which is always in the
- * proper state).
+ * or getCompletionStatus() method on the query object to see if it has
+ * succeeded. However, if this method returns a failure, it means that the
+ * query has failed, and there is no guarantee that its data members are
+ * properly initialized (except for the 'mQueryDeliveryStatus', which is
+ * always in the proper state).
*/
virtual status_t doQuery(QemuQuery* query);
@@ -300,25 +312,26 @@
public:
/* Lists camera devices connected to the host.
* Param:
- * list - Upon success contains list of cameras connected to the host. The
+ * list - Upon success contains a list of cameras connected to the host. The
* list returned here is represented as a string, containing multiple
- * lines, separated with '\n', where each line represents a camera. Each
+ * lines separated with '\n', where each line represents a camera. Each
* camera line is formatted as such:
*
* "name=<device name> channel=<num> pix=<num> framedims=<dimensions>\n"
*
* Where:
- * - 'name' is the name of camera device attached to the host. This name
- * must be used for subsequent connection to the 'emulated camera'
+ * - 'name' is the name of the camera device attached to the host. This
+ * name must be used for subsequent connection to the 'emulated camera'
* service for that camera.
* - 'channel' - input channel number (positive int) to use to communicate
* with the camera.
- * - 'pix' - pixel format (a "fourcc" int), chosen for the video frames.
+ * - 'pix' - pixel format (a "fourcc" uint), chosen for the video frames
+ * by the camera service.
* - 'framedims' contains a list of frame dimensions supported by the
- * camera. Each etry in the list is in form '<width>x<height>', where
- * 'width' and 'height' are numeric values for width and height of a
- * supported frame dimension. Entries in this list are separated with
- * ','.
+ * camera for the chosen pixel format. Each etry in the list is in form
+ * '<width>x<height>', where 'width' and 'height' are numeric values
+ * for width and height of a supported frame dimension. Entries in
+ * this list are separated with ',' with no spaces between the entries.
* Return:
* NO_ERROR on success, or an appropriate error status on failure.
*/
diff --git a/tools/emulator/system/camera/media_profiles.xml b/tools/emulator/system/camera/media_profiles.xml
new file mode 100644
index 0000000..ae1ce88
--- /dev/null
+++ b/tools/emulator/system/camera/media_profiles.xml
@@ -0,0 +1,400 @@
+<?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.
+-->
+<!DOCTYPE MediaSettings [
+<!ELEMENT MediaSettings (CamcorderProfiles,
+ EncoderOutputFileFormat+,
+ VideoEncoderCap+,
+ AudioEncoderCap+,
+ VideoDecoderCap,
+ AudioDecoderCap)>
+<!ELEMENT CamcorderProfiles (EncoderProfile+, ImageEncoding+, ImageDecoding, Camera)>
+<!ELEMENT EncoderProfile (Video, Audio)>
+<!ATTLIST EncoderProfile quality (high|low) #REQUIRED>
+<!ATTLIST EncoderProfile fileFormat (mp4|3gp) #REQUIRED>
+<!ATTLIST EncoderProfile duration (30|60) #REQUIRED>
+<!ATTLIST EncoderProfile cameraId (0|1) #REQUIRED>
+<!ELEMENT Video EMPTY>
+<!ATTLIST Video codec (h264|h263|m4v) #REQUIRED>
+<!ATTLIST Video bitRate CDATA #REQUIRED>
+<!ATTLIST Video width CDATA #REQUIRED>
+<!ATTLIST Video height CDATA #REQUIRED>
+<!ATTLIST Video frameRate CDATA #REQUIRED>
+<!ELEMENT Audio EMPTY>
+<!ATTLIST Audio codec (amrnb|amrwb|aac) #REQUIRED>
+<!ATTLIST Audio bitRate CDATA #REQUIRED>
+<!ATTLIST Audio sampleRate CDATA #REQUIRED>
+<!ATTLIST Audio channels (1|2) #REQUIRED>
+<!ELEMENT ImageEncoding EMPTY>
+<!ATTLIST ImageEncoding quality (90|80|70|60|50|40) #REQUIRED>
+<!ELEMENT ImageDecoding EMPTY>
+<!ATTLIST ImageDecoding memCap CDATA #REQUIRED>
+<!ELEMENT Camera EMPTY>
+<!ELEMENT EncoderOutputFileFormat EMPTY>
+<!ATTLIST EncoderOutputFileFormat name (mp4|3gp) #REQUIRED>
+<!ELEMENT VideoEncoderCap EMPTY>
+<!ATTLIST VideoEncoderCap name (h264|h263|m4v|wmv) #REQUIRED>
+<!ATTLIST VideoEncoderCap enabled (true|false) #REQUIRED>
+<!ATTLIST VideoEncoderCap minBitRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxBitRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameRate CDATA #REQUIRED>
+<!ELEMENT AudioEncoderCap EMPTY>
+<!ATTLIST AudioEncoderCap name (amrnb|amrwb|aac|wma) #REQUIRED>
+<!ATTLIST AudioEncoderCap enabled (true|false) #REQUIRED>
+<!ATTLIST AudioEncoderCap minBitRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap maxBitRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap minSampleRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap maxSampleRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap minChannels (1|2) #REQUIRED>
+<!ATTLIST AudioEncoderCap maxChannels (1|2) #REQUIRED>
+<!ELEMENT VideoDecoderCap EMPTY>
+<!ATTLIST VideoDecoderCap name (wmv) #REQUIRED>
+<!ATTLIST VideoDecoderCap enabled (true|false) #REQUIRED>
+<!ELEMENT AudioDecoderCap EMPTY>
+<!ATTLIST AudioDecoderCap name (wma) #REQUIRED>
+<!ATTLIST AudioDecoderCap enabled (true|false) #REQUIRED>
+<!ELEMENT VideoEditorCap EMPTY>
+<!ATTLIST VideoEditorCap maxInputFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxInputFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxOutputFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxOutputFrameHeight CDATA #REQUIRED>
+<!ELEMENT ExportVideoProfile EMPTY>
+<!ATTLIST ExportVideoProfile name (h264|h263|m4v) #REQUIRED>
+<!ATTLIST ExportVideoProfile profile CDATA #REQUIRED>
+<!ATTLIST ExportVideoProfile level CDATA #REQUIRED>
+]>
+<!--
+ This file is used to declare the multimedia profiles and capabilities
+ on an android-powered device.
+-->
+<MediaSettings>
+ <!-- Each camcorder profile defines a set of predefined configuration parameters -->
+ <CamcorderProfiles cameraId="0">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <CamcorderProfiles cameraId="1">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <CamcorderProfiles cameraId="2">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <CamcorderProfiles cameraId="3">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <CamcorderProfiles cameraId="4">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <CamcorderProfiles cameraId="5">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <CamcorderProfiles cameraId="6">
+
+ <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+ <Video codec="m4v"
+ bitRate="128000"
+ width="320"
+ height="240"
+ frameRate="15" />
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+ <Video codec="h264"
+ bitRate="192000"
+ width="176"
+ height="144"
+ frameRate="30" />
+ <!-- audio setting is ignored -->
+ <Audio codec="amrnb"
+ bitRate="12200"
+ sampleRate="8000"
+ channels="1" />
+ </EncoderProfile>
+
+ <ImageEncoding quality="95" />
+ <ImageEncoding quality="80" />
+ <ImageEncoding quality="70" />
+ <ImageDecoding memCap="20000000" />
+
+ </CamcorderProfiles>
+
+ <EncoderOutputFileFormat name="3gp" />
+ <EncoderOutputFileFormat name="mp4" />
+
+ <!--
+ If a codec is not enabled, it is invisible to the applications
+ In other words, the applications won't be able to use the codec
+ or query the capabilities of the codec at all if it is disabled
+ -->
+ <VideoEncoderCap name="h264" enabled="true"
+ minBitRate="64000" maxBitRate="192000"
+ minFrameWidth="176" maxFrameWidth="320"
+ minFrameHeight="144" maxFrameHeight="240"
+ minFrameRate="15" maxFrameRate="30" />
+
+ <VideoEncoderCap name="h263" enabled="true"
+ minBitRate="64000" maxBitRate="192000"
+ minFrameWidth="176" maxFrameWidth="320"
+ minFrameHeight="144" maxFrameHeight="240"
+ minFrameRate="15" maxFrameRate="30" />
+
+ <VideoEncoderCap name="m4v" enabled="true"
+ minBitRate="64000" maxBitRate="192000"
+ minFrameWidth="176" maxFrameWidth="320"
+ minFrameHeight="144" maxFrameHeight="240"
+ minFrameRate="15" maxFrameRate="30" />
+
+ <AudioEncoderCap name="aac" enabled="true"
+ minBitRate="8000" maxBitRate="96000"
+ minSampleRate="8000" maxSampleRate="48000"
+ minChannels="1" maxChannels="1" />
+
+ <AudioEncoderCap name="amrwb" enabled="true"
+ minBitRate="6600" maxBitRate="23050"
+ minSampleRate="16000" maxSampleRate="16000"
+ minChannels="1" maxChannels="1" />
+
+ <AudioEncoderCap name="amrnb" enabled="true"
+ minBitRate="5525" maxBitRate="12200"
+ minSampleRate="8000" maxSampleRate="8000"
+ minChannels="1" maxChannels="1" />
+
+ <!--
+ FIXME:
+ We do not check decoder capabilities at present
+ At present, we only check whether windows media is visible
+ for TEST applications. For other applications, we do
+ not perform any checks at all.
+ -->
+ <VideoDecoderCap name="wmv" enabled="false"/>
+ <AudioDecoderCap name="wma" enabled="false"/>
+ <VideoEditorCap maxInputFrameWidth="320"
+ maxInputFrameHeight="240" maxOutputFrameWidth="320"
+ maxOutputFrameHeight="240"/>
+ <!--
+ The VideoEditor Export codec profile and level values
+ correspond to the values in OMX_Video.h.
+ E.g. for h264, profile value 1 means OMX_VIDEO_AVCProfileBaseline
+ and level 4096 means OMX_VIDEO_AVCLevel41.
+ Please note that the values are in decimal.
+ These values are for video encoder.
+ -->
+ <!--
+ Codec = h.264, Baseline profile, level 4.1
+ -->
+ <ExportVideoProfile name="h264" profile= "1" level="512"/>
+ <!--
+ Codec = h.263, Baseline profile, level 0
+ -->
+ <ExportVideoProfile name="h263" profile= "1" level="1"/>
+ <!--
+ Codec = mpeg4, Simple profile, level 3
+ -->
+ <ExportVideoProfile name="m4v" profile= "1" level="16"/>
+</MediaSettings>