Merge "createSurface getpid() first parameter was removed"
diff --git a/Android.mk b/Android.mk
index 5acfb86..79f6220 100644
--- a/Android.mk
+++ b/Android.mk
@@ -67,7 +67,6 @@
core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
core/java/android/app/IActivityController.aidl \
core/java/android/app/IActivityPendingResult.aidl \
- core/java/android/app/IActivityWatcher.aidl \
core/java/android/app/IAlarmManager.aidl \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
@@ -110,6 +109,7 @@
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
core/java/android/database/IContentObserver.aidl \
+ core/java/android/hardware/ISerialManager.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/16.txt b/api/16.txt
index 02a5104..be544de 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -15052,7 +15052,7 @@
method public static final deprecated boolean supportsProcesses();
field public static final int BLUETOOTH_GID = 2000; // 0x7d0
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
- field public static final int LAST_APPLICATION_UID = 89999; // 0x1869f
+ field public static final int LAST_APPLICATION_UID = 19999; // 0x1869f
field public static final int PHONE_UID = 1001; // 0x3e9
field public static final int SIGNAL_KILL = 9; // 0x9
field public static final int SIGNAL_QUIT = 3; // 0x3
diff --git a/api/current.txt b/api/current.txt
index 2037515..d034b89 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -614,8 +614,10 @@
field public static final int layout_height = 16842997; // 0x10100f5
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
+ field public static final int layout_marginEnd = 16843692; // 0x10103ac
field public static final int layout_marginLeft = 16842999; // 0x10100f7
field public static final int layout_marginRight = 16843001; // 0x10100f9
+ field public static final int layout_marginStart = 16843691; // 0x10103ab
field public static final int layout_marginTop = 16843000; // 0x10100f8
field public static final int layout_row = 16843643; // 0x101037b
field public static final int layout_rowSpan = 16843644; // 0x101037c
@@ -711,8 +713,10 @@
field public static final int packageNames = 16843649; // 0x1010381
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
+ field public static final int paddingEnd = 16843690; // 0x10103aa
field public static final int paddingLeft = 16842966; // 0x10100d6
field public static final int paddingRight = 16842968; // 0x10100d8
+ field public static final int paddingStart = 16843689; // 0x10103a9
field public static final int paddingTop = 16842967; // 0x10100d7
field public static final int panelBackground = 16842846; // 0x101005e
field public static final int panelColorBackground = 16842849; // 0x1010061
@@ -992,6 +996,7 @@
field public static final int textColorTertiary = 16843282; // 0x1010212
field public static final int textColorTertiaryInverse = 16843283; // 0x1010213
field public static final int textCursorDrawable = 16843618; // 0x1010362
+ field public static final int textDirection = 16843688; // 0x10103a8
field public static final int textEditNoPasteWindowLayout = 16843541; // 0x1010315
field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314
field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f
@@ -15180,7 +15185,7 @@
method public static final deprecated boolean supportsProcesses();
field public static final int BLUETOOTH_GID = 2000; // 0x7d0
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
- field public static final int LAST_APPLICATION_UID = 89999; // 0x15f8f
+ field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
field public static final int PHONE_UID = 1001; // 0x3e9
field public static final int SIGNAL_KILL = 9; // 0x9
field public static final int SIGNAL_QUIT = 3; // 0x3
@@ -20478,6 +20483,19 @@
method public int getTopPadding();
}
+ public abstract interface TextDirectionHeuristic {
+ }
+
+ public class TextDirectionHeuristics {
+ ctor public TextDirectionHeuristics();
+ field public static final android.text.TextDirectionHeuristic ANYRTL_LTR;
+ field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_LTR;
+ field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_RTL;
+ field public static final android.text.TextDirectionHeuristic LOCALE;
+ field public static final android.text.TextDirectionHeuristic LTR;
+ field public static final android.text.TextDirectionHeuristic RTL;
+ }
+
public class TextPaint extends android.graphics.Paint {
ctor public TextPaint();
ctor public TextPaint(int);
@@ -21600,6 +21618,26 @@
method public void println(java.lang.String);
}
+ public class LongSparseArray implements java.lang.Cloneable {
+ ctor public LongSparseArray();
+ ctor public LongSparseArray(int);
+ method public void append(long, E);
+ method public void clear();
+ method public android.util.LongSparseArray<E> clone();
+ method public void delete(long);
+ method public E get(long);
+ method public E get(long, E);
+ method public int indexOfKey(long);
+ method public int indexOfValue(E);
+ method public long keyAt(int);
+ method public void put(long, E);
+ method public void remove(long);
+ method public void removeAt(int);
+ method public void setValueAt(int, E);
+ method public int size();
+ method public E valueAt(int);
+ }
+
public class LruCache {
ctor public LruCache(int);
method protected V create(K);
@@ -23145,12 +23183,15 @@
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public int getOverScrollMode();
method public int getPaddingBottom();
+ method public int getPaddingEnd();
method public int getPaddingLeft();
method public int getPaddingRight();
+ method public int getPaddingStart();
method public int getPaddingTop();
method public final android.view.ViewParent getParent();
method public float getPivotX();
method public float getPivotY();
+ method public int getResolvedTextDirection();
method public android.content.res.Resources getResources();
method public final int getRight();
method protected float getRightFadingEdgeStrength();
@@ -23170,6 +23211,7 @@
method public int getSystemUiVisibility();
method public java.lang.Object getTag();
method public java.lang.Object getTag(int);
+ method public int getTextDirection();
method public final int getTop();
method protected float getTopFadingEdgeStrength();
method protected int getTopPaddingOffset();
@@ -23220,6 +23262,7 @@
method public boolean isLongClickable();
method public boolean isOpaque();
method protected boolean isPaddingOffsetRequired();
+ method public boolean isPaddingRelative();
method public boolean isPressed();
method public boolean isSaveEnabled();
method public boolean isSaveFromParentEnabled();
@@ -23267,6 +23310,9 @@
method protected void onMeasure(int, int);
method protected void onOverScrolled(int, int, boolean, boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+ method public void onResetResolvedTextDirection();
+ method public void onResolvePadding(int);
+ method public void onResolveTextDirection();
method protected void onRestoreInstanceState(android.os.Parcelable);
method protected android.os.Parcelable onSaveInstanceState();
method protected void onScrollChanged(int, int, int, int);
@@ -23301,8 +23347,11 @@
method public void requestLayout();
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
+ method public void resetResolvedTextDirection();
+ method public void resolvePadding();
method public static int resolveSize(int, int);
method public static int resolveSizeAndState(int, int, int);
+ method public void resolveTextDirection();
method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -23361,6 +23410,7 @@
method public void setOnTouchListener(android.view.View.OnTouchListener);
method public void setOverScrollMode(int);
method public void setPadding(int, int, int, int);
+ method public void setPaddingRelative(int, int, int, int);
method public void setPivotX(float);
method public void setPivotY(float);
method public void setPressed(boolean);
@@ -23382,6 +23432,7 @@
method public void setSystemUiVisibility(int);
method public void setTag(java.lang.Object);
method public void setTag(int, java.lang.Object);
+ method public void setTextDirection(int);
method public final void setTop(int);
method public void setTouchDelegate(android.view.TouchDelegate);
method public void setTranslationX(float);
@@ -23404,6 +23455,7 @@
method public boolean willNotCacheDrawing();
method public boolean willNotDraw();
field public static final android.util.Property ALPHA;
+ field protected static int DEFAULT_TEXT_DIRECTION;
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -23480,6 +23532,12 @@
field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
+ field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
+ field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
+ field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
+ field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
+ field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
+ field public static final int TEXT_DIRECTION_RTL = 4; // 0x4
field public static final android.util.Property TRANSLATION_X;
field public static final android.util.Property TRANSLATION_Y;
field protected static final java.lang.String VIEW_LOG_TAG = "View";
@@ -23746,7 +23804,6 @@
method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void requestTransparentRegion(android.view.View);
method protected void resetResolvedLayoutDirection();
- method protected void resetResolvedTextDirection();
method public void scheduleLayoutAnimation();
method public void setAddStatesFromChildren(boolean);
method public void setAlwaysDrawnWithCacheEnabled(boolean);
@@ -23798,10 +23855,15 @@
ctor public ViewGroup.MarginLayoutParams(int, int);
ctor public ViewGroup.MarginLayoutParams(android.view.ViewGroup.MarginLayoutParams);
ctor public ViewGroup.MarginLayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getMarginEnd();
+ method public int getMarginStart();
+ method public boolean isMarginRelative();
method public void setMargins(int, int, int, int);
field public int bottomMargin;
+ field public int endMargin;
field public int leftMargin;
field public int rightMargin;
+ field public int startMargin;
field public int topMargin;
}
@@ -24892,6 +24954,7 @@
method public void showSoftInputFromInputMethod(android.os.IBinder, int);
method public void showStatusIcon(android.os.IBinder, java.lang.String, int);
method public boolean switchToLastInputMethod(android.os.IBinder);
+ method public boolean switchToNextInputMethod(android.os.IBinder, boolean);
method public void toggleSoftInput(int, int);
method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
method public void updateCursor(android.view.View, int, int, int, int);
@@ -26386,10 +26449,12 @@
field public static final android.widget.GridLayout.Alignment BASELINE;
field public static final android.widget.GridLayout.Alignment BOTTOM;
field public static final android.widget.GridLayout.Alignment CENTER;
+ field public static final android.widget.GridLayout.Alignment END;
field public static final android.widget.GridLayout.Alignment FILL;
field public static final int HORIZONTAL = 0; // 0x0
field public static final android.widget.GridLayout.Alignment LEFT;
field public static final android.widget.GridLayout.Alignment RIGHT;
+ field public static final android.widget.GridLayout.Alignment START;
field public static final android.widget.GridLayout.Alignment TOP;
field public static final int UNDEFINED = -2147483648; // 0x80000000
field public static final int VERTICAL = 1; // 0x1
@@ -27572,7 +27637,6 @@
method protected void resetResolvedDrawables();
method protected void resetResolvedLayoutDirection();
method protected void resolveDrawables();
- method protected void resolveTextDirection();
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3d36ebf..901f7c7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -215,6 +215,22 @@
list[i] = Long.valueOf(strings[i]);
}
intent.putExtra(key, list);
+ hasIntentInfo = true;
+ } else if (opt.equals("--ef")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Float.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("--efa")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ float[] list = new float[strings.length];
+ for (int i = 0; i < strings.length; i++) {
+ list[i] = Float.valueOf(strings[i]);
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
} else if (opt.equals("--ez")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -1342,9 +1358,11 @@
" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
" [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
" [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+ " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
" [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
" [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
+ " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
" [--debug-log-resolution] [--exclude-stopped-packages]\n" +
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index d4e669b..ea1888b 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
#include <utils/String8.h>
#include <fcntl.h>
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 0d5b4ca..3545ace 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -25,12 +25,12 @@
#include <cutils/properties.h>
+#include <androidfw/AssetManager.h>
#include <binder/IPCThreadState.h>
-#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/AssetManager.h>
+#include <utils/threads.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 8e28bba..c85d72c 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -20,8 +20,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <androidfw/AssetManager.h>
#include <utils/threads.h>
-#include <utils/AssetManager.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk
new file mode 100644
index 0000000..a3d83cf
--- /dev/null
+++ b/cmds/content/Android.mk
@@ -0,0 +1,35 @@
+# Copyright 2012 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE := content
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+ALL_PREBUILT += $(TARGET_OUT)/bin/content
+$(TARGET_OUT)/bin/content : $(LOCAL_PATH)/content | $(ACP)
+ $(transform-prebuilt-to-target)
+
+NOTICE_FILE := NOTICE
+files_noticed := bin/content
+
+# Generate rules for a single file. The argument is the file path relative to
+# the installation root
+define make-notice-file
+
+$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
+ @echo Notice file: $$< -- $$@
+ @mkdir -p $$(dir $$@)
+ @cat $$< >> $$@
+
+$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
+
+endef
+
+$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
diff --git a/cmds/content/MODULE_LICENSE_APACHE2 b/cmds/content/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/content/MODULE_LICENSE_APACHE2
diff --git a/cmds/content/NOTICE b/cmds/content/NOTICE
new file mode 100644
index 0000000..33ff961
--- /dev/null
+++ b/cmds/content/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2012, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/content/content b/cmds/content/content
new file mode 100755
index 0000000..a8e056d
--- /dev/null
+++ b/cmds/content/content
@@ -0,0 +1,5 @@
+# Script to start "content" on the device, which has a very rudimentary shell.
+base=/system
+export CLASSPATH=$base/framework/content.jar
+exec app_process $base/bin com.android.commands.content.Content "$@"
+
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
new file mode 100644
index 0000000..1dcba70
--- /dev/null
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -0,0 +1,442 @@
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.commands.content;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.IActivityManager.ContentProviderHolder;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.text.TextUtils;
+
+/**
+ * This class is a command line utility for manipulating content. A client
+ * can insert, update, and remove records in a content provider. For example,
+ * some settings may be configured before running the CTS tests, etc.
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>
+ * # Add "new_setting" secure setting with value "new_value".</br>
+ * adb shell content insert --uri content://settings/secure --bind name:s:new_setting
+ * --bind value:s:new_value
+ * </li>
+ * <li>
+ * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in
+ * the where clause).</br>
+ * adb shell content update --uri content://settings/secure --bind value:s:newer_value
+ * --where "name=\'new_setting\'"
+ * </li>
+ * <li>
+ * # Remove "new_setting" secure setting.</br>
+ * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'"
+ * </li>
+ * <li>
+ * # Query \"name\" and \"value\" columns from secure settings where \"name\" is equal to"
+ * \"new_setting\" and sort the result by name in ascending order.\n"
+ * adb shell content query --uri content://settings/secure --projection name:value
+ * --where "name=\'new_setting\'" --sort \"name ASC\"
+ * </li>
+ * </ul>
+ * </p>
+ */
+public class Content {
+
+ private static final String USAGE =
+ "usage: adb shell content [subcommand] [options]\n"
+ + "\n"
+ + "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]\n"
+ + " <URI> a content provider URI.\n"
+ + " <BINDING> binds a typed value to a column and is formatted:\n"
+ + " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
+ + " <TYPE> specifies data type such as:\n"
+ + " b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
+ + " Example:\n"
+ + " # Add \"new_setting\" secure setting with value \"new_value\".\n"
+ + " adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+ + " --bind value:s:new_value\n"
+ + "\n"
+ + "usage: adb shell content update --uri <URI> [--where <WHERE>]\n"
+ + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+ + " - see example below).\n"
+ + " Example:\n"
+ + " # Change \"new_setting\" secure setting to \"newer_value\".\n"
+ + " adb shell content update --uri content://settings/secure --bind"
+ + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+ + "\n"
+ + "usage: adb shell content delete --uri <URI> --bind <BINDING>"
+ + " [--bind <BINDING>...] [--where <WHERE>]\n"
+ + " Example:\n"
+ + " # Remove \"new_setting\" secure setting.\n"
+ + " adb shell content delete --uri content://settings/secure "
+ + "--where \"name=\'new_setting\'\"\n"
+ + "\n"
+ + "usage: adb shell content query --uri <URI> [--projection <PROJECTION>]"
+ + " [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+ + " <PROJECTION> is a list of colon separated column names and is formatted:\n"
+ + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+ + " <SORT_OREDER> is the order in which rows in the result should be sorted.\n"
+ + " Example:\n"
+ + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
+ + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
+ + " adb shell content query --uri content://settings/secure --projection name:value"
+ + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
+ + "\n";
+
+ private static class Parser {
+ private static final String ARGUMENT_INSERT = "insert";
+ private static final String ARGUMENT_DELETE = "delete";
+ private static final String ARGUMENT_UPDATE = "update";
+ private static final String ARGUMENT_QUERY = "query";
+ private static final String ARGUMENT_WHERE = "--where";
+ private static final String ARGUMENT_BIND = "--bind";
+ private static final String ARGUMENT_URI = "--uri";
+ private static final String ARGUMENT_PROJECTION = "--projection";
+ private static final String ARGUMENT_SORT = "--sort";
+ private static final String TYPE_BOOLEAN = "b";
+ private static final String TYPE_STRING = "s";
+ private static final String TYPE_INTEGER = "i";
+ private static final String TYPE_LONG = "l";
+ private static final String TYPE_FLOAT = "f";
+ private static final String TYPE_DOUBLE = "d";
+ private static final String COLON = ":";
+ private static final String ARGUMENT_PREFIX = "--";
+
+ private final Tokenizer mTokenizer;
+
+ public Parser(String[] args) {
+ mTokenizer = new Tokenizer(args);
+ }
+
+ public Command parseCommand() {
+ try {
+ String operation = mTokenizer.nextArg();
+ if (ARGUMENT_INSERT.equals(operation)) {
+ return parseInsertCommand();
+ } else if (ARGUMENT_DELETE.equals(operation)) {
+ return parseDeleteCommand();
+ } else if (ARGUMENT_UPDATE.equals(operation)) {
+ return parseUpdateCommand();
+ } else if (ARGUMENT_QUERY.equals(operation)) {
+ return parseQueryCommand();
+ } else {
+ throw new IllegalArgumentException("Unsupported operation: " + operation);
+ }
+ } catch (IllegalArgumentException iae) {
+ System.out.println(USAGE);
+ System.out.println("[ERROR] " + iae.getMessage());
+ return null;
+ }
+ }
+
+ private InsertCommand parseInsertCommand() {
+ Uri uri = null;
+ ContentValues values = new ContentValues();
+ for (String argument; (argument = mTokenizer.nextArg()) != null;) {
+ if (ARGUMENT_URI.equals(argument)) {
+ uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_BIND.equals(argument)) {
+ parseBindValue(values);
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Content provider URI not specified."
+ + " Did you specify --uri argument?");
+ }
+ if (values.size() == 0) {
+ throw new IllegalArgumentException("Bindings not specified."
+ + " Did you specify --bind argument(s)?");
+ }
+ return new InsertCommand(uri, values);
+ }
+
+ private DeleteCommand parseDeleteCommand() {
+ Uri uri = null;
+ String where = null;
+ for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+ if (ARGUMENT_URI.equals(argument)) {
+ uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_WHERE.equals(argument)) {
+ where = argumentValueRequired(argument);
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Content provider URI not specified."
+ + " Did you specify --uri argument?");
+ }
+ return new DeleteCommand(uri, where);
+ }
+
+ private UpdateCommand parseUpdateCommand() {
+ Uri uri = null;
+ String where = null;
+ ContentValues values = new ContentValues();
+ for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+ if (ARGUMENT_URI.equals(argument)) {
+ uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_WHERE.equals(argument)) {
+ where = argumentValueRequired(argument);
+ } else if (ARGUMENT_BIND.equals(argument)) {
+ parseBindValue(values);
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Content provider URI not specified."
+ + " Did you specify --uri argument?");
+ }
+ if (values.size() == 0) {
+ throw new IllegalArgumentException("Bindings not specified."
+ + " Did you specify --bind argument(s)?");
+ }
+ return new UpdateCommand(uri, values, where);
+ }
+
+ public QueryCommand parseQueryCommand() {
+ Uri uri = null;
+ String[] projection = null;
+ String sort = null;
+ String where = null;
+ for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+ if (ARGUMENT_URI.equals(argument)) {
+ uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_WHERE.equals(argument)) {
+ where = argumentValueRequired(argument);
+ } else if (ARGUMENT_SORT.equals(argument)) {
+ sort = argumentValueRequired(argument);
+ } else if (ARGUMENT_PROJECTION.equals(argument)) {
+ projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Content provider URI not specified."
+ + " Did you specify --uri argument?");
+ }
+ return new QueryCommand(uri, projection, where, sort);
+ }
+
+ private void parseBindValue(ContentValues values) {
+ String argument = mTokenizer.nextArg();
+ if (TextUtils.isEmpty(argument)) {
+ throw new IllegalArgumentException("Binding not well formed: " + argument);
+ }
+ String[] binding = argument.split(COLON);
+ if (binding.length != 3) {
+ throw new IllegalArgumentException("Binding not well formed: " + argument);
+ }
+ String column = binding[0];
+ String type = binding[1];
+ String value = binding[2];
+ if (TYPE_STRING.equals(type)) {
+ values.put(column, value);
+ } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
+ values.put(column, Boolean.parseBoolean(value));
+ } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
+ values.put(column, Long.parseLong(value));
+ } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
+ values.put(column, Double.parseDouble(value));
+ } else {
+ throw new IllegalArgumentException("Unsupported type: " + type);
+ }
+ }
+
+ private String argumentValueRequired(String argument) {
+ String value = mTokenizer.nextArg();
+ if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
+ throw new IllegalArgumentException("No value for argument: " + argument);
+ }
+ return value;
+ }
+ }
+
+ private static class Tokenizer {
+ private final String[] mArgs;
+ private int mNextArg;
+
+ public Tokenizer(String[] args) {
+ mArgs = args;
+ }
+
+ private String nextArg() {
+ if (mNextArg < mArgs.length) {
+ return mArgs[mNextArg++];
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static abstract class Command {
+ final Uri mUri;
+
+ public Command(Uri uri) {
+ mUri = uri;
+ }
+
+ public final void execute() {
+ String providerName = mUri.getAuthority();
+ try {
+ IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IContentProvider provider = null;
+ IBinder token = new Binder();
+ try {
+ ContentProviderHolder holder = activityManager.getContentProviderExternal(
+ providerName, token);
+ if (holder == null) {
+ throw new IllegalStateException("Could not find provider: " + providerName);
+ }
+ provider = holder.provider;
+ onExecute(provider);
+ } finally {
+ if (provider != null) {
+ activityManager.removeContentProviderExternal(providerName, token);
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("Error while accessing provider:" + providerName);
+ e.printStackTrace();
+ }
+ }
+
+ protected abstract void onExecute(IContentProvider provider) throws Exception;
+ }
+
+ private static class InsertCommand extends Command {
+ final ContentValues mContentValues;
+
+ public InsertCommand(Uri uri, ContentValues contentValues) {
+ super(uri);
+ mContentValues = contentValues;
+ }
+
+ @Override
+ public void onExecute(IContentProvider provider) throws Exception {
+ provider.insert(mUri, mContentValues);
+ }
+ }
+
+ private static class DeleteCommand extends Command {
+ final String mWhere;
+
+ public DeleteCommand(Uri uri, String where) {
+ super(uri);
+ mWhere = where;
+ }
+
+ @Override
+ public void onExecute(IContentProvider provider) throws Exception {
+ provider.delete(mUri, mWhere, null);
+ }
+ }
+
+ private static class QueryCommand extends DeleteCommand {
+ final String[] mProjection;
+ final String mSortOrder;
+
+ public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) {
+ super(uri, where);
+ mProjection = projection;
+ mSortOrder = sortOrder;
+ }
+
+ @Override
+ public void onExecute(IContentProvider provider) throws Exception {
+ Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null);
+ if (cursor == null) {
+ System.out.println("No result found.");
+ return;
+ }
+ try {
+ if (cursor.moveToFirst()) {
+ int rowIndex = 0;
+ StringBuilder builder = new StringBuilder();
+ do {
+ builder.setLength(0);
+ builder.append("Row: ").append(rowIndex).append(" ");
+ rowIndex++;
+ final int columnCount = cursor.getColumnCount();
+ for (int i = 0; i < columnCount; i++) {
+ if (i > 0) {
+ builder.append(", ");
+ }
+ String columnName = cursor.getColumnName(i);
+ String columnValue = null;
+ final int columnIndex = cursor.getColumnIndex(columnName);
+ final int type = cursor.getType(columnIndex);
+ switch (type) {
+ case Cursor.FIELD_TYPE_FLOAT:
+ columnValue = String.valueOf(cursor.getFloat(columnIndex));
+ break;
+ case Cursor.FIELD_TYPE_INTEGER:
+ columnValue = String.valueOf(cursor.getInt(columnIndex));
+ break;
+ case Cursor.FIELD_TYPE_STRING:
+ columnValue = cursor.getString(columnIndex);
+ break;
+ case Cursor.FIELD_TYPE_BLOB:
+ columnValue = "BLOB";
+ break;
+ case Cursor.FIELD_TYPE_NULL:
+ columnValue = "NULL";
+ break;
+ }
+ builder.append(columnName).append("=").append(columnValue);
+ }
+ System.out.println(builder);
+ } while (cursor.moveToNext());
+ } else {
+ System.out.println("No reuslt found.");
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+
+ private static class UpdateCommand extends InsertCommand {
+ final String mWhere;
+
+ public UpdateCommand(Uri uri, ContentValues contentValues, String where) {
+ super(uri, contentValues);
+ mWhere = where;
+ }
+
+ @Override
+ public void onExecute(IContentProvider provider) throws Exception {
+ provider.update(mUri, mContentValues, mWhere, null);
+ }
+ }
+
+ public static void main(String[] args) {
+ Parser parser = new Parser(args);
+ Command command = parser.parseCommand();
+ if (command != null) {
+ command.execute();
+ }
+ }
+}
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
deleted file mode 100644
index 5a9b979..0000000
--- a/cmds/keystore/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := keystore.cpp
-LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto
-LOCAL_MODULE:= keystore
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := keystore_cli.cpp
-LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto
-LOCAL_MODULE:= keystore_cli
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp
deleted file mode 100644
index 05f77e5..0000000
--- a/cmds/keystore/keystore.cpp
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <arpa/inet.h>
-
-#include <openssl/aes.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-
-#define LOG_TAG "keystore"
-#include <cutils/log.h>
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-
-#include "keystore.h"
-
-/* KeyStore is a secured storage for key-value pairs. In this implementation,
- * each file stores one key-value pair. Keys are encoded in file names, and
- * values are encrypted with checksums. The encryption key is protected by a
- * user-defined password. To keep things simple, buffers are always larger than
- * the maximum space we needed, so boundary checks on buffers are omitted. */
-
-#define KEY_SIZE ((NAME_MAX - 15) / 2)
-#define VALUE_SIZE 32768
-#define PASSWORD_SIZE VALUE_SIZE
-
-struct Value {
- int length;
- uint8_t value[VALUE_SIZE];
-};
-
-/* Here is the encoding of keys. This is necessary in order to allow arbitrary
- * characters in keys. Characters in [0-~] are not encoded. Others are encoded
- * into two bytes. The first byte is one of [+-.] which represents the first
- * two bits of the character. The second byte encodes the rest of the bits into
- * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
- * that Base64 cannot be used here due to the need of prefix match on keys. */
-
-static int encode_key(char* out, uid_t uid, const Value* key) {
- int n = snprintf(out, NAME_MAX, "%u_", uid);
- out += n;
- const uint8_t* in = key->value;
- int length = key->length;
- for (int i = length; i > 0; --i, ++in, ++out) {
- if (*in >= '0' && *in <= '~') {
- *out = *in;
- } else {
- *out = '+' + (*in >> 6);
- *++out = '0' + (*in & 0x3F);
- ++length;
- }
- }
- *out = '\0';
- return n + length;
-}
-
-static int decode_key(uint8_t* out, char* in, int length) {
- for (int i = 0; i < length; ++i, ++in, ++out) {
- if (*in >= '0' && *in <= '~') {
- *out = *in;
- } else {
- *out = (*in - '+') << 6;
- *out |= (*++in - '0') & 0x3F;
- --length;
- }
- }
- *out = '\0';
- return length;
-}
-
-static size_t readFully(int fd, uint8_t* data, size_t size) {
- size_t remaining = size;
- while (remaining > 0) {
- ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, size));
- if (n == -1 || n == 0) {
- return size-remaining;
- }
- data += n;
- remaining -= n;
- }
- return size;
-}
-
-static size_t writeFully(int fd, uint8_t* data, size_t size) {
- size_t remaining = size;
- while (remaining > 0) {
- ssize_t n = TEMP_FAILURE_RETRY(write(fd, data, size));
- if (n == -1 || n == 0) {
- return size-remaining;
- }
- data += n;
- remaining -= n;
- }
- return size;
-}
-
-class Entropy {
-public:
- Entropy() : mRandom(-1) {}
- ~Entropy() {
- if (mRandom != -1) {
- close(mRandom);
- }
- }
-
- bool open() {
- const char* randomDevice = "/dev/urandom";
- mRandom = ::open(randomDevice, O_RDONLY);
- if (mRandom == -1) {
- ALOGE("open: %s: %s", randomDevice, strerror(errno));
- return false;
- }
- return true;
- }
-
- bool generate_random_data(uint8_t* data, size_t size) {
- return (readFully(mRandom, data, size) == size);
- }
-
-private:
- int mRandom;
-};
-
-/* Here is the file format. There are two parts in blob.value, the secret and
- * the description. The secret is stored in ciphertext, and its original size
- * can be found in blob.length. The description is stored after the secret in
- * plaintext, and its size is specified in blob.info. The total size of the two
- * parts must be no more than VALUE_SIZE bytes. The first three bytes of the
- * file are reserved for future use and are always set to zero. Fields other
- * than blob.info, blob.length, and blob.value are modified by encryptBlob()
- * and decryptBlob(). Thus they should not be accessed from outside. */
-
-struct __attribute__((packed)) blob {
- uint8_t reserved[3];
- uint8_t info;
- uint8_t vector[AES_BLOCK_SIZE];
- uint8_t encrypted[0];
- uint8_t digest[MD5_DIGEST_LENGTH];
- uint8_t digested[0];
- int32_t length; // in network byte order when encrypted
- uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE];
-};
-
-class Blob {
-public:
- Blob(uint8_t* value, int32_t valueLength, uint8_t* info, uint8_t infoLength) {
- mBlob.length = valueLength;
- memcpy(mBlob.value, value, valueLength);
-
- mBlob.info = infoLength;
- memcpy(mBlob.value + valueLength, info, infoLength);
- }
-
- Blob(blob b) {
- mBlob = b;
- }
-
- Blob() {}
-
- uint8_t* getValue() {
- return mBlob.value;
- }
-
- int32_t getLength() {
- return mBlob.length;
- }
-
- uint8_t getInfo() {
- return mBlob.info;
- }
-
- ResponseCode encryptBlob(const char* filename, AES_KEY *aes_key, Entropy* entropy) {
- if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) {
- return SYSTEM_ERROR;
- }
-
- // data includes the value and the value's length
- size_t dataLength = mBlob.length + sizeof(mBlob.length);
- // pad data to the AES_BLOCK_SIZE
- size_t digestedLength = ((dataLength + AES_BLOCK_SIZE - 1)
- / AES_BLOCK_SIZE * AES_BLOCK_SIZE);
- // encrypted data includes the digest value
- size_t encryptedLength = digestedLength + MD5_DIGEST_LENGTH;
- // move info after space for padding
- memmove(&mBlob.encrypted[encryptedLength], &mBlob.value[mBlob.length], mBlob.info);
- // zero padding area
- memset(mBlob.value + mBlob.length, 0, digestedLength - dataLength);
-
- mBlob.length = htonl(mBlob.length);
- MD5(mBlob.digested, digestedLength, mBlob.digest);
-
- uint8_t vector[AES_BLOCK_SIZE];
- memcpy(vector, mBlob.vector, AES_BLOCK_SIZE);
- AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength,
- aes_key, vector, AES_ENCRYPT);
-
- memset(mBlob.reserved, 0, sizeof(mBlob.reserved));
- size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob);
- size_t fileLength = encryptedLength + headerLength + mBlob.info;
-
- const char* tmpFileName = ".tmp";
- int out = open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
- if (out == -1) {
- return SYSTEM_ERROR;
- }
- size_t writtenBytes = writeFully(out, (uint8_t*) &mBlob, fileLength);
- if (close(out) != 0) {
- return SYSTEM_ERROR;
- }
- if (writtenBytes != fileLength) {
- unlink(tmpFileName);
- return SYSTEM_ERROR;
- }
- return (rename(tmpFileName, filename) == 0) ? NO_ERROR : SYSTEM_ERROR;
- }
-
- ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) {
- int in = open(filename, O_RDONLY);
- if (in == -1) {
- return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
- }
- // fileLength may be less than sizeof(mBlob) since the in
- // memory version has extra padding to tolerate rounding up to
- // the AES_BLOCK_SIZE
- size_t fileLength = readFully(in, (uint8_t*) &mBlob, sizeof(mBlob));
- if (close(in) != 0) {
- return SYSTEM_ERROR;
- }
- size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob);
- if (fileLength < headerLength) {
- return VALUE_CORRUPTED;
- }
-
- ssize_t encryptedLength = fileLength - (headerLength + mBlob.info);
- if (encryptedLength < 0 || encryptedLength % AES_BLOCK_SIZE != 0) {
- return VALUE_CORRUPTED;
- }
- AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key,
- mBlob.vector, AES_DECRYPT);
- size_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
- uint8_t computedDigest[MD5_DIGEST_LENGTH];
- MD5(mBlob.digested, digestedLength, computedDigest);
- if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
- return VALUE_CORRUPTED;
- }
-
- ssize_t maxValueLength = digestedLength - sizeof(mBlob.length);
- mBlob.length = ntohl(mBlob.length);
- if (mBlob.length < 0 || mBlob.length > maxValueLength) {
- return VALUE_CORRUPTED;
- }
- if (mBlob.info != 0) {
- // move info from after padding to after data
- memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info);
- }
- return NO_ERROR;
- }
-
-private:
- struct blob mBlob;
-};
-
-class KeyStore {
-public:
- KeyStore(Entropy* entropy) : mEntropy(entropy), mRetry(MAX_RETRY) {
- if (access(MASTER_KEY_FILE, R_OK) == 0) {
- setState(STATE_LOCKED);
- } else {
- setState(STATE_UNINITIALIZED);
- }
- }
-
- State getState() {
- return mState;
- }
-
- int8_t getRetry() {
- return mRetry;
- }
-
- ResponseCode initialize(Value* pw) {
- if (!generateMasterKey()) {
- return SYSTEM_ERROR;
- }
- ResponseCode response = writeMasterKey(pw);
- if (response != NO_ERROR) {
- return response;
- }
- setupMasterKeys();
- return NO_ERROR;
- }
-
- ResponseCode writeMasterKey(Value* pw) {
- uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
- generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
- AES_KEY passwordAesKey;
- AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
- Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt));
- return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy);
- }
-
- ResponseCode readMasterKey(Value* pw) {
- int in = open(MASTER_KEY_FILE, O_RDONLY);
- if (in == -1) {
- return SYSTEM_ERROR;
- }
-
- // we read the raw blob to just to get the salt to generate
- // the AES key, then we create the Blob to use with decryptBlob
- blob rawBlob;
- size_t length = readFully(in, (uint8_t*) &rawBlob, sizeof(rawBlob));
- if (close(in) != 0) {
- return SYSTEM_ERROR;
- }
- // find salt at EOF if present, otherwise we have an old file
- uint8_t* salt;
- if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
- salt = (uint8_t*) &rawBlob + length - SALT_SIZE;
- } else {
- salt = NULL;
- }
- uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
- generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
- AES_KEY passwordAesKey;
- AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
- Blob masterKeyBlob(rawBlob);
- ResponseCode response = masterKeyBlob.decryptBlob(MASTER_KEY_FILE, &passwordAesKey);
- if (response == SYSTEM_ERROR) {
- return SYSTEM_ERROR;
- }
- if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
- // if salt was missing, generate one and write a new master key file with the salt.
- if (salt == NULL) {
- if (!generateSalt()) {
- return SYSTEM_ERROR;
- }
- response = writeMasterKey(pw);
- }
- if (response == NO_ERROR) {
- memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
- setupMasterKeys();
- }
- return response;
- }
- if (mRetry <= 0) {
- reset();
- return UNINITIALIZED;
- }
- --mRetry;
- switch (mRetry) {
- case 0: return WRONG_PASSWORD_0;
- case 1: return WRONG_PASSWORD_1;
- case 2: return WRONG_PASSWORD_2;
- case 3: return WRONG_PASSWORD_3;
- default: return WRONG_PASSWORD_3;
- }
- }
-
- bool reset() {
- clearMasterKeys();
- setState(STATE_UNINITIALIZED);
-
- DIR* dir = opendir(".");
- struct dirent* file;
-
- if (!dir) {
- return false;
- }
- while ((file = readdir(dir)) != NULL) {
- unlink(file->d_name);
- }
- closedir(dir);
- return true;
- }
-
- bool isEmpty() {
- DIR* dir = opendir(".");
- struct dirent* file;
- if (!dir) {
- return true;
- }
- bool result = true;
- while ((file = readdir(dir)) != NULL) {
- if (isKeyFile(file->d_name)) {
- result = false;
- break;
- }
- }
- closedir(dir);
- return result;
- }
-
- void lock() {
- clearMasterKeys();
- setState(STATE_LOCKED);
- }
-
- ResponseCode get(const char* filename, Blob* keyBlob) {
- return keyBlob->decryptBlob(filename, &mMasterKeyDecryption);
- }
-
- ResponseCode put(const char* filename, Blob* keyBlob) {
- return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy);
- }
-
-private:
- static const char* MASTER_KEY_FILE;
- static const int MASTER_KEY_SIZE_BYTES = 16;
- static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
-
- static const int MAX_RETRY = 4;
- static const size_t SALT_SIZE = 16;
-
- Entropy* mEntropy;
-
- State mState;
- int8_t mRetry;
-
- uint8_t mMasterKey[MASTER_KEY_SIZE_BYTES];
- uint8_t mSalt[SALT_SIZE];
-
- AES_KEY mMasterKeyEncryption;
- AES_KEY mMasterKeyDecryption;
-
- void setState(State state) {
- mState = state;
- if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
- mRetry = MAX_RETRY;
- }
- }
-
- bool generateSalt() {
- return mEntropy->generate_random_data(mSalt, sizeof(mSalt));
- }
-
- bool generateMasterKey() {
- if (!mEntropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
- return false;
- }
- if (!generateSalt()) {
- return false;
- }
- return true;
- }
-
- void setupMasterKeys() {
- AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption);
- AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption);
- setState(STATE_NO_ERROR);
- }
-
- void clearMasterKeys() {
- memset(mMasterKey, 0, sizeof(mMasterKey));
- memset(mSalt, 0, sizeof(mSalt));
- memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption));
- memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
- }
-
- static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, Value* pw, uint8_t* salt) {
- size_t saltSize;
- if (salt != NULL) {
- saltSize = SALT_SIZE;
- } else {
- // pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
- salt = (uint8_t*) "keystore";
- // sizeof = 9, not strlen = 8
- saltSize = sizeof("keystore");
- }
- PKCS5_PBKDF2_HMAC_SHA1((char*) pw->value, pw->length, salt, saltSize, 8192, keySize, key);
- }
-
- static bool isKeyFile(const char* filename) {
- return ((strcmp(filename, MASTER_KEY_FILE) != 0)
- && (strcmp(filename, ".") != 0)
- && (strcmp(filename, "..") != 0));
- }
-};
-
-const char* KeyStore::MASTER_KEY_FILE = ".masterkey";
-
-/* Here is the protocol used in both requests and responses:
- * code [length_1 message_1 ... length_n message_n] end-of-file
- * where code is one byte long and lengths are unsigned 16-bit integers in
- * network order. Thus the maximum length of a message is 65535 bytes. */
-
-static int recv_code(int sock, int8_t* code) {
- return recv(sock, code, 1, 0) == 1;
-}
-
-static int recv_message(int sock, uint8_t* message, int length) {
- uint8_t bytes[2];
- if (recv(sock, &bytes[0], 1, 0) != 1 ||
- recv(sock, &bytes[1], 1, 0) != 1) {
- return -1;
- } else {
- int offset = bytes[0] << 8 | bytes[1];
- if (length < offset) {
- return -1;
- }
- length = offset;
- offset = 0;
- while (offset < length) {
- int n = recv(sock, &message[offset], length - offset, 0);
- if (n <= 0) {
- return -1;
- }
- offset += n;
- }
- }
- return length;
-}
-
-static int recv_end_of_file(int sock) {
- uint8_t byte;
- return recv(sock, &byte, 1, 0) == 0;
-}
-
-static void send_code(int sock, int8_t code) {
- send(sock, &code, 1, 0);
-}
-
-static void send_message(int sock, uint8_t* message, int length) {
- uint16_t bytes = htons(length);
- send(sock, &bytes, 2, 0);
- send(sock, message, length, 0);
-}
-
-/* Here are the actions. Each of them is a function without arguments. All
- * information is defined in global variables, which are set properly before
- * performing an action. The number of parameters required by each action is
- * fixed and defined in a table. If the return value of an action is positive,
- * it will be treated as a response code and transmitted to the client. Note
- * that the lengths of parameters are checked when they are received, so
- * boundary checks on parameters are omitted. */
-
-static const ResponseCode NO_ERROR_RESPONSE_CODE_SENT = (ResponseCode) 0;
-
-static ResponseCode test(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
- return (ResponseCode) keyStore->getState();
-}
-
-static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) {
- char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
- Blob keyBlob;
- ResponseCode responseCode = keyStore->get(filename, &keyBlob);
- if (responseCode != NO_ERROR) {
- return responseCode;
- }
- send_code(sock, NO_ERROR);
- send_message(sock, keyBlob.getValue(), keyBlob.getLength());
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
-
-static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) {
- char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
- Blob keyBlob(val->value, val->length, 0, NULL);
- return keyStore->put(filename, &keyBlob);
-}
-
-static ResponseCode del(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) {
- char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
- return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
-}
-
-static ResponseCode exist(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) {
- char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
- if (access(filename, R_OK) == -1) {
- return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
- }
- return NO_ERROR;
-}
-
-static ResponseCode saw(KeyStore* keyStore, int sock, uid_t uid, Value* keyPrefix, Value*) {
- DIR* dir = opendir(".");
- if (!dir) {
- return SYSTEM_ERROR;
- }
- char filename[NAME_MAX];
- int n = encode_key(filename, uid, keyPrefix);
- send_code(sock, NO_ERROR);
-
- struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
- if (!strncmp(filename, file->d_name, n)) {
- char* p = &file->d_name[n];
- keyPrefix->length = decode_key(keyPrefix->value, p, strlen(p));
- send_message(sock, keyPrefix->value, keyPrefix->length);
- }
- }
- closedir(dir);
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
-
-static ResponseCode reset(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
- return keyStore->reset() ? NO_ERROR : SYSTEM_ERROR;
-}
-
-/* Here is the history. To improve the security, the parameters to generate the
- * master key has been changed. To make a seamless transition, we update the
- * file using the same password when the user unlock it for the first time. If
- * any thing goes wrong during the transition, the new file will not overwrite
- * the old one. This avoids permanent damages of the existing data. */
-
-static ResponseCode password(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value*) {
- switch (keyStore->getState()) {
- case STATE_UNINITIALIZED: {
- // generate master key, encrypt with password, write to file, initialize mMasterKey*.
- return keyStore->initialize(pw);
- }
- case STATE_NO_ERROR: {
- // rewrite master key with new password.
- return keyStore->writeMasterKey(pw);
- }
- case STATE_LOCKED: {
- // read master key, decrypt with password, initialize mMasterKey*.
- return keyStore->readMasterKey(pw);
- }
- }
- return SYSTEM_ERROR;
-}
-
-static ResponseCode lock(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
- keyStore->lock();
- return NO_ERROR;
-}
-
-static ResponseCode unlock(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value* unused) {
- return password(keyStore, sock, uid, pw, unused);
-}
-
-static ResponseCode zero(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
- return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR;
-}
-
-/* Here are the permissions, actions, users, and the main function. */
-
-enum perm {
- TEST = 1,
- GET = 2,
- INSERT = 4,
- DELETE = 8,
- EXIST = 16,
- SAW = 32,
- RESET = 64,
- PASSWORD = 128,
- LOCK = 256,
- UNLOCK = 512,
- ZERO = 1024,
-};
-
-static const int MAX_PARAM = 2;
-
-static const State STATE_ANY = (State) 0;
-
-static struct action {
- ResponseCode (*run)(KeyStore* keyStore, int sock, uid_t uid, Value* param1, Value* param2);
- int8_t code;
- State state;
- uint32_t perm;
- int lengths[MAX_PARAM];
-} actions[] = {
- {test, 't', STATE_ANY, TEST, {0, 0}},
- {get, 'g', STATE_NO_ERROR, GET, {KEY_SIZE, 0}},
- {insert, 'i', STATE_NO_ERROR, INSERT, {KEY_SIZE, VALUE_SIZE}},
- {del, 'd', STATE_ANY, DELETE, {KEY_SIZE, 0}},
- {exist, 'e', STATE_ANY, EXIST, {KEY_SIZE, 0}},
- {saw, 's', STATE_ANY, SAW, {KEY_SIZE, 0}},
- {reset, 'r', STATE_ANY, RESET, {0, 0}},
- {password, 'p', STATE_ANY, PASSWORD, {PASSWORD_SIZE, 0}},
- {lock, 'l', STATE_NO_ERROR, LOCK, {0, 0}},
- {unlock, 'u', STATE_LOCKED, UNLOCK, {PASSWORD_SIZE, 0}},
- {zero, 'z', STATE_ANY, ZERO, {0, 0}},
- {NULL, 0 , STATE_ANY, 0, {0, 0}},
-};
-
-static struct user {
- uid_t uid;
- uid_t euid;
- uint32_t perms;
-} users[] = {
- {AID_SYSTEM, ~0, ~0},
- {AID_VPN, AID_SYSTEM, GET},
- {AID_WIFI, AID_SYSTEM, GET},
- {AID_ROOT, AID_SYSTEM, GET},
- {~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW},
-};
-
-static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) {
- struct user* user = users;
- struct action* action = actions;
- int i;
-
- while (~user->uid && user->uid != uid) {
- ++user;
- }
- while (action->code && action->code != code) {
- ++action;
- }
- if (!action->code) {
- return UNDEFINED_ACTION;
- }
- if (!(action->perm & user->perms)) {
- return PERMISSION_DENIED;
- }
- if (action->state != STATE_ANY && action->state != keyStore->getState()) {
- return (ResponseCode) keyStore->getState();
- }
- if (~user->euid) {
- uid = user->euid;
- }
- Value params[MAX_PARAM];
- for (i = 0; i < MAX_PARAM && action->lengths[i] != 0; ++i) {
- params[i].length = recv_message(sock, params[i].value, action->lengths[i]);
- if (params[i].length < 0) {
- return PROTOCOL_ERROR;
- }
- }
- if (!recv_end_of_file(sock)) {
- return PROTOCOL_ERROR;
- }
- return action->run(keyStore, sock, uid, ¶ms[0], ¶ms[1]);
-}
-
-int main(int argc, char* argv[]) {
- int controlSocket = android_get_control_socket("keystore");
- if (argc < 2) {
- ALOGE("A directory must be specified!");
- return 1;
- }
- if (chdir(argv[1]) == -1) {
- ALOGE("chdir: %s: %s", argv[1], strerror(errno));
- return 1;
- }
-
- Entropy entropy;
- if (!entropy.open()) {
- return 1;
- }
- if (listen(controlSocket, 3) == -1) {
- ALOGE("listen: %s", strerror(errno));
- return 1;
- }
-
- signal(SIGPIPE, SIG_IGN);
-
- KeyStore keyStore(&entropy);
- int sock;
- while ((sock = accept(controlSocket, NULL, 0)) != -1) {
- struct timeval tv;
- tv.tv_sec = 3;
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-
- struct ucred cred;
- socklen_t size = sizeof(cred);
- int credResult = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &size);
- if (credResult != 0) {
- ALOGW("getsockopt: %s", strerror(errno));
- } else {
- int8_t request;
- if (recv_code(sock, &request)) {
- State old_state = keyStore.getState();
- ResponseCode response = process(&keyStore, sock, cred.uid, request);
- if (response == NO_ERROR_RESPONSE_CODE_SENT) {
- response = NO_ERROR;
- } else {
- send_code(sock, response);
- }
- ALOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
- cred.uid,
- request, response,
- old_state, keyStore.getState(),
- keyStore.getRetry());
- }
- }
- close(sock);
- }
- ALOGE("accept: %s", strerror(errno));
- return 1;
-}
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
deleted file mode 100644
index 5ae3d24..0000000
--- a/cmds/keystore/keystore.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __KEYSTORE_H__
-#define __KEYSTORE_H__
-
-// note state values overlap with ResponseCode for the purposes of the state() API
-enum State {
- STATE_NO_ERROR = 1,
- STATE_LOCKED = 2,
- STATE_UNINITIALIZED = 3,
-};
-
-enum ResponseCode {
- NO_ERROR = STATE_NO_ERROR, // 1
- LOCKED = STATE_LOCKED, // 2
- UNINITIALIZED = STATE_UNINITIALIZED, // 3
- SYSTEM_ERROR = 4,
- PROTOCOL_ERROR = 5,
- PERMISSION_DENIED = 6,
- KEY_NOT_FOUND = 7,
- VALUE_CORRUPTED = 8,
- UNDEFINED_ACTION = 9,
- WRONG_PASSWORD_0 = 10,
- WRONG_PASSWORD_1 = 11,
- WRONG_PASSWORD_2 = 12,
- WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
-};
-
-#endif
diff --git a/cmds/keystore/keystore_cli.cpp b/cmds/keystore/keystore_cli.cpp
deleted file mode 100644
index dcd3bcb..0000000
--- a/cmds/keystore/keystore_cli.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <cutils/sockets.h>
-
-#include "keystore.h"
-
-static const char* responses[] = {
- NULL,
- /* [NO_ERROR] = */ "No error",
- /* [LOCKED] = */ "Locked",
- /* [UNINITIALIZED] = */ "Uninitialized",
- /* [SYSTEM_ERROR] = */ "System error",
- /* [PROTOCOL_ERROR] = */ "Protocol error",
- /* [PERMISSION_DENIED] = */ "Permission denied",
- /* [KEY_NOT_FOUND] = */ "Key not found",
- /* [VALUE_CORRUPTED] = */ "Value corrupted",
- /* [UNDEFINED_ACTION] = */ "Undefined action",
- /* [WRONG_PASSWORD] = */ "Wrong password (last chance)",
- /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)",
- /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)",
- /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
-};
-
-int main(int argc, char* argv[])
-{
- if (argc < 2) {
- printf("Usage: %s action [parameter ...]\n", argv[0]);
- return 0;
- }
-
- int sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock == -1) {
- puts("Failed to connect");
- return 1;
- }
-
- send(sock, argv[1], 1, 0);
- uint8_t bytes[65536];
- for (int i = 2; i < argc; ++i) {
- uint16_t length = strlen(argv[i]);
- bytes[0] = length >> 8;
- bytes[1] = length;
- send(sock, &bytes, 2, 0);
- send(sock, argv[i], length, 0);
- }
- shutdown(sock, SHUT_WR);
-
- uint8_t code;
- if (recv(sock, &code, 1, 0) != 1) {
- puts("Failed to receive");
- return 1;
- }
- printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown");
- int i;
- while ((i = recv(sock, &bytes[0], 1, 0)) == 1) {
- int length;
- int offset;
- if ((i = recv(sock, &bytes[1], 1, 0)) != 1) {
- puts("Failed to receive");
- return 1;
- }
- length = bytes[0] << 8 | bytes[1];
- for (offset = 0; offset < length; offset += i) {
- i = recv(sock, &bytes[offset], length - offset, 0);
- if (i <= 0) {
- puts("Failed to receive");
- return 1;
- }
- }
- fwrite(bytes, 1, length, stdout);
- puts("");
- }
- return 0;
-}
diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h
deleted file mode 100644
index 4b4923e..0000000
--- a/cmds/keystore/keystore_get.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __KEYSTORE_GET_H__
-#define __KEYSTORE_GET_H__
-
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <cutils/sockets.h>
-
-#define KEYSTORE_MESSAGE_SIZE 65535
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This function is provided for native components to get values from keystore.
- * Users are required to link against libcutils. Keys and values are 8-bit safe.
- * The first two arguments are the key and its length. The third argument
- * specifies the buffer to store the retrieved value, which must be an array of
- * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or
- * -1 if an error happens. */
-static int keystore_get(const char *key, int length, char *value)
-{
- uint8_t bytes[2] = {length >> 8, length};
- uint8_t code = 'g';
- int sock;
-
- if (length < 0 || length > KEYSTORE_MESSAGE_SIZE) {
- return -1;
- }
- sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock == -1) {
- return -1;
- }
- if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 &&
- send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 &&
- recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 &&
- recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) {
- int offset = 0;
- length = bytes[0] << 8 | bytes[1];
- while (offset < length) {
- int n = recv(sock, &value[offset], length - offset, 0);
- if (n <= 0) {
- length = -1;
- break;
- }
- offset += n;
- }
- } else {
- length = -1;
- }
-
- close(sock);
- return length;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/cmds/keystore/test-keystore b/cmds/keystore/test-keystore
deleted file mode 100755
index 3be51b3..0000000
--- a/cmds/keystore/test-keystore
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-set -e
-
-prefix=$0
-log_file=$prefix.log
-baseline_file=$prefix.baseline
-
-function cleanup_output() {
- rm -f $log_file
- rm -f $baseline_file
-}
-
-function log() {
- echo "$@"
- append $log_file \# "$@"
- append $baseline_file \# "$@"
-}
-
-function expect() {
- append $baseline_file "$@"
-}
-
-function append() {
- declare -r file=$1
- shift
- echo "$@" >> $file
-}
-
-function run() {
- # strip out carriage returns from adb
- # strip out date/time from ls -l
- "$@" | tr --delete '\r' | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} +[0-9]{1,2}:[0-9]{2} //' >> $log_file
-}
-
-function keystore() {
- declare -r user=$1
- shift
- run adb shell su $user keystore_cli "$@"
-}
-
-function list_keystore_directory() {
- run adb shell ls -al /data/misc/keystore
-}
-
-function compare() {
- log "comparing $baseline_file and $log_file"
- diff $baseline_file $log_file || (log $tag FAILED && exit 1)
-}
-
-function test_basic() {
-
- #
- # reset
- #
- log "reset keystore as system user"
- keystore system r
- expect "1 No error"
- list_keystore_directory
-
- #
- # basic tests as system/root
- #
- log "root does not have permission to run test"
- keystore root t
- expect "6 Permission denied"
-
- log "but system user does"
- keystore system t
- expect "3 Uninitialized"
- list_keystore_directory
-
- log "password is now bar"
- keystore system p bar
- expect "1 No error"
- list_keystore_directory
- expect "-rw------- keystore keystore 84 .masterkey"
-
- log "no error implies initialized and unlocked"
- keystore system t
- expect "1 No error"
-
- log "saw with no argument"
- keystore system s
- expect "5 Protocol error"
-
- log "saw nothing"
- keystore system s ""
- expect "1 No error"
-
- log "add key baz"
- keystore system i baz quux
- expect "1 No error"
-
- log "1000 is uid of system"
- list_keystore_directory
- expect "-rw------- keystore keystore 84 .masterkey"
- expect "-rw------- keystore keystore 52 1000_baz"
-
- log "saw baz"
- keystore system s ""
- expect "1 No error"
- expect "baz"
-
- log "get baz"
- keystore system g baz
- expect "1 No error"
- expect "quux"
-
- log "root can read system user keys (as can wifi or vpn users)"
- keystore root g baz
- expect "1 No error"
- expect "quux"
-
- #
- # app user tests
- #
-
- # app_0 has uid 10000, as seen below
- log "other uses cannot see the system keys"
- keystore app_0 g baz
- expect "7 Key not found"
-
- log "app user cannot use reset, password, lock, unlock"
- keystore app_0 r
- expect "6 Permission denied"
- keystore app_0 p
- expect "6 Permission denied"
- keystore app_0 l
- expect "6 Permission denied"
- keystore app_0 u
- expect "6 Permission denied"
-
- log "install app_0 key"
- keystore app_0 i 0x deadbeef
- expect 1 No error
- list_keystore_directory
- expect "-rw------- keystore keystore 84 .masterkey"
- expect "-rw------- keystore keystore 52 10000_0x"
- expect "-rw------- keystore keystore 52 1000_baz"
-
- log "get with no argument"
- keystore app_0 g
- expect "5 Protocol error"
-
- keystore app_0 g 0x
- expect "1 No error"
- expect "deadbeef"
-
- keystore app_0 i fred barney
- expect "1 No error"
-
- keystore app_0 s ""
- expect "1 No error"
- expect "0x"
- expect "fred"
-
- log "note that saw returns the suffix of prefix matches"
- keystore app_0 s fr # fred
- expect "1 No error"
- expect "ed" # fred
-
- #
- # lock tests
- #
- log "lock the store as system"
- keystore system l
- expect "1 No error"
- keystore system t
- expect "2 Locked"
-
- log "saw works while locked"
- keystore app_0 s ""
- expect "1 No error"
- expect "0x"
- expect "fred"
-
- log "...but cannot read keys..."
- keystore app_0 g 0x
- expect "2 Locked"
-
- log "...but they can be deleted."
- keystore app_0 e 0x
- expect "1 No error"
- keystore app_0 d 0x
- expect "1 No error"
- keystore app_0 e 0x
- expect "7 Key not found"
-
- #
- # password
- #
- log "wrong password"
- keystore system u foo
- expect "13 Wrong password (4 tries left)"
- log "right password"
- keystore system u bar
- expect "1 No error"
-
- log "make the password foo"
- keystore system p foo
- expect "1 No error"
-
- #
- # final reset
- #
- log "reset wipes everything for all users"
- keystore system r
- expect "1 No error"
- list_keystore_directory
-
- keystore system t
- expect "3 Uninitialized"
-
-}
-
-function test_4599735() {
- # http://b/4599735
- log "start regression test for b/4599735"
- keystore system r
- expect "1 No error"
-
- keystore system p foo
- expect "1 No error"
-
- keystore system i baz quux
- expect "1 No error"
-
- keystore root g baz
- expect "1 No error"
- expect "quux"
-
- keystore system l
- expect "1 No error"
-
- keystore system p foo
- expect "1 No error"
-
- log "after unlock, regression led to result of '8 Value corrupted'"
- keystore root g baz
- expect "1 No error"
- expect "quux"
-
- keystore system r
- expect "1 No error"
- log "end regression test for b/4599735"
-}
-
-function main() {
- cleanup_output
- log $tag START
- test_basic
- test_4599735
- compare
- log $tag PASSED
- cleanup_output
-}
-
-main
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 4ed2489..71c5622 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -43,6 +43,8 @@
{ AID_RADIO, "isms" },
{ AID_RADIO, "iphonesubinfo" },
{ AID_RADIO, "simphonebook" },
+ { AID_MEDIA, "common_time.clock" },
+ { AID_MEDIA, "common_time.config" },
};
void *svcmgr_handle;
@@ -90,6 +92,7 @@
struct svcinfo *next;
void *ptr;
struct binder_death death;
+ int allow_isolated;
unsigned len;
uint16_t name[0];
};
@@ -125,13 +128,21 @@
};
-void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
+void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
{
struct svcinfo *si;
si = find_svc(s, len);
// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
if (si && si->ptr) {
+ if (!si->allow_isolated) {
+ // If this service doesn't allow access from isolated processes,
+ // then check the uid to see if it is isolated.
+ unsigned appid = uid % AID_USER;
+ if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
+ return 0;
+ }
+ }
return si->ptr;
} else {
return 0;
@@ -140,10 +151,11 @@
int do_add_service(struct binder_state *bs,
uint16_t *s, unsigned len,
- void *ptr, unsigned uid)
+ void *ptr, unsigned uid, int allow_isolated)
{
struct svcinfo *si;
-// ALOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);
+ //ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,
+ // allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
if (!ptr || (len == 0) || (len > 127))
return -1;
@@ -175,6 +187,7 @@
si->name[len] = '\0';
si->death.func = svcinfo_death;
si->death.ptr = si;
+ si->allow_isolated = allow_isolated;
si->next = svclist;
svclist = si;
}
@@ -194,6 +207,7 @@
unsigned len;
void *ptr;
uint32_t strict_policy;
+ int allow_isolated;
// ALOGI("target=%p code=%d pid=%d uid=%d\n",
// txn->target, txn->code, txn->sender_pid, txn->sender_euid);
@@ -217,7 +231,7 @@
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
- ptr = do_find_service(bs, s, len);
+ ptr = do_find_service(bs, s, len, txn->sender_euid);
if (!ptr)
break;
bio_put_ref(reply, ptr);
@@ -226,7 +240,8 @@
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
ptr = bio_get_ref(msg);
- if (do_add_service(bs, s, len, ptr, txn->sender_euid))
+ allow_isolated = bio_get_uint32(msg) ? 1 : 0;
+ if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
return -1;
break;
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index e9642f7..11e94e8 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -35,7 +35,7 @@
record.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -59,7 +59,7 @@
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -84,7 +84,7 @@
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 021f636..14b4306 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -3,7 +3,7 @@
#include <math.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 858681f..a6362a4 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -2,10 +2,10 @@
#include <binder/ProcessState.h>
#include <media/mediarecorder.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -24,7 +24,7 @@
android::ProcessState::self()->startThreadPool();
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
#if 0
sp<MediaSource> source = new SineSource(kSampleRate, kNumChannels);
@@ -82,7 +82,7 @@
delete player;
player = NULL;
#elif 0
- CHECK_EQ(decoder->start(), OK);
+ CHECK_EQ(decoder->start(), (status_t)OK);
MediaBuffer *buffer;
while (decoder->read(&buffer) == OK) {
@@ -95,7 +95,7 @@
buffer = NULL;
}
- CHECK_EQ(decoder->stop(), OK);
+ CHECK_EQ(decoder->stop(), (status_t)OK);
#endif
#endif
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 7703058..45c3f7b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,11 +17,11 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaExtractor.h>
@@ -183,7 +183,7 @@
return 1;
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
status_t err = OK;
@@ -231,14 +231,14 @@
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
writer->addSource(encoder);
writer->setMaxFileDuration(kDurationUs);
- CHECK_EQ(OK, writer->start());
+ CHECK_EQ((status_t)OK, writer->start());
while (!writer->reachedEOS()) {
fprintf(stderr, ".");
usleep(100000);
}
err = writer->stop();
#else
- CHECK_EQ(OK, encoder->start());
+ CHECK_EQ((status_t)OK, encoder->start());
MediaBuffer *buffer;
while (encoder->read(&buffer) == OK) {
@@ -272,7 +272,7 @@
for (int i = 0; i < 100; ++i) {
MediaBuffer *buffer;
status_t err = source->read(&buffer);
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
printf("got a frame, data=%p, size=%d\n",
buffer->data(), buffer->range_length());
@@ -299,7 +299,7 @@
android::ProcessState::self()->startThreadPool();
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
const int32_t kSampleRate = 22050;
const int32_t kNumChannels = 2;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index c402286..3bd1fe2 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -17,9 +17,9 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MPEG4Writer.h>
@@ -243,7 +243,7 @@
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
status_t err = OK;
sp<MediaSource> source =
@@ -283,7 +283,7 @@
sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
writer->addSource(encoder);
int64_t start = systemTime();
- CHECK_EQ(OK, writer->start());
+ CHECK_EQ((status_t)OK, writer->start());
while (!writer->reachedEOS()) {
}
err = writer->stop();
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 78b1007..6dbcf5c 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -20,6 +20,6 @@
using namespace android;
int main(int argc, char** argv) {
- SurfaceFlinger::publishAndJoinThreadPool();
+ SurfaceFlinger::publishAndJoinThreadPool(true);
return 0;
}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index cc1efb9..6fbeee3 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -522,8 +522,7 @@
* animations possible.
*
*/
- private static class AnimationHandler extends Handler
- implements Choreographer.OnAnimateListener {
+ private static class AnimationHandler extends Handler implements Runnable {
// The per-thread list of all active animations
private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
@@ -539,7 +538,7 @@
private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
private final Choreographer mChoreographer;
- private boolean mIsChoreographed;
+ private boolean mAnimationScheduled;
private AnimationHandler() {
mChoreographer = Choreographer.getInstance();
@@ -644,22 +643,17 @@
// If there are still active or delayed animations, schedule a future call to
// onAnimate to process the next frame of the animations.
- if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
- if (!mIsChoreographed) {
- mIsChoreographed = true;
- mChoreographer.addOnAnimateListener(this);
- }
- mChoreographer.scheduleAnimation();
- } else {
- if (mIsChoreographed) {
- mIsChoreographed = false;
- mChoreographer.removeOnAnimateListener(this);
- }
+ if (!mAnimationScheduled
+ && (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())) {
+ mChoreographer.postAnimationCallback(this);
+ mAnimationScheduled = true;
}
}
+ // Called by the Choreographer.
@Override
- public void onAnimate() {
+ public void run() {
+ mAnimationScheduled = false;
doAnimationFrame();
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d80902d..24079a5d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -554,15 +554,6 @@
return true;
}
- case FINISH_OTHER_INSTANCES_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- ComponentName className = ComponentName.readFromParcel(data);
- finishOtherInstances(token, className);
- reply.writeNoException();
- return true;
- }
-
case REPORT_THUMBNAIL_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -590,6 +581,21 @@
return true;
}
+ case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String name = data.readString();
+ IBinder token = data.readStrongBinder();
+ ContentProviderHolder cph = getContentProviderExternal(name, token);
+ reply.writeNoException();
+ if (cph != null) {
+ reply.writeInt(1);
+ cph.writeToParcel(reply, 0);
+ } else {
+ reply.writeInt(0);
+ }
+ return true;
+ }
+
case PUBLISH_CONTENT_PROVIDERS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
@@ -610,7 +616,16 @@
reply.writeNoException();
return true;
}
-
+
+ case REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String name = data.readString();
+ IBinder token = data.readStrongBinder();
+ removeContentProviderExternal(name, token);
+ reply.writeNoException();
+ return true;
+ }
+
case GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
ComponentName comp = ComponentName.CREATOR.createFromParcel(data);
@@ -679,8 +694,9 @@
String resolvedType = data.readString();
b = data.readStrongBinder();
int fl = data.readInt();
+ int userId = data.readInt();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
- int res = bindService(app, token, service, resolvedType, conn, fl);
+ int res = bindService(app, token, service, resolvedType, conn, fl, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -1192,22 +1208,6 @@
return true;
}
- case REGISTER_ACTIVITY_WATCHER_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IActivityWatcher watcher = IActivityWatcher.Stub.asInterface(
- data.readStrongBinder());
- registerActivityWatcher(watcher);
- return true;
- }
-
- case UNREGISTER_ACTIVITY_WATCHER_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IActivityWatcher watcher = IActivityWatcher.Stub.asInterface(
- data.readStrongBinder());
- unregisterActivityWatcher(watcher);
- return true;
- }
-
case START_ACTIVITY_IN_PACKAGE_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -2164,18 +2164,6 @@
reply.recycle();
return res;
}
- public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- ComponentName.writeToParcel(className, data);
- mRemote.transact(FINISH_OTHER_INSTANCES_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public void reportThumbnail(IBinder token,
Bitmap thumbnail, CharSequence description) throws RemoteException
{
@@ -2214,6 +2202,25 @@
reply.recycle();
return cph;
}
+ public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
+ throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(name);
+ data.writeStrongBinder(token);
+ mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ ContentProviderHolder cph = null;
+ if (res != 0) {
+ cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
+ }
+ data.recycle();
+ reply.recycle();
+ return cph;
+ }
public void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) throws RemoteException
{
@@ -2240,7 +2247,19 @@
data.recycle();
reply.recycle();
}
-
+
+ public void removeContentProviderExternal(String name, IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(name);
+ data.writeStrongBinder(token);
+ mRemote.transact(REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
public PendingIntent getRunningServiceControlPanel(ComponentName service)
throws RemoteException
{
@@ -2325,7 +2344,7 @@
}
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
- int flags) throws RemoteException {
+ int flags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2335,6 +2354,7 @@
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
+ data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
@@ -3024,30 +3044,6 @@
data.recycle();
}
- public void registerActivityWatcher(IActivityWatcher watcher)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
- mRemote.transact(REGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
- public void unregisterActivityWatcher(IActivityWatcher watcher)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
- mRemote.transact(UNREGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
public int startActivityInPackage(int uid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded)
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index db5113e..6d5cce5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -42,7 +42,9 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.hardware.ISerialManager;
import android.hardware.SensorManager;
+import android.hardware.SerialManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
import android.location.CountryDetector;
@@ -428,6 +430,12 @@
return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
}});
+ registerService(SERIAL_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(SERIAL_SERVICE);
+ return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
+ }});
+
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new Vibrator();
@@ -903,6 +911,19 @@
}
}
+ /** @hide */
+ @Override
+ public void sendBroadcast(Intent intent, int userId) {
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.setAllowFds(false);
+ ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
+ intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false,
+ userId);
+ } catch (RemoteException e) {
+ }
+ }
+
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1117,6 +1138,12 @@
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
+ return bindService(service, conn, flags, UserId.getUserId(Process.myUid()));
+ }
+
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
@@ -1135,7 +1162,7 @@
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
- sd, flags);
+ sd, flags, userId);
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 39817ac..53a71db 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -145,14 +145,16 @@
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
- public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException;
/* oneway */
public void reportThumbnail(IBinder token,
Bitmap thumbnail, CharSequence description) throws RemoteException;
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name) throws RemoteException;
+ public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
+ throws RemoteException;
public void removeContentProvider(IApplicationThread caller,
String name) throws RemoteException;
+ public void removeContentProviderExternal(String name, IBinder token) throws RemoteException;
public void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) throws RemoteException;
public PendingIntent getRunningServiceControlPanel(ComponentName service)
@@ -167,7 +169,7 @@
int id, Notification notification, boolean keepNotification) throws RemoteException;
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
- IServiceConnection connection, int flags) throws RemoteException;
+ IServiceConnection connection, int flags, int userId) throws RemoteException;
public boolean unbindService(IServiceConnection connection) throws RemoteException;
public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException;
@@ -295,11 +297,6 @@
public void stopAppSwitches() throws RemoteException;
public void resumeAppSwitches() throws RemoteException;
- public void registerActivityWatcher(IActivityWatcher watcher)
- throws RemoteException;
- public void unregisterActivityWatcher(IActivityWatcher watcher)
- throws RemoteException;
-
public int startActivityInPackage(int uid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded)
@@ -421,7 +418,7 @@
source.readStrongBinder());
noReleaseNeeded = source.readInt() != 0;
}
- };
+ }
/** Information returned after waiting for an activity start. */
public static class WaitResult implements Parcelable {
@@ -505,7 +502,7 @@
int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
- int FINISH_OTHER_INSTANCES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
+
int GOING_TO_SLEEP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
int WAKING_UP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
@@ -559,8 +556,8 @@
int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
- int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
- int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
+
+
int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
@@ -607,4 +604,6 @@
int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138;
int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
+ int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140;
+ int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141;
}
diff --git a/core/java/android/app/IActivityWatcher.aidl b/core/java/android/app/IActivityWatcher.aidl
deleted file mode 100644
index 6737545..0000000
--- a/core/java/android/app/IActivityWatcher.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.app;
-
-/**
- * Callback interface to watch the user's traversal through activities.
- * {@hide}
- */
-oneway interface IActivityWatcher {
- void activityResuming(int activityId);
- void closingSystemDialogs(String reason);
-}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c1e28b0..c057d66 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -30,6 +30,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -433,7 +434,12 @@
*/
public WallpaperInfo getWallpaperInfo() {
try {
- return sGlobals.mService.getWallpaperInfo();
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ } else {
+ return sGlobals.mService.getWallpaperInfo();
+ }
} catch (RemoteException e) {
return null;
}
@@ -451,6 +457,10 @@
* wallpaper.
*/
public void setResource(int resid) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
try {
Resources resources = mContext.getResources();
/* Set the wallpaper to the default values */
@@ -483,6 +493,10 @@
* wallpaper.
*/
public void setBitmap(Bitmap bitmap) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
if (fd == null) {
@@ -515,6 +529,10 @@
* wallpaper.
*/
public void setStream(InputStream data) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
if (fd == null) {
@@ -558,6 +576,10 @@
* mandatory.
*/
public int getDesiredMinimumWidth() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return 0;
+ }
try {
return sGlobals.mService.getWidthHint();
} catch (RemoteException e) {
@@ -581,6 +603,10 @@
* mandatory.
*/
public int getDesiredMinimumHeight() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return 0;
+ }
try {
return sGlobals.mService.getHeightHint();
} catch (RemoteException e) {
@@ -599,7 +625,11 @@
*/
public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
try {
- sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ } else {
+ sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+ }
} catch (RemoteException e) {
// Ignore
}
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 170171e..a74a268 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -38,15 +38,23 @@
private static final boolean DEBUG = false;
// This path must match what the WallpaperManagerService uses
- private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ public static final String WALLPAPER_IMAGE = "/data/system/users/0/wallpaper";
+ public static final String WALLPAPER_INFO = "/data/system/users/0/wallpaper_info.xml";
+ // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+ public static final String WALLPAPER_IMAGE_KEY =
+ "/data/data/com.android.settings/files/wallpaper";
+ public static final String WALLPAPER_INFO_KEY = "/data/system/wallpaper_info.xml";
// Stage file - should be adjacent to the WALLPAPER_IMAGE location. The wallpapers
// will be saved to this file from the restore stream, then renamed to the proper
// location if it's deemed suitable.
- private static final String STAGE_FILE = "/data/data/com.android.settings/files/wallpaper-tmp";
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String STAGE_FILE = "/data/system/users/0/wallpaper-tmp";
Context mContext;
String[] mFiles;
+ String[] mKeys;
double mDesiredMinWidth;
double mDesiredMinHeight;
@@ -57,11 +65,12 @@
* @param context
* @param files
*/
- public WallpaperBackupHelper(Context context, String... files) {
+ public WallpaperBackupHelper(Context context, String[] files, String[] keys) {
super(context);
mContext = context;
mFiles = files;
+ mKeys = keys;
WallpaperManager wpm;
wpm = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
@@ -89,7 +98,7 @@
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
- performBackup_checked(oldState, data, newState, mFiles, mFiles);
+ performBackup_checked(oldState, data, newState, mFiles, mKeys);
}
/**
@@ -99,8 +108,8 @@
*/
public void restoreEntity(BackupDataInputStream data) {
final String key = data.getKey();
- if (isKeyInList(key, mFiles)) {
- if (key.equals(WALLPAPER_IMAGE)) {
+ if (isKeyInList(key, mKeys)) {
+ if (key.equals(WALLPAPER_IMAGE_KEY)) {
// restore the file to the stage for inspection
File f = new File(STAGE_FILE);
if (writeFile(f, data)) {
@@ -135,9 +144,9 @@
f.delete();
}
}
- } else {
- // Some other normal file; just decode it to its destination
- File f = new File(key);
+ } else if (key.equals(WALLPAPER_INFO_KEY)) {
+ // XML file containing wallpaper info
+ File f = new File(WALLPAPER_INFO);
writeFile(f, data);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bfbd0ac..a1198de 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -905,6 +905,16 @@
public abstract void sendBroadcast(Intent intent);
/**
+ * Same as #sendBroadcast(Intent intent), but for a specific user. Used by the system only.
+ * @param intent the intent to broadcast
+ * @param userId user to send the intent to
+ * @hide
+ */
+ public void sendBroadcast(Intent intent, int userId) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Broadcast the given intent to all interested BroadcastReceivers, allowing
* an optional required permission to be enforced. This
* call is asynchronous; it returns immediately, and you will continue
@@ -1307,6 +1317,15 @@
int flags);
/**
+ * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userId
+ * argument for use by system server and other multi-user aware code.
+ * @hide
+ */
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
@@ -1789,6 +1808,17 @@
public static final String USB_SERVICE = "usb";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.hardware.SerialManager} for access to serial ports.
+ *
+ * @see #getSystemService
+ * @see android.harware.SerialManager
+ *
+ * @hide
+ */
+ public static final String SERIAL_SERVICE = "serial";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3928aaf..5ba9dcc 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -294,6 +294,12 @@
mBase.sendBroadcast(intent);
}
+ /** @hide */
+ @Override
+ public void sendBroadcast(Intent intent, int userId) {
+ mBase.sendBroadcast(intent, userId);
+ }
+
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
mBase.sendBroadcast(intent, receiverPermission);
@@ -370,6 +376,12 @@
return mBase.bindService(service, conn, flags);
}
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ return mBase.bindService(service, conn, flags, userId);
+ }
+
@Override
public void unbindService(ServiceConnection conn) {
mBase.unbindService(conn);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2023f82..8029bd5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3380,7 +3380,8 @@
public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
if (s == null) return null;
- if (!copyNeeded(flags, s.owner, s.metaData) && userId == 0) {
+ if (!copyNeeded(flags, s.owner, s.metaData)
+ && userId == UserId.getUserId(s.info.applicationInfo.uid)) {
return s.info;
}
// Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/hardware/ISerialManager.aidl b/core/java/android/hardware/ISerialManager.aidl
new file mode 100644
index 0000000..74d30f7
--- /dev/null
+++ b/core/java/android/hardware/ISerialManager.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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 android.hardware;
+
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface ISerialManager
+{
+ /* Returns a list of all available serial ports */
+ String[] getSerialPorts();
+
+ /* Returns a file descriptor for the serial port. */
+ ParcelFileDescriptor openSerialPort(String name);
+}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index aeb5d92..3fdf246 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -616,6 +616,7 @@
Message msg = Message.obtain();
msg.what = 0;
msg.obj = t;
+ msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java
new file mode 100644
index 0000000..c5e1c2b
--- /dev/null
+++ b/core/java/android/hardware/SerialManager.java
@@ -0,0 +1,88 @@
+/*
+ * 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 android.hardware;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class SerialManager {
+ private static final String TAG = "SerialManager";
+
+ private final Context mContext;
+ private final ISerialManager mService;
+
+ /**
+ * {@hide}
+ */
+ public SerialManager(Context context, ISerialManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Returns a string array containing the names of available serial ports
+ *
+ * @return names of available serial ports
+ */
+ public String[] getSerialPorts() {
+ try {
+ return mService.getSerialPorts();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getSerialPorts", e);
+ return null;
+ }
+ }
+
+ /**
+ * Opens and returns the {@link android.hardware.SerialPort} with the given name.
+ * The speed of the serial port must be one of:
+ * 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
+ * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000,
+ * 1500000, 2000000, 2500000, 3000000, 3500000 or 4000000
+ *
+ * @param name of the serial port
+ * @param speed at which to open the serial port
+ * @return the serial port
+ */
+ public SerialPort openSerialPort(String name, int speed) throws IOException {
+ try {
+ ParcelFileDescriptor pfd = mService.openSerialPort(name);
+ if (pfd != null) {
+ SerialPort port = new SerialPort(name);
+ port.open(pfd, speed);
+ return port;
+ } else {
+ throw new IOException("Could not open serial port " + name);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "exception in UsbManager.openDevice", e);
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java
new file mode 100644
index 0000000..5ef122b
--- /dev/null
+++ b/core/java/android/hardware/SerialPort.java
@@ -0,0 +1,130 @@
+/*
+ * 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 android.hardware;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @hide
+ */
+public class SerialPort {
+
+ private static final String TAG = "SerialPort";
+
+ // used by the JNI code
+ private int mNativeContext;
+ private final String mName;
+ private ParcelFileDescriptor mFileDescriptor;
+
+ /**
+ * SerialPort should only be instantiated by SerialManager
+ * @hide
+ */
+ public SerialPort(String name) {
+ mName = name;
+ }
+
+ /**
+ * SerialPort should only be instantiated by SerialManager
+ * Speed must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
+ * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000,
+ * 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
+ *
+ * @hide
+ */
+ public void open(ParcelFileDescriptor pfd, int speed) throws IOException {
+ native_open(pfd.getFileDescriptor(), speed);
+ mFileDescriptor = pfd;
+ }
+
+ /**
+ * Closes the serial port
+ */
+ public void close() throws IOException {
+ if (mFileDescriptor != null) {
+ mFileDescriptor.close();
+ mFileDescriptor = null;
+ }
+ native_close();
+ }
+
+ /**
+ * Returns the name of the serial port
+ *
+ * @return the serial port's name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Reads data into the provided buffer
+ *
+ * @param buffer to read into
+ * @return number of bytes read
+ */
+ public int read(ByteBuffer buffer) throws IOException {
+ if (buffer.isDirect()) {
+ return native_read_direct(buffer, buffer.remaining());
+ } else if (buffer.hasArray()) {
+ return native_read_array(buffer.array(), buffer.remaining());
+ } else {
+ throw new IllegalArgumentException("buffer is not direct and has no array");
+ }
+ }
+
+ /**
+ * Writes data from provided buffer
+ *
+ * @param buffer to write
+ * @param length number of bytes to write
+ */
+ public void write(ByteBuffer buffer, int length) throws IOException {
+ if (buffer.isDirect()) {
+ native_write_direct(buffer, length);
+ } else if (buffer.hasArray()) {
+ native_write_array(buffer.array(), length);
+ } else {
+ throw new IllegalArgumentException("buffer is not direct and has no array");
+ }
+ }
+
+ /**
+ * Sends a stream of zero valued bits for 0.25 to 0.5 seconds
+ */
+ public void sendBreak() {
+ native_send_break();
+ }
+
+ private native void native_open(FileDescriptor pfd, int speed) throws IOException;
+ private native void native_close();
+ private native int native_read_array(byte[] buffer, int length) throws IOException;
+ private native int native_read_direct(ByteBuffer buffer, int length) throws IOException;
+ private native void native_write_array(byte[] buffer, int length) throws IOException;
+ private native void native_write_direct(ByteBuffer buffer, int length) throws IOException;
+ private native void native_send_break();
+}
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 21ecc22..fb09ba5 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -49,6 +49,7 @@
private LinkCapabilities mLinkCapabilities;
private NetworkInfo mNetworkInfo;
private InterfaceObserver mInterfaceObserver;
+ private String mHwAddr;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
@@ -74,15 +75,13 @@
if (mIface.equals(iface) && mLinkUp != up) {
Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
mLinkUp = up;
+ mTracker.mNetworkInfo.setIsAvailable(up);
// use DHCP
if (up) {
mTracker.reconnect();
} else {
- NetworkUtils.stopDhcp(mIface);
- mTracker.mNetworkInfo.setIsAvailable(false);
- mTracker.mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED,
- null, null);
+ mTracker.disconnect();
}
}
}
@@ -104,10 +103,6 @@
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
mLinkProperties = new LinkProperties();
mLinkCapabilities = new LinkCapabilities();
- mLinkUp = false;
-
- mNetworkInfo.setIsAvailable(false);
- setTeardownRequested(false);
}
private void interfaceAdded(String iface) {
@@ -116,7 +111,7 @@
Log.d(TAG, "Adding " + iface);
- synchronized(mIface) {
+ synchronized(this) {
if(!mIface.isEmpty())
return;
mIface = iface;
@@ -125,21 +120,15 @@
mNetworkInfo.setIsAvailable(true);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
-
- runDhcp();
}
- private void interfaceRemoved(String iface) {
- if (!iface.equals(mIface))
- return;
-
- Log.d(TAG, "Removing " + iface);
+ public void disconnect() {
NetworkUtils.stopDhcp(mIface);
mLinkProperties.clear();
mNetworkInfo.setIsAvailable(false);
- mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+ mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
@@ -147,6 +136,21 @@
msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.clearInterfaceAddresses(mIface);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
+ }
+ }
+
+ private void interfaceRemoved(String iface) {
+ if (!iface.equals(mIface))
+ return;
+
+ Log.d(TAG, "Removing " + iface);
+ disconnect();
mIface = "";
}
@@ -161,7 +165,7 @@
mLinkProperties = dhcpInfoInternal.makeLinkProperties();
mLinkProperties.setInterfaceName(mIface);
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
@@ -208,8 +212,15 @@
for (String iface : ifaces) {
if (iface.matches(sIfaceMatch)) {
mIface = iface;
+ service.setInterfaceUp(iface);
InterfaceConfiguration config = service.getInterfaceConfig(iface);
mLinkUp = config.isActive();
+ if (config != null && mHwAddr == null) {
+ mHwAddr = config.getHardwareAddress();
+ if (mHwAddr != null) {
+ mNetworkInfo.setExtraInfo(mHwAddr);
+ }
+ }
reconnect();
break;
}
@@ -239,9 +250,11 @@
* Re-enable connectivity to a network after a {@link #teardown()}.
*/
public boolean reconnect() {
- mTeardownRequested.set(false);
- runDhcp();
- return true;
+ if (mLinkUp) {
+ mTeardownRequested.set(false);
+ runDhcp();
+ }
+ return mLinkUp;
}
/**
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 7286f0d..2f43cb8 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -351,6 +351,18 @@
}
/**
+ * Set the extraInfo field.
+ * @param extraInfo an optional {@code String} providing addditional network state
+ * information passed up from the lower networking layers.
+ * @hide
+ */
+ public void setExtraInfo(String extraInfo) {
+ synchronized (this) {
+ this.mExtraInfo = extraInfo;
+ }
+ }
+
+ /**
* Report the reason an attempt to establish connectivity failed,
* if one is available.
* @return the reason for failure, or null if not available
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index f94d320..06c6c6e 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -25,15 +25,17 @@
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509TrustManager;
import org.apache.harmony.security.provider.cert.X509CertImpl;
import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
+import org.apache.harmony.xnet.provider.jsse.TrustManagerImpl;
/**
* Class responsible for all server certificate validation functionality
*
* {@hide}
*/
-class CertificateChainValidator {
+public class CertificateChainValidator {
/**
* The singleton instance of the certificate chain validator
@@ -122,6 +124,18 @@
}
/**
+ * Handles updates to credential storage.
+ */
+ public static void handleTrustStorageUpdate() {
+
+ X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultTrustManager();
+ if( x509TrustManager instanceof TrustManagerImpl ) {
+ TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
+ trustManager.handleTrustStorageUpdate();
+ }
+ }
+
+ /**
* Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
* Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
* @param chain the cert chain in X509 cert format.
diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java
index 21736aa..73f3d7c 100644
--- a/core/java/android/net/http/HttpResponseCache.java
+++ b/core/java/android/net/http/HttpResponseCache.java
@@ -22,8 +22,10 @@
import java.io.IOException;
import java.net.CacheRequest;
import java.net.CacheResponse;
+import java.net.ExtendedResponseCache;
import java.net.HttpURLConnection;
import java.net.ResponseCache;
+import java.net.ResponseSource;
import java.net.URI;
import java.net.URLConnection;
import java.util.List;
@@ -149,7 +151,8 @@
* } catch (Exception httpResponseCacheNotAvailable) {
* }}</pre>
*/
-public final class HttpResponseCache extends ResponseCache implements Closeable {
+public final class HttpResponseCache extends ResponseCache
+ implements Closeable, ExtendedResponseCache {
private final libcore.net.http.HttpResponseCache delegate;
@@ -260,6 +263,21 @@
return delegate.getRequestCount();
}
+ /** @hide */
+ @Override public void trackResponse(ResponseSource source) {
+ delegate.trackResponse(source);
+ }
+
+ /** @hide */
+ @Override public void trackConditionalCacheHit() {
+ delegate.trackConditionalCacheHit();
+ }
+
+ /** @hide */
+ @Override public void update(CacheResponse conditionalCacheHit, HttpURLConnection connection) {
+ delegate.update(conditionalCacheHit, connection);
+ }
+
/**
* Uninstalls the cache and releases any active resources. Stored contents
* will remain on the filesystem.
diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java
new file mode 100644
index 0000000..3a1da97
--- /dev/null
+++ b/core/java/android/os/CommonClock.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2012 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 android.os;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.util.NoSuchElementException;
+import static libcore.io.OsConstants.*;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.CommonTimeUtils;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Used for accessing the android common time service's common clock and receiving notifications
+ * about common time synchronization status changes.
+ * @hide
+ */
+public class CommonClock {
+ /**
+ * Sentinel value returned by {@link #getTime()} and {@link #getEstimatedError()} when the
+ * common time service is not able to determine the current common time due to a lack of
+ * synchronization.
+ */
+ public static final long TIME_NOT_SYNCED = -1;
+
+ /**
+ * Sentinel value returned by {@link #getTimelineId()} when the common time service is not
+ * currently synced to any timeline.
+ */
+ public static final long INVALID_TIMELINE_ID = 0;
+
+ /**
+ * Sentinel value returned by {@link #getEstimatedError()} when the common time service is not
+ * currently synced to any timeline.
+ */
+ public static final int ERROR_ESTIMATE_UNKNOWN = 0x7FFFFFFF;
+
+ /**
+ * Value used by {@link #getState()} to indicate that there was an internal error while
+ * attempting to determine the state of the common time service.
+ */
+ public static final int STATE_INVALID = -1;
+
+ /**
+ * Value used by {@link #getState()} to indicate that the common time service is in its initial
+ * state and attempting to find the current timeline master, if any. The service will
+ * transition to either {@link #STATE_CLIENT} if it finds an active master, or to
+ * {@link #STATE_MASTER} if no active master is found and this client becomes the master of a
+ * new timeline.
+ */
+ public static final int STATE_INITIAL = 0;
+
+ /**
+ * Value used by {@link #getState()} to indicate that the common time service is in its client
+ * state and is synchronizing its time to a different timeline master on the network.
+ */
+ public static final int STATE_CLIENT = 1;
+
+ /**
+ * Value used by {@link #getState()} to indicate that the common time service is in its master
+ * state and is serving as the timeline master for other common time service clients on the
+ * network.
+ */
+ public static final int STATE_MASTER = 2;
+
+ /**
+ * Value used by {@link #getState()} to indicate that the common time service is in its Ronin
+ * state. Common time service instances in the client state enter the Ronin state after their
+ * timeline master becomes unreachable on the network. Common time services who enter the Ronin
+ * state will begin a new master election for the timeline they were recently clients of. As
+ * clients detect they are not the winner and drop out of the election, they will transition to
+ * the {@link #STATE_WAIT_FOR_ELECTION} state. When there is only one client remaining in the
+ * election, it will assume ownership of the timeline and transition to the
+ * {@link #STATE_MASTER} state. During the election, all clients will allow their timeline to
+ * drift without applying correction.
+ */
+ public static final int STATE_RONIN = 3;
+
+ /**
+ * Value used by {@link #getState()} to indicate that the common time service is waiting for a
+ * master election to conclude and for the new master to announce itself before transitioning to
+ * the {@link #STATE_CLIENT} state. If no new master announces itself within the timeout
+ * threshold, the time service will transition back to the {@link #STATE_RONIN} state in order
+ * to restart the election.
+ */
+ public static final int STATE_WAIT_FOR_ELECTION = 4;
+
+ /**
+ * Name of the underlying native binder service
+ */
+ public static final String SERVICE_NAME = "common_time.clock";
+
+ /**
+ * Class constructor.
+ * @throws android.os.RemoteException
+ */
+ public CommonClock()
+ throws RemoteException {
+ mRemote = ServiceManager.getService(SERVICE_NAME);
+ if (null == mRemote)
+ throw new RemoteException();
+
+ mInterfaceDesc = mRemote.getInterfaceDescriptor();
+ mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
+ mRemote.linkToDeath(mDeathHandler, 0);
+ registerTimelineChangeListener();
+ }
+
+ /**
+ * Handy class factory method.
+ */
+ static public CommonClock create() {
+ CommonClock retVal;
+
+ try {
+ retVal = new CommonClock();
+ }
+ catch (RemoteException e) {
+ retVal = null;
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Release all native resources held by this {@link android.os.CommonClock} instance. Once
+ * resources have been released, the {@link android.os.CommonClock} instance is disconnected from
+ * the native service and will throw a {@link android.os.RemoteException} if any of its
+ * methods are called. Clients should always call release on their client instances before
+ * releasing their last Java reference to the instance. Failure to do this will cause
+ * non-deterministic native resource reclamation and may cause the common time service to remain
+ * active on the network for longer than it should.
+ */
+ public void release() {
+ unregisterTimelineChangeListener();
+ if (null != mRemote) {
+ try {
+ mRemote.unlinkToDeath(mDeathHandler, 0);
+ }
+ catch (NoSuchElementException e) { }
+ mRemote = null;
+ }
+ mUtils = null;
+ }
+
+ /**
+ * Gets the common clock's current time.
+ *
+ * @return a signed 64-bit value representing the current common time in microseconds, or the
+ * special value {@link #TIME_NOT_SYNCED} if the common time service is currently not
+ * synchronized.
+ * @throws android.os.RemoteException
+ */
+ public long getTime()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetLong(METHOD_GET_COMMON_TIME, TIME_NOT_SYNCED);
+ }
+
+ /**
+ * Gets the current estimation of common clock's synchronization accuracy from the common time
+ * service.
+ *
+ * @return a signed 32-bit value representing the common time service's estimation of
+ * synchronization accuracy in microseconds, or the special value
+ * {@link #ERROR_ESTIMATE_UNKNOWN} if the common time service is currently not synchronized.
+ * Negative values indicate that the local server estimates that the nominal common time is
+ * behind the local server's time (in other words, the local clock is running fast) Positive
+ * values indicate that the local server estimates that the nominal common time is ahead of the
+ * local server's time (in other words, the local clock is running slow)
+ * @throws android.os.RemoteException
+ */
+ public int getEstimatedError()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetInt(METHOD_GET_ESTIMATED_ERROR, ERROR_ESTIMATE_UNKNOWN);
+ }
+
+ /**
+ * Gets the ID of the timeline the common time service is currently synchronizing its clock to.
+ *
+ * @return a long representing the unique ID of the timeline the common time service is
+ * currently synchronizing with, or {@link #INVALID_TIMELINE_ID} if the common time service is
+ * currently not synchronized.
+ * @throws android.os.RemoteException
+ */
+ public long getTimelineId()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetLong(METHOD_GET_TIMELINE_ID, INVALID_TIMELINE_ID);
+ }
+
+ /**
+ * Gets the current state of this clock's common time service in the the master election
+ * algorithm.
+ *
+ * @return a integer indicating the current state of the this clock's common time service in the
+ * master election algorithm or {@link #STATE_INVALID} if there is an internal error.
+ * @throws android.os.RemoteException
+ */
+ public int getState()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetInt(METHOD_GET_STATE, STATE_INVALID);
+ }
+
+ /**
+ * Gets the IP address and UDP port of the current timeline master.
+ *
+ * @return an InetSocketAddress containing the IP address and UDP port of the current timeline
+ * master, or null if there is no current master.
+ * @throws android.os.RemoteException
+ */
+ public InetSocketAddress getMasterAddr()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ADDRESS);
+ }
+
+ /**
+ * The OnTimelineChangedListener interface defines a method called by the
+ * {@link android.os.CommonClock} instance to indicate that the time synchronization service has
+ * either synchronized with a new timeline, or is no longer a member of any timeline. The
+ * client application can implement this interface and register the listener with the
+ * {@link #setTimelineChangedListener(OnTimelineChangedListener)} method.
+ */
+ public interface OnTimelineChangedListener {
+ /**
+ * Method called when the time service's timeline has changed.
+ *
+ * @param newTimelineId a long which uniquely identifies the timeline the time
+ * synchronization service is now a member of, or {@link #INVALID_TIMELINE_ID} if the the
+ * service is not synchronized to any timeline.
+ */
+ void onTimelineChanged(long newTimelineId);
+ }
+
+ /**
+ * Registers an OnTimelineChangedListener interface.
+ * <p>Call this method with a null listener to stop receiving server death notifications.
+ */
+ public void setTimelineChangedListener(OnTimelineChangedListener listener) {
+ synchronized (mListenerLock) {
+ mTimelineChangedListener = listener;
+ }
+ }
+
+ /**
+ * The OnServerDiedListener interface defines a method called by the
+ * {@link android.os.CommonClock} instance to indicate that the connection to the native media
+ * server has been broken and that the {@link android.os.CommonClock} instance will need to be
+ * released and re-created. The client application can implement this interface and register
+ * the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
+ */
+ public interface OnServerDiedListener {
+ /**
+ * Method called when the native media server has died. <p>If the native common time
+ * service encounters a fatal error and needs to restart, the binder connection from the
+ * {@link android.os.CommonClock} instance to the common time service will be broken. To
+ * restore functionality, clients should {@link #release()} their old visualizer and create
+ * a new instance.
+ */
+ void onServerDied();
+ }
+
+ /**
+ * Registers an OnServerDiedListener interface.
+ * <p>Call this method with a null listener to stop receiving server death notifications.
+ */
+ public void setServerDiedListener(OnServerDiedListener listener) {
+ synchronized (mListenerLock) {
+ mServerDiedListener = listener;
+ }
+ }
+
+ protected void finalize() throws Throwable { release(); }
+
+ private void throwOnDeadServer() throws RemoteException {
+ if ((null == mRemote) || (null == mUtils))
+ throw new RemoteException();
+ }
+
+ private final Object mListenerLock = new Object();
+ private OnTimelineChangedListener mTimelineChangedListener = null;
+ private OnServerDiedListener mServerDiedListener = null;
+
+ private IBinder mRemote = null;
+ private String mInterfaceDesc = "";
+ private CommonTimeUtils mUtils;
+
+ private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
+ public void binderDied() {
+ synchronized (mListenerLock) {
+ if (null != mServerDiedListener)
+ mServerDiedListener.onServerDied();
+ }
+ }
+ };
+
+ private class TimelineChangedListener extends Binder {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case METHOD_CBK_ON_TIMELINE_CHANGED:
+ data.enforceInterface(DESCRIPTOR);
+ long timelineId = data.readLong();
+ synchronized (mListenerLock) {
+ if (null != mTimelineChangedListener)
+ mTimelineChangedListener.onTimelineChanged(timelineId);
+ }
+ return true;
+ }
+
+ return super.onTransact(code, data, reply, flags);
+ }
+
+ private static final String DESCRIPTOR = "android.os.ICommonClockListener";
+ };
+
+ private TimelineChangedListener mCallbackTgt = null;
+
+ private void registerTimelineChangeListener() throws RemoteException {
+ if (null != mCallbackTgt)
+ return;
+
+ boolean success = false;
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+ mCallbackTgt = new TimelineChangedListener();
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+ data.writeStrongBinder(mCallbackTgt);
+ mRemote.transact(METHOD_REGISTER_LISTENER, data, reply, 0);
+ success = (0 == reply.readInt());
+ }
+ catch (RemoteException e) {
+ success = false;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+
+ // Did we catch a remote exception or fail to register our callback target? If so, our
+ // object must already be dead (or be as good as dead). Clear out all of our state so that
+ // our other methods will properly indicate a dead object.
+ if (!success) {
+ mCallbackTgt = null;
+ mRemote = null;
+ mUtils = null;
+ }
+ }
+
+ private void unregisterTimelineChangeListener() {
+ if (null == mCallbackTgt)
+ return;
+
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+ data.writeStrongBinder(mCallbackTgt);
+ mRemote.transact(METHOD_UNREGISTER_LISTENER, data, reply, 0);
+ }
+ catch (RemoteException e) { }
+ finally {
+ reply.recycle();
+ data.recycle();
+ mCallbackTgt = null;
+ }
+ }
+
+ private static final int METHOD_IS_COMMON_TIME_VALID = IBinder.FIRST_CALL_TRANSACTION;
+ private static final int METHOD_COMMON_TIME_TO_LOCAL_TIME = METHOD_IS_COMMON_TIME_VALID + 1;
+ private static final int METHOD_LOCAL_TIME_TO_COMMON_TIME = METHOD_COMMON_TIME_TO_LOCAL_TIME + 1;
+ private static final int METHOD_GET_COMMON_TIME = METHOD_LOCAL_TIME_TO_COMMON_TIME + 1;
+ private static final int METHOD_GET_COMMON_FREQ = METHOD_GET_COMMON_TIME + 1;
+ private static final int METHOD_GET_LOCAL_TIME = METHOD_GET_COMMON_FREQ + 1;
+ private static final int METHOD_GET_LOCAL_FREQ = METHOD_GET_LOCAL_TIME + 1;
+ private static final int METHOD_GET_ESTIMATED_ERROR = METHOD_GET_LOCAL_FREQ + 1;
+ private static final int METHOD_GET_TIMELINE_ID = METHOD_GET_ESTIMATED_ERROR + 1;
+ private static final int METHOD_GET_STATE = METHOD_GET_TIMELINE_ID + 1;
+ private static final int METHOD_GET_MASTER_ADDRESS = METHOD_GET_STATE + 1;
+ private static final int METHOD_REGISTER_LISTENER = METHOD_GET_MASTER_ADDRESS + 1;
+ private static final int METHOD_UNREGISTER_LISTENER = METHOD_REGISTER_LISTENER + 1;
+
+ private static final int METHOD_CBK_ON_TIMELINE_CHANGED = IBinder.FIRST_CALL_TRANSACTION;
+}
diff --git a/core/java/android/os/CommonTimeConfig.java b/core/java/android/os/CommonTimeConfig.java
new file mode 100644
index 0000000..3355ee3
--- /dev/null
+++ b/core/java/android/os/CommonTimeConfig.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2012 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 android.os;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.NoSuchElementException;
+
+import android.os.CommonTimeUtils;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Used for configuring and controlling the status of the android common time service.
+ * @hide
+ */
+public class CommonTimeConfig {
+ /**
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -4;
+ /**
+ * Operation failed due to dead remote object.
+ */
+ public static final int ERROR_DEAD_OBJECT = -7;
+
+ /**
+ * Sentinel value returned by {@link #getMasterElectionGroupId()} when an error occurs trying to
+ * fetch the master election group.
+ */
+ public static final long INVALID_GROUP_ID = -1;
+
+ /**
+ * Name of the underlying native binder service
+ */
+ public static final String SERVICE_NAME = "common_time.config";
+
+ /**
+ * Class constructor.
+ * @throws android.os.RemoteException
+ */
+ public CommonTimeConfig()
+ throws RemoteException {
+ mRemote = ServiceManager.getService(SERVICE_NAME);
+ if (null == mRemote)
+ throw new RemoteException();
+
+ mInterfaceDesc = mRemote.getInterfaceDescriptor();
+ mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
+ mRemote.linkToDeath(mDeathHandler, 0);
+ }
+
+ /**
+ * Handy class factory method.
+ */
+ static public CommonTimeConfig create() {
+ CommonTimeConfig retVal;
+
+ try {
+ retVal = new CommonTimeConfig();
+ }
+ catch (RemoteException e) {
+ retVal = null;
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Release all native resources held by this {@link android.os.CommonTimeConfig} instance. Once
+ * resources have been released, the {@link android.os.CommonTimeConfig} instance is
+ * disconnected from the native service and will throw a {@link android.os.RemoteException} if
+ * any of its methods are called. Clients should always call release on their client instances
+ * before releasing their last Java reference to the instance. Failure to do this will cause
+ * non-deterministic native resource reclamation and may cause the common time service to remain
+ * active on the network for longer than it should.
+ */
+ public void release() {
+ if (null != mRemote) {
+ try {
+ mRemote.unlinkToDeath(mDeathHandler, 0);
+ }
+ catch (NoSuchElementException e) { }
+ mRemote = null;
+ }
+ mUtils = null;
+ }
+
+ /**
+ * Gets the current priority of the common time service used in the master election protocol.
+ *
+ * @return an 8 bit value indicating the priority of this common time service relative to other
+ * common time services operating in the same domain.
+ * @throws android.os.RemoteException
+ */
+ public byte getMasterElectionPriority()
+ throws RemoteException {
+ throwOnDeadServer();
+ return (byte)mUtils.transactGetInt(METHOD_GET_MASTER_ELECTION_PRIORITY, -1);
+ }
+
+ /**
+ * Sets the current priority of the common time service used in the master election protocol.
+ *
+ * @param priority priority of the common time service used in the master election protocol.
+ * Lower numbers are lower priority.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setMasterElectionPriority(byte priority) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+ return mUtils.transactSetInt(METHOD_SET_MASTER_ELECTION_PRIORITY, priority);
+ }
+
+ /**
+ * Gets the IP endpoint used by the time service to participate in the master election protocol.
+ *
+ * @return an InetSocketAddress containing the IP address and UDP port being used by the
+ * system's common time service to participate in the master election protocol.
+ * @throws android.os.RemoteException
+ */
+ public InetSocketAddress getMasterElectionEndpoint()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ELECTION_ENDPOINT);
+ }
+
+ /**
+ * Sets the IP endpoint used by the common time service to participate in the master election
+ * protocol.
+ *
+ * @param ep The IP address and UDP port to be used by the common time service to participate in
+ * the master election protocol. The supplied IP address must be either the broadcast or
+ * multicast address, unicast addresses are considered to be illegal values.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setMasterElectionEndpoint(InetSocketAddress ep) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+ return mUtils.transactSetSockaddr(METHOD_SET_MASTER_ELECTION_ENDPOINT, ep);
+ }
+
+ /**
+ * Gets the current group ID used by the common time service in the master election protocol.
+ *
+ * @return The 64-bit group ID of the common time service.
+ * @throws android.os.RemoteException
+ */
+ public long getMasterElectionGroupId()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetLong(METHOD_GET_MASTER_ELECTION_GROUP_ID, INVALID_GROUP_ID);
+ }
+
+ /**
+ * Sets the current group ID used by the common time service in the master election protocol.
+ *
+ * @param id The 64-bit group ID of the common time service.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setMasterElectionGroupId(long id) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+ return mUtils.transactSetLong(METHOD_SET_MASTER_ELECTION_GROUP_ID, id);
+ }
+
+ /**
+ * Gets the name of the network interface which the common time service attempts to bind to.
+ *
+ * @return a string with the network interface name which the common time service is bound to,
+ * or null if the service is currently unbound. Examples of interface names are things like
+ * "eth0", or "wlan0".
+ * @throws android.os.RemoteException
+ */
+ public String getInterfaceBinding()
+ throws RemoteException {
+ throwOnDeadServer();
+
+ String ifaceName = mUtils.transactGetString(METHOD_GET_INTERFACE_BINDING, null);
+
+ if ((null != ifaceName) && (0 == ifaceName.length()))
+ return null;
+
+ return ifaceName;
+ }
+
+ /**
+ * Sets the name of the network interface which the common time service should attempt to bind
+ * to.
+ *
+ * @param ifaceName The name of the network interface ("eth0", "wlan0", etc...) wich the common
+ * time service should attempt to bind to, or null to force the common time service to unbind
+ * from the network and run in networkless mode.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setNetworkBinding(String ifaceName) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+
+ return mUtils.transactSetString(METHOD_SET_INTERFACE_BINDING,
+ (null == ifaceName) ? "" : ifaceName);
+ }
+
+ /**
+ * Gets the amount of time the common time service will wait between master announcements when
+ * it is the timeline master.
+ *
+ * @return The time (in milliseconds) between master announcements.
+ * @throws android.os.RemoteException
+ */
+ public int getMasterAnnounceInterval()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetInt(METHOD_GET_MASTER_ANNOUNCE_INTERVAL, -1);
+ }
+
+ /**
+ * Sets the amount of time the common time service will wait between master announcements when
+ * it is the timeline master.
+ *
+ * @param interval The time (in milliseconds) between master announcements.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setMasterAnnounceInterval(int interval) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+ return mUtils.transactSetInt(METHOD_SET_MASTER_ANNOUNCE_INTERVAL, interval);
+ }
+
+ /**
+ * Gets the amount of time the common time service will wait between time synchronization
+ * requests when it is the client of another common time service on the network.
+ *
+ * @return The time (in milliseconds) between time sync requests.
+ * @throws android.os.RemoteException
+ */
+ public int getClientSyncInterval()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetInt(METHOD_GET_CLIENT_SYNC_INTERVAL, -1);
+ }
+
+ /**
+ * Sets the amount of time the common time service will wait between time synchronization
+ * requests when it is the client of another common time service on the network.
+ *
+ * @param interval The time (in milliseconds) between time sync requests.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setClientSyncInterval(int interval) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+ return mUtils.transactSetInt(METHOD_SET_CLIENT_SYNC_INTERVAL, interval);
+ }
+
+ /**
+ * Gets the panic threshold for the estimated error level of the common time service. When the
+ * common time service's estimated error rises above this level, the service will panic and
+ * reset, causing a discontinuity in the currently synchronized timeline.
+ *
+ * @return The threshold (in microseconds) past which the common time service will panic.
+ * @throws android.os.RemoteException
+ */
+ public int getPanicThreshold()
+ throws RemoteException {
+ throwOnDeadServer();
+ return mUtils.transactGetInt(METHOD_GET_PANIC_THRESHOLD, -1);
+ }
+
+ /**
+ * Sets the panic threshold for the estimated error level of the common time service. When the
+ * common time service's estimated error rises above this level, the service will panic and
+ * reset, causing a discontinuity in the currently synchronized timeline.
+ *
+ * @param threshold The threshold (in microseconds) past which the common time service will
+ * panic.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setPanicThreshold(int threshold) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+ return mUtils.transactSetInt(METHOD_SET_PANIC_THRESHOLD, threshold);
+ }
+
+ /**
+ * Gets the current state of the common time service's auto disable flag.
+ *
+ * @return The current state of the common time service's auto disable flag.
+ * @throws android.os.RemoteException
+ */
+ public boolean getAutoDisable()
+ throws RemoteException {
+ throwOnDeadServer();
+ return (1 == mUtils.transactGetInt(METHOD_GET_AUTO_DISABLE, 1));
+ }
+
+ /**
+ * Sets the current state of the common time service's auto disable flag. When the time
+ * service's auto disable flag is set, it will automatically cease all network activity when
+ * it has no active local clients, resuming activity the next time the service has interested
+ * local clients. When the auto disabled flag is cleared, the common time service will continue
+ * to participate the time synchronization group even when it has no active local clients.
+ *
+ * @param autoDisable The desired state of the common time service's auto disable flag.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int setAutoDisable(boolean autoDisable) {
+ if (checkDeadServer())
+ return ERROR_DEAD_OBJECT;
+
+ return mUtils.transactSetInt(METHOD_SET_AUTO_DISABLE, autoDisable ? 1 : 0);
+ }
+
+ /**
+ * At startup, the time service enters the initial state and remains there until it is given a
+ * network interface to bind to. Common time will be unavailable to clients of the common time
+ * service until the service joins a network (even an empty network). Devices may use the
+ * {@link #forceNetworklessMasterMode()} method to force a time service in the INITIAL state
+ * with no network configuration to assume MASTER status for a brand new timeline in order to
+ * allow clients of the common time service to operate, even though the device is isolated and
+ * not on any network. When a networkless master does join a network, it will defer to any
+ * masters already on the network, or continue to maintain the timeline it made up during its
+ * networkless state if no other masters are detected. Attempting to force a client into master
+ * mode while it is actively bound to a network will fail with the status code {@link #ERROR}
+ *
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ */
+ public int forceNetworklessMasterMode() {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+ mRemote.transact(METHOD_FORCE_NETWORKLESS_MASTER_MODE, data, reply, 0);
+
+ return reply.readInt();
+ }
+ catch (RemoteException e) {
+ return ERROR_DEAD_OBJECT;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ /**
+ * The OnServerDiedListener interface defines a method called by the
+ * {@link android.os.CommonTimeConfig} instance to indicate that the connection to the native
+ * media server has been broken and that the {@link android.os.CommonTimeConfig} instance will
+ * need to be released and re-created. The client application can implement this interface and
+ * register the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
+ */
+ public interface OnServerDiedListener {
+ /**
+ * Method called when the native common time service has died. <p>If the native common time
+ * service encounters a fatal error and needs to restart, the binder connection from the
+ * {@link android.os.CommonTimeConfig} instance to the common time service will be broken.
+ */
+ void onServerDied();
+ }
+
+ /**
+ * Registers an OnServerDiedListener interface.
+ * <p>Call this method with a null listener to stop receiving server death notifications.
+ */
+ public void setServerDiedListener(OnServerDiedListener listener) {
+ synchronized (mListenerLock) {
+ mServerDiedListener = listener;
+ }
+ }
+
+ protected void finalize() throws Throwable { release(); }
+
+ private boolean checkDeadServer() {
+ return ((null == mRemote) || (null == mUtils));
+ }
+
+ private void throwOnDeadServer() throws RemoteException {
+ if (checkDeadServer())
+ throw new RemoteException();
+ }
+
+ private final Object mListenerLock = new Object();
+ private OnServerDiedListener mServerDiedListener = null;
+
+ private IBinder mRemote = null;
+ private String mInterfaceDesc = "";
+ private CommonTimeUtils mUtils;
+
+ private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
+ public void binderDied() {
+ synchronized (mListenerLock) {
+ if (null != mServerDiedListener)
+ mServerDiedListener.onServerDied();
+ }
+ }
+ };
+
+ private static final int METHOD_GET_MASTER_ELECTION_PRIORITY = IBinder.FIRST_CALL_TRANSACTION;
+ private static final int METHOD_SET_MASTER_ELECTION_PRIORITY = METHOD_GET_MASTER_ELECTION_PRIORITY + 1;
+ private static final int METHOD_GET_MASTER_ELECTION_ENDPOINT = METHOD_SET_MASTER_ELECTION_PRIORITY + 1;
+ private static final int METHOD_SET_MASTER_ELECTION_ENDPOINT = METHOD_GET_MASTER_ELECTION_ENDPOINT + 1;
+ private static final int METHOD_GET_MASTER_ELECTION_GROUP_ID = METHOD_SET_MASTER_ELECTION_ENDPOINT + 1;
+ private static final int METHOD_SET_MASTER_ELECTION_GROUP_ID = METHOD_GET_MASTER_ELECTION_GROUP_ID + 1;
+ private static final int METHOD_GET_INTERFACE_BINDING = METHOD_SET_MASTER_ELECTION_GROUP_ID + 1;
+ private static final int METHOD_SET_INTERFACE_BINDING = METHOD_GET_INTERFACE_BINDING + 1;
+ private static final int METHOD_GET_MASTER_ANNOUNCE_INTERVAL = METHOD_SET_INTERFACE_BINDING + 1;
+ private static final int METHOD_SET_MASTER_ANNOUNCE_INTERVAL = METHOD_GET_MASTER_ANNOUNCE_INTERVAL + 1;
+ private static final int METHOD_GET_CLIENT_SYNC_INTERVAL = METHOD_SET_MASTER_ANNOUNCE_INTERVAL + 1;
+ private static final int METHOD_SET_CLIENT_SYNC_INTERVAL = METHOD_GET_CLIENT_SYNC_INTERVAL + 1;
+ private static final int METHOD_GET_PANIC_THRESHOLD = METHOD_SET_CLIENT_SYNC_INTERVAL + 1;
+ private static final int METHOD_SET_PANIC_THRESHOLD = METHOD_GET_PANIC_THRESHOLD + 1;
+ private static final int METHOD_GET_AUTO_DISABLE = METHOD_SET_PANIC_THRESHOLD + 1;
+ private static final int METHOD_SET_AUTO_DISABLE = METHOD_GET_AUTO_DISABLE + 1;
+ private static final int METHOD_FORCE_NETWORKLESS_MASTER_MODE = METHOD_SET_AUTO_DISABLE + 1;
+}
diff --git a/core/java/android/os/CommonTimeUtils.java b/core/java/android/os/CommonTimeUtils.java
new file mode 100644
index 0000000..9081ee4
--- /dev/null
+++ b/core/java/android/os/CommonTimeUtils.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 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 android.os;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import static libcore.io.OsConstants.*;
+
+class CommonTimeUtils {
+ /**
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -4;
+ /**
+ * Operation failed due to dead remote object.
+ */
+ public static final int ERROR_DEAD_OBJECT = -7;
+
+ public CommonTimeUtils(IBinder remote, String interfaceDesc) {
+ mRemote = remote;
+ mInterfaceDesc = interfaceDesc;
+ }
+
+ public int transactGetInt(int method_code, int error_ret_val)
+ throws RemoteException {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+ int ret_val;
+
+ try {
+ int res;
+ data.writeInterfaceToken(mInterfaceDesc);
+ mRemote.transact(method_code, data, reply, 0);
+
+ res = reply.readInt();
+ ret_val = (0 == res) ? reply.readInt() : error_ret_val;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+
+ return ret_val;
+ }
+
+ public int transactSetInt(int method_code, int val) {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+ data.writeInt(val);
+ mRemote.transact(method_code, data, reply, 0);
+
+ return reply.readInt();
+ }
+ catch (RemoteException e) {
+ return ERROR_DEAD_OBJECT;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ public long transactGetLong(int method_code, long error_ret_val)
+ throws RemoteException {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+ long ret_val;
+
+ try {
+ int res;
+ data.writeInterfaceToken(mInterfaceDesc);
+ mRemote.transact(method_code, data, reply, 0);
+
+ res = reply.readInt();
+ ret_val = (0 == res) ? reply.readLong() : error_ret_val;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+
+ return ret_val;
+ }
+
+ public int transactSetLong(int method_code, long val) {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+ data.writeLong(val);
+ mRemote.transact(method_code, data, reply, 0);
+
+ return reply.readInt();
+ }
+ catch (RemoteException e) {
+ return ERROR_DEAD_OBJECT;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ public String transactGetString(int method_code, String error_ret_val)
+ throws RemoteException {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+ String ret_val;
+
+ try {
+ int res;
+ data.writeInterfaceToken(mInterfaceDesc);
+ mRemote.transact(method_code, data, reply, 0);
+
+ res = reply.readInt();
+ ret_val = (0 == res) ? reply.readString() : error_ret_val;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+
+ return ret_val;
+ }
+
+ public int transactSetString(int method_code, String val) {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+ data.writeString(val);
+ mRemote.transact(method_code, data, reply, 0);
+
+ return reply.readInt();
+ }
+ catch (RemoteException e) {
+ return ERROR_DEAD_OBJECT;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ public InetSocketAddress transactGetSockaddr(int method_code)
+ throws RemoteException {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+ InetSocketAddress ret_val = null;
+
+ try {
+ int res;
+ data.writeInterfaceToken(mInterfaceDesc);
+ mRemote.transact(method_code, data, reply, 0);
+
+ res = reply.readInt();
+ if (0 == res) {
+ int type;
+ int port = 0;
+ String addrStr = null;
+
+ type = reply.readInt();
+
+ if (AF_INET == type) {
+ int addr = reply.readInt();
+ port = reply.readInt();
+ addrStr = String.format("%d.%d.%d.%d", (addr >> 24) & 0xFF,
+ (addr >> 16) & 0xFF,
+ (addr >> 8) & 0xFF,
+ addr & 0xFF);
+ } else if (AF_INET6 == type) {
+ int addr1 = reply.readInt();
+ int addr2 = reply.readInt();
+ int addr3 = reply.readInt();
+ int addr4 = reply.readInt();
+
+ port = reply.readInt();
+
+ int flowinfo = reply.readInt();
+ int scope_id = reply.readInt();
+
+ addrStr = String.format("[%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X]",
+ (addr1 >> 16) & 0xFFFF, addr1 & 0xFFFF,
+ (addr2 >> 16) & 0xFFFF, addr2 & 0xFFFF,
+ (addr3 >> 16) & 0xFFFF, addr3 & 0xFFFF,
+ (addr4 >> 16) & 0xFFFF, addr4 & 0xFFFF);
+ }
+
+ if (null != addrStr) {
+ ret_val = new InetSocketAddress(addrStr, port);
+ }
+ }
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+
+ return ret_val;
+ }
+
+ public int transactSetSockaddr(int method_code, InetSocketAddress addr) {
+ android.os.Parcel data = android.os.Parcel.obtain();
+ android.os.Parcel reply = android.os.Parcel.obtain();
+ int ret_val = ERROR;
+
+ try {
+ data.writeInterfaceToken(mInterfaceDesc);
+
+ if (null == addr) {
+ data.writeInt(0);
+ } else {
+ data.writeInt(1);
+ final InetAddress a = addr.getAddress();
+ final byte[] b = a.getAddress();
+ final int p = addr.getPort();
+
+ if (a instanceof Inet4Address) {
+ int v4addr = (((int)b[0] & 0xFF) << 24) |
+ (((int)b[1] & 0xFF) << 16) |
+ (((int)b[2] & 0xFF) << 8) |
+ ((int)b[3] & 0xFF);
+
+ data.writeInt(AF_INET);
+ data.writeInt(v4addr);
+ data.writeInt(p);
+ } else
+ if (a instanceof Inet6Address) {
+ int i;
+ Inet6Address v6 = (Inet6Address)a;
+ data.writeInt(AF_INET6);
+ for (i = 0; i < 4; ++i) {
+ int aword = (((int)b[(i*4) + 0] & 0xFF) << 24) |
+ (((int)b[(i*4) + 1] & 0xFF) << 16) |
+ (((int)b[(i*4) + 2] & 0xFF) << 8) |
+ ((int)b[(i*4) + 3] & 0xFF);
+ data.writeInt(aword);
+ }
+ data.writeInt(p);
+ data.writeInt(0); // flow info
+ data.writeInt(v6.getScopeId());
+ } else {
+ return ERROR_BAD_VALUE;
+ }
+ }
+
+ mRemote.transact(method_code, data, reply, 0);
+ ret_val = reply.readInt();
+ }
+ catch (RemoteException e) {
+ ret_val = ERROR_DEAD_OBJECT;
+ }
+ finally {
+ reply.recycle();
+ data.recycle();
+ }
+
+ return ret_val;
+ }
+
+ private IBinder mRemote;
+ private String mInterfaceDesc;
+};
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index af2fa9b..610b3550 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -513,7 +513,7 @@
* message queue.
*/
public final void removeMessages(int what) {
- mQueue.removeMessages(this, what, null, true);
+ mQueue.removeMessages(this, what, null);
}
/**
@@ -522,7 +522,7 @@
* all messages will be removed.
*/
public final void removeMessages(int what, Object object) {
- mQueue.removeMessages(this, what, object, true);
+ mQueue.removeMessages(this, what, object);
}
/**
@@ -539,7 +539,7 @@
* the message queue.
*/
public final boolean hasMessages(int what) {
- return mQueue.removeMessages(this, what, null, false);
+ return mQueue.hasMessages(this, what, null);
}
/**
@@ -547,7 +547,7 @@
* whose obj is 'object' in the message queue.
*/
public final boolean hasMessages(int what, Object object) {
- return mQueue.removeMessages(this, what, object, false);
+ return mQueue.hasMessages(this, what, object);
}
// if we can get rid of this method, the handler need not remember its loop
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
index 9a5ff47..7b11c28 100644
--- a/core/java/android/os/IServiceManager.java
+++ b/core/java/android/os/IServiceManager.java
@@ -45,7 +45,8 @@
* Place a new @a service called @a name into the service
* manager.
*/
- public void addService(String name, IBinder service) throws RemoteException;
+ public void addService(String name, IBinder service, boolean allowIsolated)
+ throws RemoteException;
/**
* Return a list of all currently running services.
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 5607f7f..a06aadb6 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -55,13 +55,13 @@
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
+ private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
- private Printer mLogging = null;
- private static Looper mMainLooper = null; // guarded by Looper.class
+ private Printer mLogging;
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
@@ -70,10 +70,14 @@
* {@link #quit()}.
*/
public static void prepare() {
+ prepare(true);
+ }
+
+ private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
- sThreadLocal.set(new Looper());
+ sThreadLocal.set(new Looper(quitAllowed));
}
/**
@@ -83,19 +87,21 @@
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
- prepare();
- setMainLooper(myLooper());
- myLooper().mQueue.mQuitAllowed = false;
- }
-
- private synchronized static void setMainLooper(Looper looper) {
- mMainLooper = looper;
+ prepare(false);
+ synchronized (Looper.class) {
+ if (sMainLooper != null) {
+ throw new IllegalStateException("The main Looper has already been prepared.");
+ }
+ sMainLooper = myLooper();
+ }
}
/** Returns the application's main looper, which lives in the main thread of the application.
*/
- public synchronized static Looper getMainLooper() {
- return mMainLooper;
+ public static Looper getMainLooper() {
+ synchronized (Looper.class) {
+ return sMainLooper;
+ }
}
/**
@@ -103,63 +109,61 @@
* {@link #quit()} to end the loop.
*/
public static void loop() {
- Looper me = myLooper();
+ final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
- MessageQueue queue = me.mQueue;
-
+ final MessageQueue queue = me.mQueue;
+
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
-
- while (true) {
+
+ for (;;) {
Message msg = queue.next(); // might block
- if (msg != null) {
- if (msg.target == null) {
- // No target is a magic identifier for the quit message.
- return;
- }
-
- long wallStart = 0;
- long threadStart = 0;
-
- // This must be in a local variable, in case a UI event sets the logger
- Printer logging = me.mLogging;
- if (logging != null) {
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- wallStart = SystemClock.currentTimeMicro();
- threadStart = SystemClock.currentThreadTimeMicro();
- }
-
- msg.target.dispatchMessage(msg);
-
- if (logging != null) {
- long wallTime = SystemClock.currentTimeMicro() - wallStart;
- long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
-
- logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
- if (logging instanceof Profiler) {
- ((Profiler) logging).profile(msg, wallStart, wallTime,
- threadStart, threadTime);
- }
- }
-
- // Make sure that during the course of dispatching the
- // identity of the thread wasn't corrupted.
- final long newIdent = Binder.clearCallingIdentity();
- if (ident != newIdent) {
- Log.wtf(TAG, "Thread identity changed from 0x"
- + Long.toHexString(ident) + " to 0x"
- + Long.toHexString(newIdent) + " while dispatching to "
- + msg.target.getClass().getName() + " "
- + msg.callback + " what=" + msg.what);
- }
-
- msg.recycle();
+ if (msg == null) {
+ // No message indicates that the message queue is quitting.
+ return;
}
+
+ long wallStart = 0;
+ long threadStart = 0;
+
+ // This must be in a local variable, in case a UI event sets the logger
+ Printer logging = me.mLogging;
+ if (logging != null) {
+ logging.println(">>>>> Dispatching to " + msg.target + " " +
+ msg.callback + ": " + msg.what);
+ wallStart = SystemClock.currentTimeMicro();
+ threadStart = SystemClock.currentThreadTimeMicro();
+ }
+
+ msg.target.dispatchMessage(msg);
+
+ if (logging != null) {
+ long wallTime = SystemClock.currentTimeMicro() - wallStart;
+ long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
+
+ logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
+ if (logging instanceof Profiler) {
+ ((Profiler) logging).profile(msg, wallStart, wallTime,
+ threadStart, threadTime);
+ }
+ }
+
+ // Make sure that during the course of dispatching the
+ // identity of the thread wasn't corrupted.
+ final long newIdent = Binder.clearCallingIdentity();
+ if (ident != newIdent) {
+ Log.wtf(TAG, "Thread identity changed from 0x"
+ + Long.toHexString(ident) + " to 0x"
+ + Long.toHexString(newIdent) + " while dispatching to "
+ + msg.target.getClass().getName() + " "
+ + msg.callback + " what=" + msg.what);
+ }
+
+ msg.recycle();
}
}
@@ -193,18 +197,61 @@
return myLooper().mQueue;
}
- private Looper() {
- mQueue = new MessageQueue();
+ private Looper(boolean quitAllowed) {
+ mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
+ /**
+ * Quits the looper.
+ *
+ * Causes the {@link #loop} method to terminate as soon as possible.
+ */
public void quit() {
- Message msg = Message.obtain();
- // NOTE: By enqueueing directly into the message queue, the
- // message is left with a null target. This is how we know it is
- // a quit message.
- mQueue.enqueueMessage(msg, 0);
+ mQueue.quit();
+ }
+
+ /**
+ * Posts a synchronization barrier to the Looper's message queue.
+ *
+ * Message processing occurs as usual until the message queue encounters the
+ * synchronization barrier that has been posted. When the barrier is encountered,
+ * later synchronous messages in the queue are stalled (prevented from being executed)
+ * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
+ * the token that identifies the synchronization barrier.
+ *
+ * This method is used to immediately postpone execution of all subsequently posted
+ * synchronous messages until a condition is met that releases the barrier.
+ * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
+ * and continue to be processed as usual.
+ *
+ * This call must be always matched by a call to {@link #removeSyncBarrier} with
+ * the same token to ensure that the message queue resumes normal operation.
+ * Otherwise the application will probably hang!
+ *
+ * @return A token that uniquely identifies the barrier. This token must be
+ * passed to {@link #removeSyncBarrier} to release the barrier.
+ *
+ * @hide
+ */
+ public final int postSyncBarrier() {
+ return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
+ }
+
+
+ /**
+ * Removes a synchronization barrier.
+ *
+ * @param token The synchronization barrier token that was returned by
+ * {@link #postSyncBarrier}.
+ *
+ * @throws IllegalStateException if the barrier was not found.
+ *
+ * @hide
+ */
+ public final void removeSyncBarrier(int token) {
+ mQueue.removeSyncBarrier(token);
}
/**
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 844ed6a..b816b11 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -75,13 +75,13 @@
public Messenger replyTo;
/** If set message is in use */
- /*package*/ static final int FLAG_IN_USE = 1;
+ /*package*/ static final int FLAG_IN_USE = 1 << 0;
- /** Flags reserved for future use (All are reserved for now) */
- /*package*/ static final int FLAGS_RESERVED = ~FLAG_IN_USE;
+ /** If set message is asynchronous */
+ /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
/** Flags to clear in the copyFrom method */
- /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAGS_RESERVED | FLAG_IN_USE;
+ /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
/*package*/ int flags;
@@ -363,6 +363,48 @@
target.sendMessage(this);
}
+ /**
+ * Returns true if the message is asynchronous.
+ *
+ * Asynchronous messages represent interrupts or events that do not require global ordering
+ * with represent to synchronous messages. Asynchronous messages are not subject to
+ * the synchronization barriers introduced by {@link MessageQueue#acquireSyncBarrier()}.
+ *
+ * @return True if the message is asynchronous.
+ *
+ * @see #setAsynchronous(boolean)
+ * @see MessageQueue#acquireSyncBarrier()
+ * @see MessageQueue#releaseSyncBarrier()
+ *
+ * @hide
+ */
+ public boolean isAsynchronous() {
+ return (flags & FLAG_ASYNCHRONOUS) != 0;
+ }
+
+ /**
+ * Sets whether the message is asynchronous.
+ *
+ * Asynchronous messages represent interrupts or events that do not require global ordering
+ * with represent to synchronous messages. Asynchronous messages are not subject to
+ * the synchronization barriers introduced by {@link MessageQueue#acquireSyncBarrier()}.
+ *
+ * @param async True if the message is asynchronous.
+ *
+ * @see #isAsynchronous()
+ * @see MessageQueue#acquireSyncBarrier()
+ * @see MessageQueue#releaseSyncBarrier()
+ *
+ * @hide
+ */
+ public void setAsynchronous(boolean async) {
+ if (async) {
+ flags |= FLAG_ASYNCHRONOUS;
+ } else {
+ flags &= ~FLAG_ASYNCHRONOUS;
+ }
+ }
+
/*package*/ void clearForRecycle() {
flags = 0;
what = 0;
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index a658fc4..64027ef 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -30,18 +30,24 @@
* {@link Looper#myQueue() Looper.myQueue()}.
*/
public class MessageQueue {
+ // True if the message queue can be quit.
+ private final boolean mQuitAllowed;
+
+ @SuppressWarnings("unused")
+ private int mPtr; // used by native code
+
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuiting;
- boolean mQuitAllowed = true;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;
- @SuppressWarnings("unused")
- private int mPtr; // used by native code
-
+ // The next barrier token.
+ // Barriers are indicated by messages with a null target whose arg1 field carries the token.
+ private int mNextBarrierToken;
+
private native void nativeInit();
private native void nativeDestroy();
private native void nativePollOnce(int ptr, int timeoutMillis);
@@ -93,11 +99,12 @@
mIdleHandlers.remove(handler);
}
}
-
- MessageQueue() {
+
+ MessageQueue(boolean quitAllowed) {
+ mQuitAllowed = quitAllowed;
nativeInit();
}
-
+
@Override
protected void finalize() throws Throwable {
try {
@@ -118,30 +125,51 @@
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
+ if (mQuiting) {
+ return null;
+ }
+
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
- final Message msg = mMessages;
+ Message prevMsg = null;
+ Message msg = mMessages;
+ if (msg != null && msg.target == null) {
+ // Stalled by a barrier. Find the next asynchronous message in the queue.
+ do {
+ prevMsg = msg;
+ msg = msg.next;
+ } while (msg != null && !msg.isAsynchronous());
+ }
if (msg != null) {
- final long when = msg.when;
- if (now >= when) {
+ if (now < msg.when) {
+ // Next message is not ready. Set a timeout to wake up when it is ready.
+ nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
+ } else {
+ // Got a message.
mBlocked = false;
- mMessages = msg.next;
+ if (prevMsg != null) {
+ prevMsg.next = msg.next;
+ } else {
+ mMessages = msg.next;
+ }
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
- } else {
- nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
}
} else {
+ // No more messages.
nextPollTimeoutMillis = -1;
}
- // If first time, then get the number of idlers to run.
- if (pendingIdleHandlerCount < 0) {
+ // If first time idle, then get the number of idlers to run.
+ // Idle handles only run if the queue is empty or if the first message
+ // in the queue (possibly a barrier) is due to be handled in the future.
+ if (pendingIdleHandlerCount < 0
+ && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
- if (pendingIdleHandlerCount == 0) {
+ if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
@@ -182,41 +210,118 @@
}
}
- final boolean enqueueMessage(Message msg, long when) {
- if (msg.isInUse()) {
- throw new AndroidRuntimeException(msg
- + " This message is already in use.");
+ final void quit() {
+ if (!mQuitAllowed) {
+ throw new RuntimeException("Main thread not allowed to quit.");
}
- if (msg.target == null && !mQuitAllowed) {
- throw new RuntimeException("Main thread not allowed to quit");
- }
- final boolean needWake;
+
synchronized (this) {
if (mQuiting) {
- RuntimeException e = new RuntimeException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- } else if (msg.target == null) {
- mQuiting = true;
+ return;
}
+ mQuiting = true;
+ }
+ nativeWake(mPtr);
+ }
- msg.when = when;
- //Log.d("MessageQueue", "Enqueing: " + msg);
+ final int enqueueSyncBarrier(long when) {
+ // Enqueue a new sync barrier token.
+ // We don't need to wake the queue because the purpose of a barrier is to stall it.
+ synchronized (this) {
+ final int token = mNextBarrierToken++;
+ final Message msg = Message.obtain();
+ msg.arg1 = token;
+
+ Message prev = null;
Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked; // new head, might need to wake up
- } else {
- Message prev = null;
+ if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
- msg.next = prev.next;
+ }
+ if (prev != null) { // invariant: p == prev.next
+ msg.next = p;
prev.next = msg;
- needWake = false; // still waiting on head, no need to wake up
+ } else {
+ msg.next = p;
+ mMessages = msg;
+ }
+ return token;
+ }
+ }
+
+ final void removeSyncBarrier(int token) {
+ // Remove a sync barrier token from the queue.
+ // If the queue is no longer stalled by a barrier then wake it.
+ final boolean needWake;
+ synchronized (this) {
+ Message prev = null;
+ Message p = mMessages;
+ while (p != null && (p.target != null || p.arg1 != token)) {
+ prev = p;
+ p = p.next;
+ }
+ if (p == null) {
+ throw new IllegalStateException("The specified message queue synchronization "
+ + " barrier token has not been posted or has already been removed.");
+ }
+ if (prev != null) {
+ prev.next = p.next;
+ needWake = false;
+ } else {
+ mMessages = p.next;
+ needWake = mMessages == null || mMessages.target != null;
+ }
+ p.recycle();
+ }
+ if (needWake) {
+ nativeWake(mPtr);
+ }
+ }
+
+ final boolean enqueueMessage(Message msg, long when) {
+ if (msg.isInUse()) {
+ throw new AndroidRuntimeException(msg + " This message is already in use.");
+ }
+ if (msg.target == null) {
+ throw new AndroidRuntimeException("Message must have a target.");
+ }
+
+ boolean needWake;
+ synchronized (this) {
+ if (mQuiting) {
+ RuntimeException e = new RuntimeException(
+ msg.target + " sending message to a Handler on a dead thread");
+ Log.w("MessageQueue", e.getMessage(), e);
+ return false;
+ }
+
+ msg.when = when;
+ Message p = mMessages;
+ if (p == null || when == 0 || when < p.when) {
+ // New head, wake up the event queue if blocked.
+ msg.next = p;
+ mMessages = msg;
+ needWake = mBlocked;
+ } else {
+ // Inserted within the middle of the queue. Usually we don't have to wake
+ // up the event queue unless there is a barrier at the head of the queue
+ // and the message is the earliest asynchronous message in the queue.
+ needWake = mBlocked && p.target == null && msg.isAsynchronous();
+ Message prev;
+ for (;;) {
+ prev = p;
+ p = p.next;
+ if (p == null || when < p.when) {
+ break;
+ }
+ if (needWake && p.isAsynchronous()) {
+ needWake = false;
+ }
+ }
+ msg.next = p; // invariant: p == prev.next
+ prev.next = msg;
}
}
if (needWake) {
@@ -225,17 +330,34 @@
return true;
}
- final boolean removeMessages(Handler h, int what, Object object,
- boolean doRemove) {
+ final boolean hasMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return false;
+ }
+
synchronized (this) {
Message p = mMessages;
- boolean found = false;
+ while (p != null) {
+ if (p.target == h && p.what == what && (object == null || p.obj == object)) {
+ return true;
+ }
+ p = p.next;
+ }
+ return false;
+ }
+ }
+
+ final void removeMessages(Handler h, int what, Object object) {
+ if (h == null) {
+ return;
+ }
+
+ synchronized (this) {
+ Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
- if (!doRemove) return true;
- found = true;
Message n = p.next;
mMessages = n;
p.recycle();
@@ -248,8 +370,6 @@
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
- if (!doRemove) return true;
- found = true;
Message nn = n.next;
n.recycle();
p.next = nn;
@@ -258,13 +378,11 @@
}
p = n;
}
-
- return found;
}
}
final void removeMessages(Handler h, Runnable r, Object object) {
- if (r == null) {
+ if (h == null || r == null) {
return;
}
@@ -298,6 +416,10 @@
}
final void removeCallbacksAndMessages(Handler h, Object object) {
+ if (h == null) {
+ return;
+ }
+
synchronized (this) {
Message p = mMessages;
@@ -325,16 +447,4 @@
}
}
}
-
- /*
- private void dumpQueue_l()
- {
- Message p = mMessages;
- System.out.println(this + " queue is:");
- while (p != null) {
- System.out.println(" " + p);
- p = p.next;
- }
- }
- */
}
diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java
index 5a79215..58df940 100644
--- a/core/java/android/os/Power.java
+++ b/core/java/android/os/Power.java
@@ -104,4 +104,6 @@
}
private static native void rebootNative(String reason) throws IOException ;
+
+ public static native int powerInitNative();
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0746af8..6139296 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -119,7 +119,7 @@
* Last of application-specific UIDs starting at
* {@link #FIRST_APPLICATION_UID}.
*/
- public static final int LAST_APPLICATION_UID = 89999;
+ public static final int LAST_APPLICATION_UID = 19999;
/**
* First uid used for fully isolated sandboxed processes (with no permissions of their own)
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 1af24f4a..13b8b66 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -69,7 +69,24 @@
*/
public static void addService(String name, IBinder service) {
try {
- getIServiceManager().addService(name, service);
+ getIServiceManager().addService(name, service, false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in addService", e);
+ }
+ }
+
+ /**
+ * Place a new @a service called @a name into the service
+ * manager.
+ *
+ * @param name the name of the new service
+ * @param service the service object
+ * @param allowIsolated set to true to allow isolated sandboxed processes
+ * to access this service
+ */
+ public static void addService(String name, IBinder service, boolean allowIsolated) {
+ try {
+ getIServiceManager().addService(name, service, allowIsolated);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 2aab0e6..43b5128 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -71,7 +71,8 @@
data.enforceInterface(IServiceManager.descriptor);
String name = data.readString();
IBinder service = data.readStrongBinder();
- addService(name, service);
+ boolean allowIsolated = data.readInt() != 0;
+ addService(name, service, allowIsolated);
return true;
}
@@ -136,13 +137,14 @@
return binder;
}
- public void addService(String name, IBinder service)
+ public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
+ data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
index 4124d51..0da67d63 100644
--- a/core/java/android/os/UserId.java
+++ b/core/java/android/os/UserId.java
@@ -56,6 +56,11 @@
return getAppId(uid1) == getAppId(uid2);
}
+ public static final boolean isIsolated(int uid) {
+ uid = getAppId(uid);
+ return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID;
+ }
+
/**
* Returns the user id for a given uid.
* @hide
@@ -68,6 +73,10 @@
}
}
+ public static final int getCallingUserId() {
+ return getUserId(Binder.getCallingUid());
+ }
+
/**
* Returns the uid that is composed from the userId and the appId.
* @hide
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cdb622c..fbf512c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -16,6 +16,7 @@
package android.os.storage;
+import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -534,6 +535,7 @@
* @hide
*/
public String getVolumeState(String mountPoint) {
+ if (mMountService == null) return Environment.MEDIA_REMOVED;
try {
return mMountService.getVolumeState(mountPoint);
} catch (RemoteException e) {
@@ -547,6 +549,7 @@
* @hide
*/
public StorageVolume[] getVolumeList() {
+ if (mMountService == null) return new StorageVolume[0];
try {
Parcelable[] list = mMountService.getVolumeList();
if (list == null) return new StorageVolume[0];
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4e147c2..0aad64a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1499,6 +1499,12 @@
public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
/**
+ * Master volume (float in the range 0.0f to 1.0f).
+ * @hide
+ */
+ public static final String VOLUME_MASTER = "volume_master";
+
+ /**
* Whether the notifications should use the ring volume (value of 1) or a separate
* notification volume (value of 0). In most cases, users will have this enabled so the
* notification and ringer volumes will be the same. However, power users can disable this
@@ -1830,6 +1836,12 @@
public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
/**
+ * Whether the lockscreen should be completely disabled.
+ * @hide
+ */
+ public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
+
+ /**
* URI for the low battery sound file.
* @hide
*/
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index e5c1e5b..ae41eab 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -17,13 +17,10 @@
package android.text;
-import java.util.Locale;
-
import android.util.LocaleUtil;
/**
* Some objects that implement TextDirectionHeuristic.
- * @hide
*/
public class TextDirectionHeuristics {
@@ -74,9 +71,8 @@
* Computes the text direction based on an algorithm. Subclasses implement
* {@link #defaultIsRtl} to handle cases where the algorithm cannot determine the
* direction from the text alone.
- * @hide
*/
- public static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
+ private static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
private final TextDirectionAlgorithm mAlgorithm;
public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
@@ -157,13 +153,11 @@
/**
* Interface for an algorithm to guess the direction of a paragraph of text.
*
- * @hide
*/
- public static interface TextDirectionAlgorithm {
+ private static interface TextDirectionAlgorithm {
/**
* Returns whether the range of text is RTL according to the algorithm.
*
- * @hide
*/
TriState checkRtl(char[] text, int start, int count);
}
@@ -173,9 +167,8 @@
* the paragraph direction. This is the standard Unicode Bidirectional
* algorithm.
*
- * @hide
*/
- public static class FirstStrong implements TextDirectionAlgorithm {
+ private static class FirstStrong implements TextDirectionAlgorithm {
@Override
public TriState checkRtl(char[] text, int start, int count) {
TriState result = TriState.UNKNOWN;
@@ -196,9 +189,8 @@
* character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
* direction of text.
*
- * @hide
*/
- public static class AnyStrong implements TextDirectionAlgorithm {
+ private static class AnyStrong implements TextDirectionAlgorithm {
private final boolean mLookForRtl;
@Override
@@ -239,7 +231,7 @@
/**
* Algorithm that uses the Locale direction to force the direction of a paragraph.
*/
- public static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl {
+ private static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl {
public TextDirectionHeuristicLocale() {
super(null);
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 95a3cdc..43dfc81 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1325,7 +1325,11 @@
sb.append("&"); //$NON-NLS-1$
break;
case '\'':
- sb.append("'"); //$NON-NLS-1$
+ //http://www.w3.org/TR/xhtml1
+ // The named character reference ' (the apostrophe, U+0027) was introduced in
+ // XML 1.0 but does not appear in HTML. Authors should therefore use ' instead
+ // of ' to work as expected in HTML 4 user agents.
+ sb.append("'"); //$NON-NLS-1$
break;
case '"':
sb.append("""); //$NON-NLS-1$
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index 8594852..318149a 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -22,7 +22,7 @@
/**
* Interface for converting text key events into edit operations on an
- * Editable class. Note that for must cases this interface has been
+ * Editable class. Note that for most cases this interface has been
* superceded by general soft input methods as defined by
* {@link android.view.inputmethod.InputMethod}; it should only be used
* for cases where an application has its own on-screen keypad and also wants
diff --git a/core/java/android/text/method/TransformationMethod.java b/core/java/android/text/method/TransformationMethod.java
index 9f51c2a..b542109 100644
--- a/core/java/android/text/method/TransformationMethod.java
+++ b/core/java/android/text/method/TransformationMethod.java
@@ -18,7 +18,6 @@
import android.graphics.Rect;
import android.view.View;
-import android.widget.TextView;
/**
* TextView uses TransformationMethods to do things like replacing the
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 1ec8be6..630e5f3 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -19,56 +19,50 @@
import com.android.internal.util.ArrayUtils;
/**
- * SparseArrays map longs to Objects. Unlike a normal array of Objects,
+ * SparseArray mapping longs to Objects. Unlike a normal array of Objects,
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Longs to Objects.
- *
- * @hide
*/
-public class LongSparseArray<E> {
+public class LongSparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
+ private long[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+
/**
- * Creates a new SparseArray containing no mappings.
+ * Creates a new LongSparseArray containing no mappings.
*/
public LongSparseArray() {
this(10);
}
/**
- * Creates a new SparseArray containing no mappings that will not
+ * Creates a new LongSparseArray containing no mappings that will not
* require any additional memory allocation to store the specified
* number of mappings.
*/
public LongSparseArray(int initialCapacity) {
- initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+ initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
mKeys = new long[initialCapacity];
mValues = new Object[initialCapacity];
mSize = 0;
}
-
- /**
- * @return A copy of all keys contained in the sparse array.
- */
- public long[] getKeys() {
- int length = mKeys.length;
- long[] result = new long[length];
- System.arraycopy(mKeys, 0, result, 0, length);
- return result;
- }
-
- /**
- * Sets all supplied keys to the given unique value.
- * @param keys Keys to set
- * @param uniqueValue Value to set all supplied keys to
- */
- public void setValues(long[] keys, E uniqueValue) {
- int length = keys.length;
- for (int i = 0; i < length; i++) {
- put(keys[i], uniqueValue);
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public LongSparseArray<E> clone() {
+ LongSparseArray<E> clone = null;
+ try {
+ clone = (LongSparseArray<E>) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
}
+ return clone;
}
/**
@@ -83,6 +77,7 @@
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
+ @SuppressWarnings("unchecked")
public E get(long key, E valueIfKeyNotFound) {
int i = binarySearch(mKeys, 0, mSize, key);
@@ -114,6 +109,16 @@
delete(key);
}
+ /**
+ * Removes the mapping at the specified index.
+ */
+ public void removeAt(int index) {
+ if (mValues[index] != DELETED) {
+ mValues[index] = DELETED;
+ mGarbage = true;
+ }
+ }
+
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
@@ -129,6 +134,7 @@
if (i != o) {
keys[o] = keys[i];
values[o] = val;
+ values[i] = null;
}
o++;
@@ -168,7 +174,7 @@
}
if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(mSize + 1);
+ int n = ArrayUtils.idealLongArraySize(mSize + 1);
long[] nkeys = new long[n];
Object[] nvalues = new Object[n];
@@ -194,7 +200,7 @@
}
/**
- * Returns the number of key-value mappings that this SparseArray
+ * Returns the number of key-value mappings that this LongSparseArray
* currently stores.
*/
public int size() {
@@ -208,7 +214,7 @@
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
- * SparseArray stores.
+ * LongSparseArray stores.
*/
public long keyAt(int index) {
if (mGarbage) {
@@ -221,8 +227,9 @@
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
- * SparseArray stores.
+ * LongSparseArray stores.
*/
+ @SuppressWarnings("unchecked")
public E valueAt(int index) {
if (mGarbage) {
gc();
@@ -234,7 +241,7 @@
/**
* Given an index in the range <code>0...size()-1</code>, sets a new
* value for the <code>index</code>th key-value mapping that this
- * SparseArray stores.
+ * LongSparseArray stores.
*/
public void setValueAt(int index, E value) {
if (mGarbage) {
@@ -278,7 +285,7 @@
}
/**
- * Removes all key-value mappings from this SparseArray.
+ * Removes all key-value mappings from this LongSparseArray.
*/
public void clear() {
int n = mSize;
@@ -308,7 +315,7 @@
int pos = mSize;
if (pos >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(pos + 1);
+ int n = ArrayUtils.idealLongArraySize(pos + 1);
long[] nkeys = new long[n];
Object[] nvalues = new Object[n];
@@ -345,20 +352,4 @@
else
return ~high;
}
-
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
- private long[] mKeys;
- private Object[] mValues;
- private int mSize;
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 3ee275c..42c3913 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -16,8 +16,6 @@
package android.view;
-import com.android.internal.util.ArrayUtils;
-
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -28,12 +26,16 @@
/**
* Coordinates animations and drawing for UI on a particular thread.
*
- * This object is thread-safe. Other threads can add and remove listeners
- * or schedule work to occur at a later time on the UI thread.
+ * This object is thread-safe. Other threads can post callbacks to run at a later time
+ * on the UI thread.
+ *
+ * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver}
+ * can only be accessed from the UI thread so operations that touch the event receiver
+ * are posted to the UI thread if needed.
*
* @hide
*/
-public final class Choreographer extends Handler {
+public final class Choreographer {
private static final String TAG = "Choreographer";
private static final boolean DEBUG = false;
@@ -78,23 +80,28 @@
private static final int MSG_DO_ANIMATION = 0;
private static final int MSG_DO_DRAW = 1;
+ private static final int MSG_DO_SCHEDULE_VSYNC = 2;
private final Object mLock = new Object();
private final Looper mLooper;
+ private final FrameHandler mHandler;
+ private final FrameDisplayEventReceiver mDisplayEventReceiver;
- private OnAnimateListener[] mOnAnimateListeners;
- private OnDrawListener[] mOnDrawListeners;
+ private Callback mCallbackPool;
+
+ private Callback mAnimationCallbacks;
+ private Callback mDrawCallbacks;
private boolean mAnimationScheduled;
private boolean mDrawScheduled;
- private FrameDisplayEventReceiver mFrameDisplayEventReceiver;
private long mLastAnimationTime;
private long mLastDrawTime;
private Choreographer(Looper looper) {
- super(looper);
mLooper = looper;
+ mHandler = new FrameHandler(looper);
+ mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastAnimationTime = Long.MIN_VALUE;
mLastDrawTime = Long.MIN_VALUE;
}
@@ -143,14 +150,77 @@
}
/**
- * Schedules animation (and drawing) to occur on the next frame synchronization boundary.
+ * Posts a callback to run on the next animation cycle and schedules an animation cycle.
+ * The callback only runs once and then is automatically removed.
+ *
+ * @param runnable The callback to run during the next animation cycle.
+ *
+ * @see #removeAnimationCallback
*/
- public void scheduleAnimation() {
+ public void postAnimationCallback(Runnable runnable) {
+ if (runnable == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
synchronized (mLock) {
+ mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, runnable);
scheduleAnimationLocked();
}
}
+ /**
+ * Removes an animation callback.
+ * Does nothing if the specified animation callback has not been posted or has already
+ * been removed.
+ *
+ * @param runnable The animation callback to remove.
+ *
+ * @see #postAnimationCallback
+ */
+ public void removeAnimationCallback(Runnable runnable) {
+ if (runnable == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
+ synchronized (mLock) {
+ mAnimationCallbacks = removeCallbackLocked(mAnimationCallbacks, runnable);
+ }
+ }
+
+ /**
+ * Posts a callback to run on the next draw cycle and schedules a draw cycle.
+ * The callback only runs once and then is automatically removed.
+ *
+ * @param runnable The callback to run during the next draw cycle.
+ *
+ * @see #removeDrawCallback
+ */
+ public void postDrawCallback(Runnable runnable) {
+ if (runnable == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
+ synchronized (mLock) {
+ mDrawCallbacks = addCallbackLocked(mDrawCallbacks, runnable);
+ scheduleDrawLocked();
+ }
+ }
+
+ /**
+ * Removes a draw callback.
+ * Does nothing if the specified draw callback has not been posted or has already
+ * been removed.
+ *
+ * @param runnable The draw callback to remove.
+ *
+ * @see #postDrawCallback
+ */
+ public void removeDrawCallback(Runnable runnable) {
+ if (runnable == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
+ synchronized (mLock) {
+ mDrawCallbacks = removeCallbackLocked(mDrawCallbacks, runnable);
+ }
+ }
+
private void scheduleAnimationLocked() {
if (!mAnimationScheduled) {
mAnimationScheduled = true;
@@ -158,76 +228,47 @@
if (DEBUG) {
Log.d(TAG, "Scheduling vsync for animation.");
}
- if (mFrameDisplayEventReceiver == null) {
- mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
+
+ // If running on the Looper thread, then schedule the vsync immediately,
+ // otherwise post a message to schedule the vsync from the UI thread
+ // as soon as possible.
+ if (isRunningOnLooperThreadLocked()) {
+ doScheduleVsyncLocked();
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtFrontOfQueue(msg);
}
- mFrameDisplayEventReceiver.scheduleVsync();
} else {
final long now = SystemClock.uptimeMillis();
final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now);
if (DEBUG) {
Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms.");
}
- sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime);
+ Message msg = mHandler.obtainMessage(MSG_DO_ANIMATION);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtTime(msg, nextAnimationTime);
}
}
}
- /**
- * Returns true if {@link #scheduleAnimation()} has been called but
- * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
- * not yet been called.
- */
- public boolean isAnimationScheduled() {
- synchronized (mLock) {
- return mAnimationScheduled;
- }
- }
-
- /**
- * Schedules drawing to occur on the next frame synchronization boundary.
- * Must be called on the UI thread.
- */
- public void scheduleDraw() {
- synchronized (mLock) {
- if (!mDrawScheduled) {
- mDrawScheduled = true;
- if (USE_ANIMATION_TIMER_FOR_DRAW) {
- scheduleAnimationLocked();
- } else {
- if (DEBUG) {
- Log.d(TAG, "Scheduling draw immediately.");
- }
- sendEmptyMessage(MSG_DO_DRAW);
+ private void scheduleDrawLocked() {
+ if (!mDrawScheduled) {
+ mDrawScheduled = true;
+ if (USE_ANIMATION_TIMER_FOR_DRAW) {
+ scheduleAnimationLocked();
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Scheduling draw immediately.");
}
+ Message msg = mHandler.obtainMessage(MSG_DO_DRAW);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
}
}
}
- /**
- * Returns true if {@link #scheduleDraw()} has been called but
- * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
- * not yet been called.
- */
- public boolean isDrawScheduled() {
- synchronized (mLock) {
- return mDrawScheduled;
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_DO_ANIMATION:
- doAnimation();
- break;
- case MSG_DO_DRAW:
- doDraw();
- break;
- }
- }
-
- private void doAnimation() {
+ void doAnimation() {
doAnimationInner();
if (USE_ANIMATION_TIMER_FOR_DRAW) {
@@ -235,9 +276,9 @@
}
}
- private void doAnimationInner() {
+ void doAnimationInner() {
final long start;
- final OnAnimateListener[] listeners;
+ final Callback callbacks;
synchronized (mLock) {
if (!mAnimationScheduled) {
return; // no work to do
@@ -251,12 +292,14 @@
}
mLastAnimationTime = start;
- listeners = mOnAnimateListeners;
+ callbacks = mAnimationCallbacks;
+ mAnimationCallbacks = null;
}
- if (listeners != null) {
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onAnimate();
+ if (callbacks != null) {
+ runCallbacks(callbacks);
+ synchronized (mLock) {
+ recycleCallbacksLocked(callbacks);
}
}
@@ -265,9 +308,9 @@
}
}
- private void doDraw() {
+ void doDraw() {
final long start;
- final OnDrawListener[] listeners;
+ final Callback callbacks;
synchronized (mLock) {
if (!mDrawScheduled) {
return; // no work to do
@@ -281,12 +324,14 @@
}
mLastDrawTime = start;
- listeners = mOnDrawListeners;
+ callbacks = mDrawCallbacks;
+ mDrawCallbacks = null;
}
- if (listeners != null) {
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onDraw();
+ if (callbacks != null) {
+ runCallbacks(callbacks);
+ synchronized (mLock) {
+ recycleCallbacksLocked(callbacks);
}
}
@@ -295,134 +340,106 @@
}
}
- /**
- * Adds an animation listener.
- *
- * @param listener The listener to add.
- */
- public void addOnAnimateListener(OnAnimateListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- if (DEBUG) {
- Log.d(TAG, "Adding onAnimate listener: " + listener);
- }
-
+ void doScheduleVsync() {
synchronized (mLock) {
- mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class,
- mOnAnimateListeners, listener);
+ doScheduleVsyncLocked();
}
}
- /**
- * Removes an animation listener.
- *
- * @param listener The listener to remove.
- */
- public void removeOnAnimateListener(OnAnimateListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- if (DEBUG) {
- Log.d(TAG, "Removing onAnimate listener: " + listener);
- }
-
- synchronized (mLock) {
- mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class,
- mOnAnimateListeners, listener);
- stopTimingLoopIfNoListenersLocked();
+ private void doScheduleVsyncLocked() {
+ if (mAnimationScheduled) {
+ mDisplayEventReceiver.scheduleVsync();
}
}
- /**
- * Adds a draw listener.
- *
- * @param listener The listener to add.
- */
- public void addOnDrawListener(OnDrawListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- if (DEBUG) {
- Log.d(TAG, "Adding onDraw listener: " + listener);
- }
-
- synchronized (mLock) {
- mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class,
- mOnDrawListeners, listener);
- }
+ private boolean isRunningOnLooperThreadLocked() {
+ return Looper.myLooper() == mLooper;
}
- /**
- * Removes a draw listener.
- * Must be called on the UI thread.
- *
- * @param listener The listener to remove.
- */
- public void removeOnDrawListener(OnDrawListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
+ private Callback addCallbackLocked(Callback head, Runnable runnable) {
+ Callback callback = obtainCallbackLocked(runnable);
+ if (head == null) {
+ return callback;
}
-
- if (DEBUG) {
- Log.d(TAG, "Removing onDraw listener: " + listener);
+ Callback tail = head;
+ while (tail.next != null) {
+ tail = tail.next;
}
-
- synchronized (mLock) {
- mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class,
- mOnDrawListeners, listener);
- stopTimingLoopIfNoListenersLocked();
- }
+ tail.next = callback;
+ return head;
}
- private void stopTimingLoopIfNoListenersLocked() {
- if (mOnDrawListeners == null && mOnAnimateListeners == null) {
- if (DEBUG) {
- Log.d(TAG, "Stopping timing loop.");
- }
-
- if (mAnimationScheduled) {
- mAnimationScheduled = false;
- if (!USE_VSYNC) {
- removeMessages(MSG_DO_ANIMATION);
+ private Callback removeCallbackLocked(Callback head, Runnable runnable) {
+ Callback predecessor = null;
+ for (Callback callback = head; callback != null;) {
+ final Callback next = callback.next;
+ if (callback.runnable == runnable) {
+ if (predecessor != null) {
+ predecessor.next = next;
+ } else {
+ head = next;
}
+ recycleCallbackLocked(callback);
+ } else {
+ predecessor = callback;
}
+ callback = next;
+ }
+ return head;
+ }
- if (mDrawScheduled) {
- mDrawScheduled = false;
- if (!USE_ANIMATION_TIMER_FOR_DRAW) {
- removeMessages(MSG_DO_DRAW);
- }
- }
-
- if (mFrameDisplayEventReceiver != null) {
- mFrameDisplayEventReceiver.dispose();
- mFrameDisplayEventReceiver = null;
- }
+ private void runCallbacks(Callback head) {
+ while (head != null) {
+ head.runnable.run();
+ head = head.next;
}
}
- /**
- * Listens for animation frame timing events.
- */
- public static interface OnAnimateListener {
- /**
- * Called to animate properties before drawing the frame.
- */
- public void onAnimate();
+ private void recycleCallbacksLocked(Callback head) {
+ while (head != null) {
+ final Callback next = head.next;
+ recycleCallbackLocked(head);
+ head = next;
+ }
}
- /**
- * Listens for draw frame timing events.
- */
- public static interface OnDrawListener {
- /**
- * Called to draw the frame.
- */
- public void onDraw();
+ private Callback obtainCallbackLocked(Runnable runnable) {
+ Callback callback = mCallbackPool;
+ if (callback == null) {
+ callback = new Callback();
+ } else {
+ mCallbackPool = callback.next;
+ callback.next = null;
+ }
+ callback.runnable = runnable;
+ return callback;
+ }
+
+ private void recycleCallbackLocked(Callback callback) {
+ callback.runnable = null;
+ callback.next = mCallbackPool;
+ mCallbackPool = callback;
+ }
+
+ private final class FrameHandler extends Handler {
+ public FrameHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_DO_ANIMATION:
+ doAnimation();
+ break;
+ case MSG_DO_DRAW:
+ doDraw();
+ break;
+ case MSG_DO_SCHEDULE_VSYNC:
+ doScheduleVsync();
+ break;
+ }
+ }
}
private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
@@ -435,4 +452,9 @@
doAnimation();
}
}
+
+ private static final class Callback {
+ public Callback next;
+ public Runnable runnable;
+ }
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index d6711ee..6c2e540 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -25,6 +25,10 @@
/**
* Provides a low-level mechanism for an application to receive display events
* such as vertical sync.
+ *
+ * The display event receive is NOT thread safe. Moreover, its methods must only
+ * be called on the Looper thread to which it is attached.
+ *
* @hide
*/
public abstract class DisplayEventReceiver {
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index fec0d4b..f60c8f0 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -27,6 +27,15 @@
*/
public abstract class DisplayList {
/**
+ * Flag used when calling
+ * {@link HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int)}.
+ * When this flag is set, draw operations lying outside of the bounds of the
+ * display list will be culled early. It is recommeneded to always set this
+ * flag.
+ */
+ public static final int FLAG_CLIP_CHILDREN = 0x1;
+
+ /**
* Starts recording the display list. All operations performed on the
* returned canvas are recorded and stored in this display list.
*
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 1e92b43..f5fc708 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -385,13 +385,14 @@
private static native void nSetDisplayListName(int displayList, String name);
@Override
- public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
- return nDrawDisplayList(mRenderer,
- ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
+ public boolean drawDisplayList(DisplayList displayList, int width, int height,
+ Rect dirty, int flags) {
+ return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
+ width, height, dirty, flags);
}
private static native boolean nDrawDisplayList(int renderer, int displayList,
- int width, int height, Rect dirty);
+ int width, int height, Rect dirty, int flags);
@Override
void outputDisplayList(DisplayList displayList) {
@@ -407,9 +408,12 @@
void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
final GLES20Layer glLayer = (GLES20Layer) layer;
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
+ } finally {
+ if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ }
}
private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
@@ -607,10 +611,14 @@
return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
}
+ int count;
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- int count = nSaveLayer(mRenderer, nativePaint, saveFlags);
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ count = nSaveLayer(mRenderer, nativePaint, saveFlags);
+ } finally {
+ if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ }
return count;
}
@@ -620,10 +628,14 @@
public int saveLayer(float left, float top, float right, float bottom, Paint paint,
int saveFlags) {
if (left < right && top < bottom) {
+ int count;
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
+ } finally {
+ if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ }
return count;
}
return save(saveFlags);
@@ -707,9 +719,12 @@
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
Paint paint) {
int modifiers = setupModifiers(paint);
- nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
- useCenter, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+ startAngle, sweepAngle, useCenter, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawArc(int renderer, float left, float top,
@@ -726,10 +741,13 @@
if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing patches
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+ } finally {
+ if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ }
}
private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
@@ -740,9 +758,12 @@
if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawBitmap(
@@ -753,10 +774,13 @@
if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
- matrix.native_instance, nativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
+ matrix.native_instance, nativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
@@ -767,23 +791,26 @@
if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- int left, top, right, bottom;
- if (src == null) {
- left = top = 0;
- right = bitmap.getWidth();
- bottom = bitmap.getHeight();
- } else {
- left = src.left;
- right = src.right;
- top = src.top;
- bottom = src.bottom;
+ int left, top, right, bottom;
+ if (src == null) {
+ left = top = 0;
+ right = bitmap.getWidth();
+ bottom = bitmap.getHeight();
+ } else {
+ left = src.left;
+ right = src.right;
+ top = src.top;
+ bottom = src.bottom;
+ }
+
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
-
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
@Override
@@ -791,23 +818,26 @@
if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
// Shaders are ignored when drawing bitmaps
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-
- float left, top, right, bottom;
- if (src == null) {
- left = top = 0;
- right = bitmap.getWidth();
- bottom = bitmap.getHeight();
- } else {
- left = src.left;
- right = src.right;
- top = src.top;
- bottom = src.bottom;
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+
+ float left, top, right, bottom;
+ if (src == null) {
+ left = top = 0;
+ right = bitmap.getWidth();
+ bottom = bitmap.getHeight();
+ } else {
+ left = src.left;
+ right = src.right;
+ top = src.top;
+ bottom = src.bottom;
+ }
+
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
-
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
@@ -819,12 +849,15 @@
int width, int height, boolean hasAlpha, Paint paint) {
// Shaders are ignored when drawing bitmaps
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
- b.recycle();
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ try {
+ final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
+ b.recycle();
+ } finally {
+ if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ }
}
@Override
@@ -854,10 +887,13 @@
colorOffset = 0;
int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
- verts, vertOffset, colors, colorOffset, nativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
+ verts, vertOffset, colors, colorOffset, nativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
@@ -867,8 +903,11 @@
@Override
public void drawCircle(float cx, float cy, float radius, Paint paint) {
int modifiers = setupModifiers(paint);
- nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawCircle(int renderer, float cx, float cy,
@@ -901,8 +940,11 @@
throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
}
int modifiers = setupModifiers(paint);
- nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawLines(int renderer, float[] points,
@@ -916,8 +958,11 @@
@Override
public void drawOval(RectF oval, Paint paint) {
int modifiers = setupModifiers(paint);
- nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawOval(int renderer, float left, float top,
@@ -933,14 +978,17 @@
@Override
public void drawPath(Path path, Paint paint) {
int modifiers = setupModifiers(paint);
- if (path.isSimplePath) {
- if (path.rects != null) {
- nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
+ try {
+ if (path.isSimplePath) {
+ if (path.rects != null) {
+ nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
+ }
+ } else {
+ nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
}
- } else {
- nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
private static native void nDrawPath(int renderer, int path, int paint);
@@ -1001,8 +1049,11 @@
@Override
public void drawPoints(float[] pts, int offset, int count, Paint paint) {
int modifiers = setupModifiers(paint);
- nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawPoints(int renderer, float[] points,
@@ -1047,8 +1098,11 @@
@Override
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
int modifiers = setupModifiers(paint);
- nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawRect(int renderer, float left, float top,
@@ -1072,9 +1126,12 @@
@Override
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
int modifiers = setupModifiers(paint);
- nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
- rx, ry, paint.mNativePaint);
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ try {
+ nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
+ rx, ry, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
}
private static native void nDrawRoundRect(int renderer, float left, float top,
@@ -1223,17 +1280,17 @@
}
private int setupModifiers(Bitmap b, Paint paint) {
- if (b.getConfig() == Bitmap.Config.ALPHA_8) {
+ if (b.getConfig() != Bitmap.Config.ALPHA_8) {
+ final ColorFilter filter = paint.getColorFilter();
+ if (filter != null) {
+ nSetupColorFilter(mRenderer, filter.nativeColorFilter);
+ return MODIFIER_COLOR_FILTER;
+ }
+
+ return MODIFIER_NONE;
+ } else {
return setupModifiers(paint);
}
-
- final ColorFilter filter = paint.getColorFilter();
- if (filter != null) {
- nSetupColorFilter(mRenderer, filter.nativeColorFilter);
- return MODIFIER_COLOR_FILTER;
- }
-
- return MODIFIER_NONE;
}
private int setupModifiers(Paint paint) {
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index c987f48..c9ba65f 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -143,8 +143,8 @@
@Override
public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
int vertOffset, int[] colors, int colorOffset, Paint paint) {
- super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
- paint);
+ super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset,
+ colors, colorOffset, paint);
mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index cbdbbde..838c03c 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -57,11 +57,14 @@
* @param height The height of the display list.
* @param dirty The dirty region to redraw in the next pass, matters only
* if this method returns true, can be null.
+ * @param flags Optional flags about drawing, see {@link DisplayList} for
+ * the possible flags.
*
* @return True if the content of the display list requires another
* drawing pass (invalidate()), false otherwise
*/
- public abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
+ public abstract boolean drawDisplayList(DisplayList displayList, int width, int height,
+ Rect dirty, int flags);
/**
* Outputs the specified display list to the log. This method exists for use by
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 9e8a228..ec95863 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -39,6 +39,7 @@
import javax.microedition.khronos.opengles.GL;
import java.io.File;
+import java.io.PrintWriter;
import static javax.microedition.khronos.egl.EGL10.*;
@@ -84,18 +85,36 @@
static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
/**
+ * System property used to enable or disable hardware rendering profiling.
+ * The default value of this property is assumed to be false.
+ *
+ * When profiling is enabled, the adb shell dumpsys gfxinfo command will
+ * output extra information about the time taken to execute by the last
+ * frames.
+ *
+ * Possible values:
+ * "true", to enable profiling
+ * "false", to disable profiling
+ */
+ static final String PROFILE_PROPERTY = "hwui.profile";
+
+ /**
* System property used to debug EGL configuration choice.
*
* Possible values:
* "choice", print the chosen configuration only
* "all", print all possible configurations
*/
- static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
+ static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
/**
* Turn on to draw dirty regions every other frame.
+ *
+ * Possible values:
+ * "true", to enable dirty regions debugging
+ * "false", to disable dirty regions debugging
*/
- private static final boolean DEBUG_DIRTY_REGION = false;
+ static final String DEBUG_DIRTY_REGIONS_PROPERTY = "hwui.debug_dirty_regions";
/**
* A process can set this flag to false to prevent the use of hardware
@@ -112,6 +131,16 @@
*/
public static boolean sSystemRendererDisabled = false;
+ /**
+ * Number of frames to profile.
+ */
+ private static final int PROFILE_MAX_FRAMES = 64;
+
+ /**
+ * Number of floats per profiled frame.
+ */
+ private static final int PROFILE_FRAME_DATA_COUNT = 3;
+
private boolean mEnabled;
private boolean mRequested = true;
@@ -226,6 +255,12 @@
abstract HardwareCanvas getCanvas();
/**
+ * Outputs extra debugging information in the specified file descriptor.
+ * @param pw
+ */
+ abstract void dumpGfxInfo(PrintWriter pw);
+
+ /**
* Sets the directory to use as a persistent storage for hardware rendering
* resources.
*
@@ -439,6 +474,7 @@
GL mGl;
HardwareCanvas mCanvas;
+
int mFrameCount;
Paint mDebugPaint;
@@ -456,6 +492,12 @@
final boolean mVsyncDisabled;
+ final boolean mProfileEnabled;
+ final float[] mProfileData;
+ int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+
+ final boolean mDebugDirtyRegions;
+
final int mGlVersion;
final boolean mTranslucent;
@@ -466,12 +508,48 @@
GlRenderer(int glVersion, boolean translucent) {
mGlVersion = glVersion;
mTranslucent = translucent;
+
+ String property;
- final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
- mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty);
+ property = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
+ mVsyncDisabled = "true".equalsIgnoreCase(property);
if (mVsyncDisabled) {
Log.d(LOG_TAG, "Disabling v-sync");
}
+
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ if (!ViewDebug.DEBUG_LATENCY) {
+ property = SystemProperties.get(PROFILE_PROPERTY, "false");
+ mProfileEnabled = "true".equalsIgnoreCase(property);
+ if (mProfileEnabled) {
+ Log.d(LOG_TAG, "Profiling hardware renderer");
+ }
+ } else {
+ mProfileEnabled = true;
+ }
+
+ if (mProfileEnabled) {
+ mProfileData = new float[PROFILE_MAX_FRAMES * PROFILE_FRAME_DATA_COUNT];
+ } else {
+ mProfileData = null;
+ }
+
+ property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false");
+ mDebugDirtyRegions = "true".equalsIgnoreCase(property);
+ if (mDebugDirtyRegions) {
+ Log.d(LOG_TAG, "Debugging dirty regions");
+ }
+ }
+
+ @Override
+ void dumpGfxInfo(PrintWriter pw) {
+ if (mProfileEnabled) {
+ pw.printf("\n\tDraw\tProcess\tExecute\n");
+ for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+ mProfileData[i + 2]);
+ }
+ }
}
/**
@@ -860,34 +938,50 @@
(view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
view.mPrivateFlags &= ~View.INVALIDATED;
- final long getDisplayListStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
+ long getDisplayListStartTime = 0;
+ if (mProfileEnabled) {
+ mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+ if (mProfileCurrentFrame >= mProfileData.length) {
+ mProfileCurrentFrame = 0;
+ }
+
getDisplayListStartTime = System.nanoTime();
}
DisplayList displayList = view.getDisplayList();
- if (ViewDebug.DEBUG_LATENCY) {
+ if (mProfileEnabled) {
long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took "
- + ((now - getDisplayListStartTime) * 0.000001f) + "ms");
+ float total = (now - getDisplayListStartTime) * 0.000001f;
+ //noinspection PointlessArithmeticExpression
+ mProfileData[mProfileCurrentFrame] = total;
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took " +
+ total + "ms");
+ }
}
if (displayList != null) {
- final long drawDisplayListStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
+ long drawDisplayListStartTime = 0;
+ if (mProfileEnabled) {
drawDisplayListStartTime = System.nanoTime();
}
- boolean invalidateNeeded = canvas.drawDisplayList(
- displayList, view.getWidth(),
- view.getHeight(), mRedrawClip);
+ boolean invalidateNeeded = canvas.drawDisplayList(displayList,
+ view.getWidth(), view.getHeight(), mRedrawClip,
+ DisplayList.FLAG_CLIP_CHILDREN);
- if (ViewDebug.DEBUG_LATENCY) {
+ if (mProfileEnabled) {
long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took "
- + ((now - drawDisplayListStartTime) * 0.000001f)
- + "ms, invalidateNeeded=" + invalidateNeeded + ".");
+ float total = (now - drawDisplayListStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 1] = total;
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took " +
+ total + "ms, invalidateNeeded=" +
+ invalidateNeeded + ".");
+ }
}
if (invalidateNeeded) {
@@ -902,8 +996,12 @@
// Shouldn't reach here
view.draw(canvas);
}
+ } finally {
+ callbacks.onHardwarePostDraw(canvas);
+ canvas.restoreToCount(saveCount);
+ view.mRecreateDisplayList = false;
- if (DEBUG_DIRTY_REGION) {
+ if (mDebugDirtyRegions) {
if (mDebugPaint == null) {
mDebugPaint = new Paint();
mDebugPaint.setColor(0x7fff0000);
@@ -912,27 +1010,28 @@
canvas.drawRect(dirty, mDebugPaint);
}
}
- } finally {
- callbacks.onHardwarePostDraw(canvas);
- canvas.restoreToCount(saveCount);
- view.mRecreateDisplayList = false;
}
onPostDraw();
attachInfo.mIgnoreDirtyState = false;
- final long eglSwapBuffersStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
+ long eglSwapBuffersStartTime = 0;
+ if (mProfileEnabled) {
eglSwapBuffersStartTime = System.nanoTime();
}
sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
- if (ViewDebug.DEBUG_LATENCY) {
+ if (mProfileEnabled) {
long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took "
- + ((now - eglSwapBuffersStartTime) * 0.000001f) + "ms");
+ float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 2] = total;
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took " +
+ total + "ms");
+ }
}
checkEglErrors();
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 764d8dc..6a457ec 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -21,6 +21,7 @@
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
+import android.util.SparseIntArray;
/**
* Provides a low-level mechanism for an application to receive input events.
@@ -38,13 +39,14 @@
private InputChannel mInputChannel;
private MessageQueue mMessageQueue;
- // The sequence number of the event that is in progress.
- private int mEventSequenceNumberInProgress = -1;
+ // Map from InputEvent sequence numbers to dispatcher sequence numbers.
+ private final SparseIntArray mSeqMap = new SparseIntArray();
private static native int nativeInit(InputEventReceiver receiver,
InputChannel inputChannel, MessageQueue messageQueue);
private static native void nativeDispose(int receiverPtr);
- private static native void nativeFinishInputEvent(int receiverPtr, boolean handled);
+ private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled);
+ private static native void nativeConsumeBatchedInputEvents(int receiverPtr);
/**
* Creates an input event receiver bound to the specified input channel.
@@ -104,12 +106,25 @@
}
/**
+ * Called when a batched input event is pending.
+ *
+ * The batched input event will continue to accumulate additional movement
+ * samples until the recipient calls {@link #consumeBatchedInputEvents} or
+ * an event is received that ends the batch and causes it to be consumed
+ * immediately (such as a pointer up event).
+ */
+ public void onBatchedInputEventPending() {
+ consumeBatchedInputEvents();
+ }
+
+ /**
* Finishes an input event and indicates whether it was handled.
+ * Must be called on the same Looper thread to which the receiver is attached.
*
* @param event The input event that was finished.
* @param handled True if the event was handled.
*/
- public void finishInputEvent(InputEvent event, boolean handled) {
+ public final void finishInputEvent(InputEvent event, boolean handled) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
@@ -117,23 +132,47 @@
Log.w(TAG, "Attempted to finish an input event but the input event "
+ "receiver has already been disposed.");
} else {
- if (event.getSequenceNumber() != mEventSequenceNumberInProgress) {
+ int index = mSeqMap.indexOfKey(event.getSequenceNumber());
+ if (index < 0) {
Log.w(TAG, "Attempted to finish an input event that is not in progress.");
} else {
- mEventSequenceNumberInProgress = -1;
- nativeFinishInputEvent(mReceiverPtr, handled);
+ int seq = mSeqMap.valueAt(index);
+ mSeqMap.removeAt(index);
+ nativeFinishInputEvent(mReceiverPtr, seq, handled);
}
}
event.recycleIfNeededAfterDispatch();
}
+ /**
+ * Consumes all pending batched input events.
+ * Must be called on the same Looper thread to which the receiver is attached.
+ *
+ * This method forces all batched input events to be delivered immediately.
+ * Should be called just before animating or drawing a new frame in the UI.
+ */
+ public final void consumeBatchedInputEvents() {
+ if (mReceiverPtr == 0) {
+ Log.w(TAG, "Attempted to consume batched input events but the input event "
+ + "receiver has already been disposed.");
+ } else {
+ nativeConsumeBatchedInputEvents(mReceiverPtr);
+ }
+ }
+
// Called from native code.
@SuppressWarnings("unused")
- private void dispatchInputEvent(InputEvent event) {
- mEventSequenceNumberInProgress = event.getSequenceNumber();
+ private void dispatchInputEvent(int seq, InputEvent event) {
+ mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchBatchedInputEventPending() {
+ onBatchedInputEventPending();
+ }
+
public static interface Factory {
public InputEventReceiver createInputEventReceiver(
InputChannel inputChannel, Looper looper);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6726c56e..c658a80 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -384,7 +384,7 @@
if (!mHaveFrame) {
return;
}
- ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent();
+ ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) {
mTranslator = viewRoot.mTranslator;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7658d04..c16eb31 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -65,6 +65,7 @@
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
@@ -600,6 +601,8 @@
* @attr ref android.R.styleable#View_paddingLeft
* @attr ref android.R.styleable#View_paddingRight
* @attr ref android.R.styleable#View_paddingTop
+ * @attr ref android.R.styleable#View_paddingStart
+ * @attr ref android.R.styleable#View_paddingEnd
* @attr ref android.R.styleable#View_saveEnabled
* @attr ref android.R.styleable#View_rotation
* @attr ref android.R.styleable#View_rotationX
@@ -1756,6 +1759,16 @@
static final int LAYOUT_DIRECTION_RESOLVED = 0x00000008;
+ /**
+ * Indicates that the view is tracking some sort of transient state
+ * that the app should not need to be aware of, but that the framework
+ * should take special care to preserve.
+ *
+ * @hide
+ */
+ static final int HAS_TRANSIENT_STATE = 0x00000010;
+
+
/* End of masks for mPrivateFlags2 */
static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
@@ -2617,7 +2630,6 @@
/**
* Text direction is inherited thru {@link ViewGroup}
- * @hide
*/
public static final int TEXT_DIRECTION_INHERIT = 0;
@@ -2626,7 +2638,6 @@
* determines the paragraph direction. If there is no strong directional character, the
* paragraph direction is the view's resolved layout direction.
*
- * @hide
*/
public static final int TEXT_DIRECTION_FIRST_STRONG = 1;
@@ -2635,42 +2646,36 @@
* any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
* If there are neither, the paragraph direction is the view's resolved layout direction.
*
- * @hide
*/
public static final int TEXT_DIRECTION_ANY_RTL = 2;
/**
* Text direction is forced to LTR.
*
- * @hide
*/
public static final int TEXT_DIRECTION_LTR = 3;
/**
* Text direction is forced to RTL.
*
- * @hide
*/
public static final int TEXT_DIRECTION_RTL = 4;
/**
* Text direction is coming from the system Locale.
*
- * @hide
*/
public static final int TEXT_DIRECTION_LOCALE = 5;
/**
* Default text direction is inherited
*
- * @hide
*/
protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
/**
* The text direction that has been defined by {@link #setTextDirection(int)}.
*
- * {@hide}
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
@ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
@@ -2688,7 +2693,6 @@
* not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds up the parent
* chain of the view.
*
- * {@hide}
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
@ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
@@ -3774,14 +3778,6 @@
}
if ((mPrivateFlags & FOCUSED) != 0) {
- // If this is the first focusable do not clear focus since the we
- // try to give it focus every time a view clears its focus. Hence,
- // the view that would gain focus already has it.
- View firstFocusable = getFirstFocusable();
- if (firstFocusable == this) {
- return;
- }
-
mPrivateFlags &= ~FOCUSED;
if (mParent != null) {
@@ -3790,24 +3786,9 @@
onFocusChanged(false, 0, null);
refreshDrawableState();
-
- // The view cleared focus and invoked the callbacks, so now is the
- // time to give focus to the the first focusable to ensure that the
- // gain focus is announced after clear focus.
- if (firstFocusable != null) {
- firstFocusable.requestFocus(FOCUS_FORWARD);
- }
}
}
- private View getFirstFocusable() {
- ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- return viewRoot.focusSearch(null, FOCUS_FORWARD);
- }
- return null;
- }
-
/**
* Called to clear the focus of a view that is about to be removed.
* Doesn't call clearChildFocus, which prevents this view from taking
@@ -3819,6 +3800,11 @@
onFocusChanged(false, 0, null);
refreshDrawableState();
+
+ // The view cleared focus and invoked the callbacks, so now is the
+ // time to give focus to the the first focusable from the top to
+ // ensure that the gain focus is announced after clear focus.
+ getRootView().requestFocus(FOCUS_FORWARD);
}
}
@@ -4913,6 +4899,43 @@
}
/**
+ * Indicates whether the view is currently tracking transient state that the
+ * app should not need to concern itself with saving and restoring, but that
+ * the framework should take special note to preserve when possible.
+ *
+ * @return true if the view has transient state
+ *
+ * @hide
+ */
+ @ViewDebug.ExportedProperty(category = "layout")
+ public boolean hasTransientState() {
+ return (mPrivateFlags2 & HAS_TRANSIENT_STATE) == HAS_TRANSIENT_STATE;
+ }
+
+ /**
+ * Set whether this view is currently tracking transient state that the
+ * framework should attempt to preserve when possible.
+ *
+ * @param hasTransientState true if this view has transient state
+ *
+ * @hide
+ */
+ public void setHasTransientState(boolean hasTransientState) {
+ if (hasTransientState() == hasTransientState) return;
+
+ mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) |
+ (hasTransientState ? HAS_TRANSIENT_STATE : 0);
+ if (mParent != null) {
+ try {
+ mParent.childHasTransientStateChanged(this, hasTransientState);
+ } catch (AbstractMethodError e) {
+ Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+ " does not fully implement ViewParent", e);
+ }
+ }
+ }
+
+ /**
* If this view doesn't do any drawing on its own, set this flag to
* allow further optimizations. By default, this flag is not set on
* View, but could be set on some View subclasses such as ViewGroup.
@@ -5466,12 +5489,6 @@
return true;
}
- /** Gets the ViewAncestor, or null if not attached. */
- /*package*/ ViewRootImpl getViewRootImpl() {
- View root = getRootView();
- return root != null ? (ViewRootImpl)root.getParent() : null;
- }
-
/**
* Call this to try to give focus to a specific view or to one of its descendants. This is a
* special variant of {@link #requestFocus() } that will allow views that are not focuable in
@@ -6849,8 +6866,8 @@
if ((changed & VISIBILITY_MASK) != 0) {
if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
- (flags & VISIBILITY_MASK));
+ ((ViewGroup) mParent).onChildVisibilityChanged(this,
+ (changed & VISIBILITY_MASK), (flags & VISIBILITY_MASK));
((View) mParent).invalidate(true);
} else if (mParent != null) {
mParent.invalidateChild(this, null);
@@ -8252,6 +8269,9 @@
throw new NullPointerException("Layout parameters cannot be null");
}
mLayoutParams = params;
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).onSetLayoutParams(this, params);
+ }
requestLayout();
}
@@ -8706,6 +8726,18 @@
}
/**
+ * Gets the view root associated with the View.
+ * @return The view root, or null if none.
+ * @hide
+ */
+ public ViewRootImpl getViewRootImpl() {
+ if (mAttachInfo != null) {
+ return mAttachInfo.mViewRootImpl;
+ }
+ return null;
+ }
+
+ /**
* <p>Causes the Runnable to be added to the message queue.
* The runnable will be run on the user interface thread.</p>
*
@@ -8719,17 +8751,13 @@
* looper processing the message queue is exiting.
*/
public boolean post(Runnable action) {
- Handler handler;
- AttachInfo attachInfo = mAttachInfo;
+ final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- handler = attachInfo.mHandler;
- } else {
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().post(action);
- return true;
+ return attachInfo.mHandler.post(action);
}
-
- return handler.post(action);
+ // Assume that post will succeed later
+ ViewRootImpl.getRunQueue().post(action);
+ return true;
}
/**
@@ -8752,17 +8780,13 @@
* occurs then the message will be dropped.
*/
public boolean postDelayed(Runnable action, long delayMillis) {
- Handler handler;
- AttachInfo attachInfo = mAttachInfo;
+ final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- handler = attachInfo.mHandler;
- } else {
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
- return true;
+ return attachInfo.mHandler.postDelayed(action, delayMillis);
}
-
- return handler.postDelayed(action, delayMillis);
+ // Assume that post will succeed later
+ ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+ return true;
}
/**
@@ -8779,17 +8803,13 @@
* (for instance, if the Runnable was not in the queue already.)
*/
public boolean removeCallbacks(Runnable action) {
- Handler handler;
- AttachInfo attachInfo = mAttachInfo;
+ final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- handler = attachInfo.mHandler;
+ attachInfo.mHandler.removeCallbacks(action);
} else {
// Assume that post will succeed later
ViewRootImpl.getRunQueue().removeCallbacks(action);
- return true;
}
-
- handler.removeCallbacks(action);
return true;
}
@@ -8838,12 +8858,9 @@
public void postInvalidateDelayed(long delayMilliseconds) {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
- AttachInfo attachInfo = mAttachInfo;
+ final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- Message msg = Message.obtain();
- msg.what = AttachInfo.INVALIDATE_MSG;
- msg.obj = this;
- attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+ attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
}
}
@@ -8866,7 +8883,7 @@
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
- AttachInfo attachInfo = mAttachInfo;
+ final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire();
info.target = this;
@@ -8875,10 +8892,7 @@
info.right = right;
info.bottom = bottom;
- final Message msg = Message.obtain();
- msg.what = AttachInfo.INVALIDATE_RECT_MSG;
- msg.obj = info;
- attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+ attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds);
}
}
@@ -9563,10 +9577,6 @@
// Clear any previous layout direction resolution
mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_RTL;
- // Reset also TextDirection as a change into LayoutDirection may impact the selected
- // TextDirectionHeuristic
- resetResolvedTextDirection();
-
// Set resolved depending on layout direction
switch (getLayoutDirection()) {
case LAYOUT_DIRECTION_INHERIT:
@@ -9603,14 +9613,15 @@
}
/**
- * @hide
+ * Force padding depending on layout direction.
*/
- protected void resolvePadding() {
+ public void resolvePadding() {
// If the user specified the absolute padding (either with android:padding or
// android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
// use the default padding or the padding from the background drawable
// (stored at this point in mPadding*)
- switch (getResolvedLayoutDirection()) {
+ int resolvedLayoutDirection = getResolvedLayoutDirection();
+ switch (resolvedLayoutDirection) {
case LAYOUT_DIRECTION_RTL:
// Start user padding override Right user padding. Otherwise, if Right user
// padding is not defined, use the default Right padding. If Right user padding
@@ -9646,6 +9657,18 @@
mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
recomputePadding();
+ onResolvePadding(resolvedLayoutDirection);
+ }
+
+ /**
+ * Resolve padding depending on the layout direction. Subclasses that care about
+ * padding resolution should override this method. The default implementation does
+ * nothing.
+ *
+ * @param layoutDirection the direction of the layout
+ *
+ */
+ public void onResolvePadding(int layoutDirection) {
}
/**
@@ -9672,8 +9695,10 @@
* @hide
*/
protected void resetResolvedLayoutDirection() {
- // Reset the current View resolution
+ // Reset the layout direction resolution
mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED;
+ // Reset also the text direction
+ resetResolvedTextDirection();
}
/**
@@ -9712,13 +9737,12 @@
}
if (mAttachInfo != null) {
- mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this);
+ mAttachInfo.mViewRootImpl.cancelInvalidate(this);
}
mCurrentAnimation = null;
resetResolvedLayoutDirection();
- resetResolvedTextDirection();
}
/**
@@ -10947,6 +10971,346 @@
}
/**
+ * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
+ * case of an active Animation being run on the view.
+ */
+ private boolean drawAnimation(ViewGroup parent, long drawingTime,
+ Animation a, boolean scalingRequired) {
+ Transformation invalidationTransform;
+ final int flags = parent.mGroupFlags;
+ final boolean initialized = a.isInitialized();
+ if (!initialized) {
+ a.initialize(mRight - mLeft, mBottom - mTop, getWidth(), getHeight());
+ a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
+ onAnimationStart();
+ }
+
+ boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
+ if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
+ if (parent.mInvalidationTransformation == null) {
+ parent.mInvalidationTransformation = new Transformation();
+ }
+ invalidationTransform = parent.mInvalidationTransformation;
+ a.getTransformation(drawingTime, invalidationTransform, 1f);
+ } else {
+ invalidationTransform = parent.mChildTransformation;
+ }
+ if (more) {
+ if (!a.willChangeBounds()) {
+ if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==
+ parent.FLAG_OPTIMIZE_INVALIDATE) {
+ parent.mGroupFlags |= parent.FLAG_INVALIDATE_REQUIRED;
+ } else if ((flags & parent.FLAG_INVALIDATE_REQUIRED) == 0) {
+ // The child need to draw an animation, potentially offscreen, so
+ // make sure we do not cancel invalidate requests
+ parent.mPrivateFlags |= DRAW_ANIMATION;
+ parent.invalidate(mLeft, mTop, mRight, mBottom);
+ }
+ } else {
+ if (parent.mInvalidateRegion == null) {
+ parent.mInvalidateRegion = new RectF();
+ }
+ final RectF region = parent.mInvalidateRegion;
+ a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
+ invalidationTransform);
+
+ // The child need to draw an animation, potentially offscreen, so
+ // make sure we do not cancel invalidate requests
+ parent.mPrivateFlags |= DRAW_ANIMATION;
+
+ final int left = mLeft + (int) region.left;
+ final int top = mTop + (int) region.top;
+ parent.invalidate(left, top, left + (int) (region.width() + .5f),
+ top + (int) (region.height() + .5f));
+ }
+ }
+ return more;
+ }
+
+ /**
+ * This method is called by ViewGroup.drawChild() to have each child view draw itself.
+ * This draw() method is an implementation detail and is not intended to be overridden or
+ * to be called from anywhere else other than ViewGroup.drawChild().
+ */
+ boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
+ boolean more = false;
+ final boolean childHasIdentityMatrix = hasIdentityMatrix();
+ final int flags = parent.mGroupFlags;
+
+ if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) {
+ parent.mChildTransformation.clear();
+ parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION;
+ }
+
+ Transformation transformToApply = null;
+ boolean concatMatrix = false;
+
+ boolean scalingRequired = false;
+ boolean caching;
+ int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE;
+
+ final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
+ if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+ (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) {
+ caching = true;
+ if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
+ } else {
+ caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
+ }
+
+ final Animation a = getAnimation();
+ if (a != null) {
+ more = drawAnimation(parent, drawingTime, a, scalingRequired);
+ concatMatrix = a.willChangeTransformationMatrix();
+ transformToApply = parent.mChildTransformation;
+ } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
+ parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
+ final boolean hasTransform =
+ parent.getChildStaticTransformation(this, parent.mChildTransformation);
+ if (hasTransform) {
+ final int transformType = parent.mChildTransformation.getTransformationType();
+ transformToApply = transformType != Transformation.TYPE_IDENTITY ?
+ parent.mChildTransformation : null;
+ concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
+ }
+ }
+
+ concatMatrix |= !childHasIdentityMatrix;
+
+ // Sets the flag as early as possible to allow draw() implementations
+ // to call invalidate() successfully when doing animations
+ mPrivateFlags |= DRAWN;
+
+ if (!concatMatrix && canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
+ (mPrivateFlags & DRAW_ANIMATION) == 0) {
+ return more;
+ }
+
+ if (hardwareAccelerated) {
+ // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
+ // retain the flag's value temporarily in the mRecreateDisplayList flag
+ mRecreateDisplayList = (mPrivateFlags & INVALIDATED) == INVALIDATED;
+ mPrivateFlags &= ~INVALIDATED;
+ }
+
+ computeScroll();
+
+ final int sx = mScrollX;
+ final int sy = mScrollY;
+
+ DisplayList displayList = null;
+ Bitmap cache = null;
+ boolean hasDisplayList = false;
+ if (caching) {
+ if (!hardwareAccelerated) {
+ if (layerType != LAYER_TYPE_NONE) {
+ layerType = LAYER_TYPE_SOFTWARE;
+ buildDrawingCache(true);
+ }
+ cache = getDrawingCache(true);
+ } else {
+ switch (layerType) {
+ case LAYER_TYPE_SOFTWARE:
+ buildDrawingCache(true);
+ cache = getDrawingCache(true);
+ break;
+ case LAYER_TYPE_NONE:
+ // Delay getting the display list until animation-driven alpha values are
+ // set up and possibly passed on to the view
+ hasDisplayList = canHaveDisplayList();
+ break;
+ }
+ }
+ }
+
+ final boolean hasNoCache = cache == null || hasDisplayList;
+ final boolean offsetForScroll = cache == null && !hasDisplayList &&
+ layerType != LAYER_TYPE_HARDWARE;
+
+ final int restoreTo = canvas.save();
+ if (offsetForScroll) {
+ canvas.translate(mLeft - sx, mTop - sy);
+ } else {
+ canvas.translate(mLeft, mTop);
+ if (scalingRequired) {
+ // mAttachInfo cannot be null, otherwise scalingRequired == false
+ final float scale = 1.0f / mAttachInfo.mApplicationScale;
+ canvas.scale(scale, scale);
+ }
+ }
+
+ float alpha = getAlpha();
+ if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
+ if (transformToApply != null || !childHasIdentityMatrix) {
+ int transX = 0;
+ int transY = 0;
+
+ if (offsetForScroll) {
+ transX = -sx;
+ transY = -sy;
+ }
+
+ if (transformToApply != null) {
+ if (concatMatrix) {
+ // Undo the scroll translation, apply the transformation matrix,
+ // then redo the scroll translate to get the correct result.
+ canvas.translate(-transX, -transY);
+ canvas.concat(transformToApply.getMatrix());
+ canvas.translate(transX, transY);
+ parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ }
+
+ float transformAlpha = transformToApply.getAlpha();
+ if (transformAlpha < 1.0f) {
+ alpha *= transformToApply.getAlpha();
+ parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ }
+ }
+
+ if (!childHasIdentityMatrix) {
+ canvas.translate(-transX, -transY);
+ canvas.concat(getMatrix());
+ canvas.translate(transX, transY);
+ }
+ }
+
+ if (alpha < 1.0f) {
+ parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ if (hasNoCache) {
+ final int multipliedAlpha = (int) (255 * alpha);
+ if (!onSetAlpha(multipliedAlpha)) {
+ int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
+ if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN ||
+ layerType != LAYER_TYPE_NONE) {
+ layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
+ }
+ if (layerType == LAYER_TYPE_NONE) {
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
+ scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+ }
+ } else {
+ // Alpha is handled by the child directly, clobber the layer's alpha
+ mPrivateFlags |= ALPHA_SET;
+ }
+ }
+ }
+ } else if ((mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+ onSetAlpha(255);
+ mPrivateFlags &= ~ALPHA_SET;
+ }
+
+ if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) {
+ if (offsetForScroll) {
+ canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
+ } else {
+ if (!scalingRequired || cache == null) {
+ canvas.clipRect(0, 0, mRight - mLeft, mBottom - mTop);
+ } else {
+ canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
+ }
+ }
+ }
+
+ if (hasDisplayList) {
+ displayList = getDisplayList();
+ if (!displayList.isValid()) {
+ // Uncommon, but possible. If a view is removed from the hierarchy during the call
+ // to getDisplayList(), the display list will be marked invalid and we should not
+ // try to use it again.
+ displayList = null;
+ hasDisplayList = false;
+ }
+ }
+
+ if (hasNoCache) {
+ boolean layerRendered = false;
+ if (layerType == LAYER_TYPE_HARDWARE) {
+ final HardwareLayer layer = getHardwareLayer();
+ if (layer != null && layer.isValid()) {
+ mLayerPaint.setAlpha((int) (alpha * 255));
+ ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);
+ layerRendered = true;
+ } else {
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayer(scrollX, scrollY,
+ scrollX + mRight - mLeft, scrollY + mBottom - mTop, mLayerPaint,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ }
+ }
+
+ if (!layerRendered) {
+ if (!hasDisplayList) {
+ // Fast path for layouts with no backgrounds
+ if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+ if (ViewDebug.TRACE_HIERARCHY) {
+ ViewDebug.trace(parent, ViewDebug.HierarchyTraceType.DRAW);
+ }
+ mPrivateFlags &= ~DIRTY_MASK;
+ dispatchDraw(canvas);
+ } else {
+ draw(canvas);
+ }
+ } else {
+ mPrivateFlags &= ~DIRTY_MASK;
+ ((HardwareCanvas) canvas).drawDisplayList(displayList,
+ mRight - mLeft, mBottom - mTop, null, flags);
+ }
+ }
+ } else if (cache != null) {
+ mPrivateFlags &= ~DIRTY_MASK;
+ Paint cachePaint;
+
+ if (layerType == LAYER_TYPE_NONE) {
+ cachePaint = parent.mCachePaint;
+ if (cachePaint == null) {
+ cachePaint = new Paint();
+ cachePaint.setDither(false);
+ parent.mCachePaint = cachePaint;
+ }
+ if (alpha < 1.0f) {
+ cachePaint.setAlpha((int) (alpha * 255));
+ parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE;
+ } else if ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) ==
+ parent.FLAG_ALPHA_LOWER_THAN_ONE) {
+ cachePaint.setAlpha(255);
+ parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE;
+ }
+ } else {
+ cachePaint = mLayerPaint;
+ cachePaint.setAlpha((int) (alpha * 255));
+ }
+ canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
+ }
+
+ canvas.restoreToCount(restoreTo);
+
+ if (a != null && !more) {
+ if (!hardwareAccelerated && !a.getFillAfter()) {
+ onSetAlpha(255);
+ }
+ parent.finishAnimatingView(this, a);
+ }
+
+ if (more && hardwareAccelerated) {
+ // invalidation is the trigger to recreate display lists, so if we're using
+ // display lists to render, force an invalidate to allow the animation to
+ // continue drawing another frame
+ parent.invalidate(true);
+ if (a.hasAlpha() && (mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+ // alpha animations should cause the child to recreate its display list
+ invalidate(true);
+ }
+ }
+
+ mRecreateDisplayList = false;
+
+ return more;
+ }
+
+ /**
* Manually render this view (and all of its children) to the given Canvas.
* The view must have already done a full layout before this function is
* called. When implementing a view, implement
@@ -11932,8 +12296,6 @@
* @param top the top padding in pixels
* @param end the end padding in pixels
* @param bottom the bottom padding in pixels
- *
- * @hide
*/
public void setPaddingRelative(int start, int top, int end, int bottom) {
mUserPaddingRelative = true;
@@ -11988,8 +12350,6 @@
* scrollbars as well.
*
* @return the start padding in pixels
- *
- * @hide
*/
public int getPaddingStart() {
return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
@@ -12013,8 +12373,6 @@
* scrollbars as well.
*
* @return the end padding in pixels
- *
- * @hide
*/
public int getPaddingEnd() {
return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
@@ -12028,8 +12386,6 @@
* @attr ref android.R.styleable#View_paddingEnd
*
* @return true if the padding is relative or false if it is not.
- *
- * @hide
*/
public boolean isPaddingRelative() {
return mUserPaddingRelative;
@@ -13761,8 +14117,6 @@
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
* {@link #TEXT_DIRECTION_LOCALE},
- *
- * @hide
*/
public int getTextDirection() {
return mTextDirection;
@@ -13779,8 +14133,6 @@
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
* {@link #TEXT_DIRECTION_LOCALE},
- *
- * @hide
*/
public void setTextDirection(int textDirection) {
if (textDirection != mTextDirection) {
@@ -13800,8 +14152,6 @@
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
* {@link #TEXT_DIRECTION_LOCALE},
- *
- * @hide
*/
public int getResolvedTextDirection() {
if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
@@ -13811,29 +14161,47 @@
}
/**
- * Resolve the text direction.
- *
- * @hide
+ * Resolve the text direction. Will call {@link View#onResolveTextDirection()} when resolution
+ * is done.
*/
- protected void resolveTextDirection() {
+ public void resolveTextDirection() {
+ if (mResolvedTextDirection != TEXT_DIRECTION_INHERIT) {
+ // Resolution has already been done.
+ return;
+ }
if (mTextDirection != TEXT_DIRECTION_INHERIT) {
mResolvedTextDirection = mTextDirection;
- return;
- }
- if (mParent != null && mParent instanceof ViewGroup) {
+ } else if (mParent != null && mParent instanceof ViewGroup) {
mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
- return;
+ } else {
+ mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
}
- mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
+ onResolveTextDirection();
}
/**
- * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
- *
- * @hide
+ * Called when text direction has been resolved. Subclasses that care about text direction
+ * resolution should override this method. The default implementation does nothing.
*/
- protected void resetResolvedTextDirection() {
+ public void onResolveTextDirection() {
+ }
+
+ /**
+ * Reset resolved text direction. Text direction can be resolved with a call to
+ * getResolvedTextDirection(). Will call {@link View#onResetResolvedTextDirection()} when
+ * reset is done.
+ */
+ public void resetResolvedTextDirection() {
mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
+ onResetResolvedTextDirection();
+ }
+
+ /**
+ * Called when text direction is reset. Subclasses that care about text direction reset should
+ * override this method and do a reset of the text direction of their children. The default
+ * implementation does nothing.
+ */
+ public void onResetResolvedTextDirection() {
}
//
@@ -14658,24 +15026,17 @@
Canvas mCanvas;
/**
+ * The view root impl.
+ */
+ final ViewRootImpl mViewRootImpl;
+
+ /**
* A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
* handler can be used to pump events in the UI events queue.
*/
final Handler mHandler;
/**
- * Identifier for messages requesting the view to be invalidated.
- * Such messages should be sent to {@link #mHandler}.
- */
- static final int INVALIDATE_MSG = 0x1;
-
- /**
- * Identifier for messages requesting the view to invalidate a region.
- * Such messages should be sent to {@link #mHandler}.
- */
- static final int INVALIDATE_RECT_MSG = 0x2;
-
- /**
* Temporary for use in computing invalidate rectangles while
* calling up the hierarchy.
*/
@@ -14703,10 +15064,11 @@
* @param handler the events handler the view must use
*/
AttachInfo(IWindowSession session, IWindow window,
- Handler handler, Callbacks effectPlayer) {
+ ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
mSession = session;
mWindow = window;
mWindowToken = window.asBinder();
+ mViewRootImpl = viewRootImpl;
mHandler = handler;
mRootCallbacks = effectPlayer;
}
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index c1db572..2a17845 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -375,7 +375,7 @@
}
private static BufferedWriter sHierarchyTraces;
- private static ViewRootImpl sHierarhcyRoot;
+ private static ViewRootImpl sHierarchyRoot;
private static String sHierarchyTracePrefix;
/**
@@ -855,7 +855,7 @@
return;
}
- if (sHierarhcyRoot != null) {
+ if (sHierarchyRoot != null) {
throw new IllegalStateException("You must call stopHierarchyTracing() before running" +
" a new trace!");
}
@@ -874,7 +874,7 @@
return;
}
- sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent();
+ sHierarchyRoot = view.getViewRootImpl();
}
/**
@@ -896,7 +896,7 @@
return;
}
- if (sHierarhcyRoot == null || sHierarchyTraces == null) {
+ if (sHierarchyRoot == null || sHierarchyTraces == null) {
throw new IllegalStateException("You must call startHierarchyTracing() before" +
" stopHierarchyTracing()!");
}
@@ -921,7 +921,7 @@
return;
}
- View view = sHierarhcyRoot.getView();
+ View view = sHierarchyRoot.getView();
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
dumpViewHierarchy(group, out, 0);
@@ -932,7 +932,7 @@
}
}
- sHierarhcyRoot = null;
+ sHierarchyRoot = null;
}
static void dispatchCommand(View view, String command, String parameters,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d3af618..c68d77d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -77,6 +77,7 @@
* @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
*/
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
+ private static final String TAG = "ViewGroup";
private static final boolean DBG = false;
@@ -103,18 +104,18 @@
* A Transformation used when drawing children, to
* apply on the child being drawn.
*/
- private final Transformation mChildTransformation = new Transformation();
+ final Transformation mChildTransformation = new Transformation();
/**
* Used to track the current invalidation region.
*/
- private RectF mInvalidateRegion;
+ RectF mInvalidateRegion;
/**
* A Transformation used to calculate a correct
* invalidation area when the application is autoscaled.
*/
- private Transformation mInvalidationTransformation;
+ Transformation mInvalidationTransformation;
// View currently under an ongoing drag
private View mCurrentDragView;
@@ -168,9 +169,14 @@
*/
protected int mGroupFlags;
+ /**
+ * NOTE: If you change the flags below make sure to reflect the changes
+ * the DisplayList class
+ */
+
// When set, ViewGroup invalidates only the child's rectangle
// Set by default
- private static final int FLAG_CLIP_CHILDREN = 0x1;
+ static final int FLAG_CLIP_CHILDREN = 0x1;
// When set, ViewGroup excludes the padding area from the invalidate rectangle
// Set by default
@@ -178,7 +184,7 @@
// When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
// a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
- private static final int FLAG_INVALIDATE_REQUIRED = 0x4;
+ static final int FLAG_INVALIDATE_REQUIRED = 0x4;
// When set, dispatchDraw() will run the layout animation and unset the flag
private static final int FLAG_RUN_ANIMATION = 0x8;
@@ -186,7 +192,7 @@
// When set, there is either no layout animation on the ViewGroup or the layout
// animation is over
// Set by default
- private static final int FLAG_ANIMATION_DONE = 0x10;
+ static final int FLAG_ANIMATION_DONE = 0x10;
// If set, this ViewGroup has padding; if unset there is no padding and we don't need
// to clip it, even if FLAG_CLIP_TO_PADDING is set
@@ -200,10 +206,10 @@
// layout animation; this avoid clobbering the hierarchy
// Automatically set when the layout animation starts, depending on the animation's
// characteristics
- private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
+ static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
// When set, the next call to drawChild() will clear mChildTransformation's matrix
- private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
+ static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
// When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
// the children's Bitmap caches if necessary
@@ -233,7 +239,7 @@
// When the previous drawChild() invocation used an alpha value that was lower than
// 1.0 and set it in mCachePaint
- private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
+ static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
/**
* When set, this ViewGroup's drawable states also include those
@@ -244,13 +250,13 @@
/**
* When set, this ViewGroup tries to always draw its children using their drawing cache.
*/
- private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
+ static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
/**
* When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
* draw its children with their drawing cache.
*/
- private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
+ static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
/**
* When set, this group will go through its list of children to notify them of
@@ -352,7 +358,7 @@
private static final int ARRAY_CAPACITY_INCREMENT = 12;
// Used to draw cached views
- private Paint mCachePaint;
+ Paint mCachePaint;
// Used to animate add/remove changes in layout
private LayoutTransition mTransition;
@@ -368,7 +374,11 @@
// Indicates whether this container will use its children layers to draw
@ViewDebug.ExportedProperty(category = "drawing")
- private boolean mDrawLayers = true;
+ boolean mDrawLayers = true;
+
+ // Indicates how many of this container's child subtrees contain transient state
+ @ViewDebug.ExportedProperty(category = "layout")
+ private int mChildCountWithTransientState = 0;
public ViewGroup(Context context) {
super(context);
@@ -648,6 +658,38 @@
}
/**
+ * Called when a child view has changed whether or not it is tracking transient state.
+ *
+ * @hide
+ */
+ public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
+ final boolean oldHasTransientState = hasTransientState();
+ if (childHasTransientState) {
+ mChildCountWithTransientState++;
+ } else {
+ mChildCountWithTransientState--;
+ }
+
+ final boolean newHasTransientState = hasTransientState();
+ if (mParent != null && oldHasTransientState != newHasTransientState) {
+ try {
+ mParent.childHasTransientStateChanged(this, newHasTransientState);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, mParent.getClass().getSimpleName() +
+ " does not fully implement ViewParent", e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean hasTransientState() {
+ return mChildCountWithTransientState > 0 || super.hasTransientState();
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -2620,336 +2662,11 @@
*
* @param canvas The canvas on which to draw the child
* @param child Who to draw
- * @param drawingTime The time at which draw is occuring
+ * @param drawingTime The time at which draw is occurring
* @return True if an invalidate() was issued
*/
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- boolean more = false;
-
- final int cl = child.mLeft;
- final int ct = child.mTop;
- final int cr = child.mRight;
- final int cb = child.mBottom;
-
- final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
-
- final int flags = mGroupFlags;
-
- if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
- mChildTransformation.clear();
- mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
- }
-
- Transformation transformToApply = null;
- Transformation invalidationTransform;
- final Animation a = child.getAnimation();
- boolean concatMatrix = false;
-
- boolean scalingRequired = false;
- boolean caching;
- int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE;
-
- final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
- if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
- (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
- caching = true;
- if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
- } else {
- caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
- }
-
- if (a != null) {
- final boolean initialized = a.isInitialized();
- if (!initialized) {
- a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
- a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
- child.onAnimationStart();
- }
-
- more = a.getTransformation(drawingTime, mChildTransformation, 1f);
- if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
- if (mInvalidationTransformation == null) {
- mInvalidationTransformation = new Transformation();
- }
- invalidationTransform = mInvalidationTransformation;
- a.getTransformation(drawingTime, invalidationTransform, 1f);
- } else {
- invalidationTransform = mChildTransformation;
- }
- transformToApply = mChildTransformation;
-
- concatMatrix = a.willChangeTransformationMatrix();
-
- if (more) {
- if (!a.willChangeBounds()) {
- if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
- FLAG_OPTIMIZE_INVALIDATE) {
- mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
- } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
- // The child need to draw an animation, potentially offscreen, so
- // make sure we do not cancel invalidate requests
- mPrivateFlags |= DRAW_ANIMATION;
- invalidate(cl, ct, cr, cb);
- }
- } else {
- if (mInvalidateRegion == null) {
- mInvalidateRegion = new RectF();
- }
- final RectF region = mInvalidateRegion;
- a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform);
-
- // The child need to draw an animation, potentially offscreen, so
- // make sure we do not cancel invalidate requests
- mPrivateFlags |= DRAW_ANIMATION;
-
- final int left = cl + (int) region.left;
- final int top = ct + (int) region.top;
- invalidate(left, top, left + (int) (region.width() + .5f),
- top + (int) (region.height() + .5f));
- }
- }
- } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
- FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
- final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
- if (hasTransform) {
- final int transformType = mChildTransformation.getTransformationType();
- transformToApply = transformType != Transformation.TYPE_IDENTITY ?
- mChildTransformation : null;
- concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
- }
- }
-
- concatMatrix |= !childHasIdentityMatrix;
-
- // Sets the flag as early as possible to allow draw() implementations
- // to call invalidate() successfully when doing animations
- child.mPrivateFlags |= DRAWN;
-
- if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
- (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
- return more;
- }
-
- if (hardwareAccelerated) {
- // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
- // retain the flag's value temporarily in the mRecreateDisplayList flag
- child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
- child.mPrivateFlags &= ~INVALIDATED;
- }
-
- child.computeScroll();
-
- final int sx = child.mScrollX;
- final int sy = child.mScrollY;
-
- DisplayList displayList = null;
- Bitmap cache = null;
- boolean hasDisplayList = false;
- if (caching) {
- if (!hardwareAccelerated) {
- if (layerType != LAYER_TYPE_NONE) {
- layerType = LAYER_TYPE_SOFTWARE;
- child.buildDrawingCache(true);
- }
- cache = child.getDrawingCache(true);
- } else {
- switch (layerType) {
- case LAYER_TYPE_SOFTWARE:
- child.buildDrawingCache(true);
- cache = child.getDrawingCache(true);
- break;
- case LAYER_TYPE_NONE:
- // Delay getting the display list until animation-driven alpha values are
- // set up and possibly passed on to the view
- hasDisplayList = child.canHaveDisplayList();
- break;
- }
- }
- }
-
- final boolean hasNoCache = cache == null || hasDisplayList;
- final boolean offsetForScroll = cache == null && !hasDisplayList &&
- layerType != LAYER_TYPE_HARDWARE;
-
- final int restoreTo = canvas.save();
- if (offsetForScroll) {
- canvas.translate(cl - sx, ct - sy);
- } else {
- canvas.translate(cl, ct);
- if (scalingRequired) {
- // mAttachInfo cannot be null, otherwise scalingRequired == false
- final float scale = 1.0f / mAttachInfo.mApplicationScale;
- canvas.scale(scale, scale);
- }
- }
-
- float alpha = child.getAlpha();
- if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
- if (transformToApply != null || !childHasIdentityMatrix) {
- int transX = 0;
- int transY = 0;
-
- if (offsetForScroll) {
- transX = -sx;
- transY = -sy;
- }
-
- if (transformToApply != null) {
- if (concatMatrix) {
- // Undo the scroll translation, apply the transformation matrix,
- // then redo the scroll translate to get the correct result.
- canvas.translate(-transX, -transY);
- canvas.concat(transformToApply.getMatrix());
- canvas.translate(transX, transY);
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
- }
-
- float transformAlpha = transformToApply.getAlpha();
- if (transformAlpha < 1.0f) {
- alpha *= transformToApply.getAlpha();
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
- }
- }
-
- if (!childHasIdentityMatrix) {
- canvas.translate(-transX, -transY);
- canvas.concat(child.getMatrix());
- canvas.translate(transX, transY);
- }
- }
-
- if (alpha < 1.0f) {
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
- if (hasNoCache) {
- final int multipliedAlpha = (int) (255 * alpha);
- if (!child.onSetAlpha(multipliedAlpha)) {
- int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN ||
- layerType != LAYER_TYPE_NONE) {
- layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
- }
- if (layerType == LAYER_TYPE_NONE) {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl,
- scrollY + cb - ct, multipliedAlpha, layerFlags);
- }
- } else {
- // Alpha is handled by the child directly, clobber the layer's alpha
- child.mPrivateFlags |= ALPHA_SET;
- }
- }
- }
- } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
- child.onSetAlpha(255);
- child.mPrivateFlags &= ~ALPHA_SET;
- }
-
- if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
- if (offsetForScroll) {
- canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
- } else {
- if (!scalingRequired || cache == null) {
- canvas.clipRect(0, 0, cr - cl, cb - ct);
- } else {
- canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
- }
- }
- }
-
- if (hasDisplayList) {
- displayList = child.getDisplayList();
- if (!displayList.isValid()) {
- // Uncommon, but possible. If a view is removed from the hierarchy during the call
- // to getDisplayList(), the display list will be marked invalid and we should not
- // try to use it again.
- displayList = null;
- hasDisplayList = false;
- }
- }
-
- if (hasNoCache) {
- boolean layerRendered = false;
- if (layerType == LAYER_TYPE_HARDWARE) {
- final HardwareLayer layer = child.getHardwareLayer();
- if (layer != null && layer.isValid()) {
- child.mLayerPaint.setAlpha((int) (alpha * 255));
- ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
- layerRendered = true;
- } else {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayer(scrollX, scrollY,
- scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- }
- }
-
- if (!layerRendered) {
- if (!hasDisplayList) {
- // Fast path for layouts with no backgrounds
- if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
- }
- child.mPrivateFlags &= ~DIRTY_MASK;
- child.dispatchDraw(canvas);
- } else {
- child.draw(canvas);
- }
- } else {
- child.mPrivateFlags &= ~DIRTY_MASK;
- ((HardwareCanvas) canvas).drawDisplayList(displayList, cr - cl, cb - ct, null);
- }
- }
- } else if (cache != null) {
- child.mPrivateFlags &= ~DIRTY_MASK;
- Paint cachePaint;
-
- if (layerType == LAYER_TYPE_NONE) {
- cachePaint = mCachePaint;
- if (cachePaint == null) {
- cachePaint = new Paint();
- cachePaint.setDither(false);
- mCachePaint = cachePaint;
- }
- if (alpha < 1.0f) {
- cachePaint.setAlpha((int) (alpha * 255));
- mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
- } else if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
- cachePaint.setAlpha(255);
- mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
- }
- } else {
- cachePaint = child.mLayerPaint;
- cachePaint.setAlpha((int) (alpha * 255));
- }
- canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
- }
-
- canvas.restoreToCount(restoreTo);
-
- if (a != null && !more) {
- if (!hardwareAccelerated && !a.getFillAfter()) {
- child.onSetAlpha(255);
- }
- finishAnimatingView(child, a);
- }
-
- if (more && hardwareAccelerated) {
- // invalidation is the trigger to recreate display lists, so if we're using
- // display lists to render, force an invalidate to allow the animation to
- // continue drawing another frame
- invalidate(true);
- if (a.hasAlpha() && (child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
- // alpha animations should cause the child to recreate its display list
- child.invalidate(true);
- }
- }
-
- child.mRecreateDisplayList = false;
-
- return more;
+ return child.draw(canvas, this, drawingTime);
}
/**
@@ -3419,6 +3136,10 @@
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
}
+
+ if (child.hasTransientState()) {
+ childHasTransientStateChanged(child, true);
+ }
}
private void addInArray(View child, int index) {
@@ -3615,6 +3336,10 @@
view.dispatchDetachedFromWindow();
}
+ if (view.hasTransientState()) {
+ childHasTransientStateChanged(view, false);
+ }
+
onViewRemoved(view);
needGlobalAttributesUpdate(false);
@@ -3686,6 +3411,10 @@
view.dispatchDetachedFromWindow();
}
+ if (view.hasTransientState()) {
+ childHasTransientStateChanged(view, false);
+ }
+
needGlobalAttributesUpdate(false);
onViewRemoved(view);
@@ -3751,6 +3480,10 @@
view.dispatchDetachedFromWindow();
}
+ if (view.hasTransientState()) {
+ childHasTransientStateChanged(view, false);
+ }
+
onViewRemoved(view);
view.mParent = null;
@@ -3791,6 +3524,10 @@
child.dispatchDetachedFromWindow();
}
+ if (child.hasTransientState()) {
+ childHasTransientStateChanged(child, false);
+ }
+
onViewRemoved(child);
}
@@ -3929,130 +3666,136 @@
// through
final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
- if (dirty == null) {
- if (child.mLayerType != LAYER_TYPE_NONE) {
- mPrivateFlags |= INVALIDATED;
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- child.mLocalDirtyRect.setEmpty();
- }
- do {
- View view = null;
- if (parent instanceof View) {
- view = (View) parent;
- if (view.mLayerType != LAYER_TYPE_NONE) {
- view.mLocalDirtyRect.setEmpty();
- if (view.getParent() instanceof View) {
- final View grandParent = (View) view.getParent();
- grandParent.mPrivateFlags |= INVALIDATED;
- grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ //noinspection PointlessBooleanExpression
+ if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
+ if (dirty == null) {
+ if (child.mLayerType != LAYER_TYPE_NONE) {
+ mPrivateFlags |= INVALIDATED;
+ mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ child.mLocalDirtyRect.setEmpty();
+ }
+ do {
+ View view = null;
+ if (parent instanceof View) {
+ view = (View) parent;
+ if (view.mLayerType != LAYER_TYPE_NONE) {
+ view.mLocalDirtyRect.setEmpty();
+ if (view.getParent() instanceof View) {
+ final View grandParent = (View) view.getParent();
+ grandParent.mPrivateFlags |= INVALIDATED;
+ grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ }
+ }
+ if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
+ // already marked dirty - we're done
+ break;
}
}
- if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
- // already marked dirty - we're done
- break;
+
+ if (drawAnimation) {
+ if (view != null) {
+ view.mPrivateFlags |= DRAW_ANIMATION;
+ } else if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).mIsAnimating = true;
+ }
}
- }
-
- if (drawAnimation) {
- if (view != null) {
- view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRootImpl) {
- ((ViewRootImpl) parent).mIsAnimating = true;
- }
- }
-
- if (parent instanceof ViewRootImpl) {
- ((ViewRootImpl) parent).invalidate();
- parent = null;
- } else if (view != null) {
- if ((view.mPrivateFlags & DRAWN) == DRAWN ||
- (view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
- view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
- view.mPrivateFlags |= DIRTY;
- parent = view.mParent;
- } else {
+
+ if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).invalidate();
parent = null;
+ } else if (view != null) {
+ if ((view.mPrivateFlags & DRAWN) == DRAWN ||
+ (view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
+ view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ view.mPrivateFlags |= DIRTY;
+ parent = view.mParent;
+ } else {
+ parent = null;
+ }
}
- }
- } while (parent != null);
- } else {
- // Check whether the child that requests the invalidate is fully opaque
- // Views being animated or transformed are not considered opaque because we may
- // be invalidating their old position and need the parent to paint behind them.
- Matrix childMatrix = child.getMatrix();
- final boolean isOpaque = child.isOpaque() && !drawAnimation &&
- child.getAnimation() == null && childMatrix.isIdentity();
- // Mark the child as dirty, using the appropriate flag
- // Make sure we do not set both flags at the same time
- int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
-
- if (child.mLayerType != LAYER_TYPE_NONE) {
- mPrivateFlags |= INVALIDATED;
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- child.mLocalDirtyRect.union(dirty);
+ } while (parent != null);
}
- final int[] location = attachInfo.mInvalidateChildLocation;
- location[CHILD_LEFT_INDEX] = child.mLeft;
- location[CHILD_TOP_INDEX] = child.mTop;
- if (!childMatrix.isIdentity()) {
- RectF boundingRect = attachInfo.mTmpTransformRect;
- boundingRect.set(dirty);
- //boundingRect.inset(-0.5f, -0.5f);
- childMatrix.mapRect(boundingRect);
- dirty.set((int) (boundingRect.left - 0.5f),
- (int) (boundingRect.top - 0.5f),
- (int) (boundingRect.right + 0.5f),
- (int) (boundingRect.bottom + 0.5f));
- }
-
- do {
- View view = null;
- if (parent instanceof View) {
- view = (View) parent;
- if (view.mLayerType != LAYER_TYPE_NONE &&
- view.getParent() instanceof View) {
- final View grandParent = (View) view.getParent();
- grandParent.mPrivateFlags |= INVALIDATED;
- grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
- }
- }
-
- if (drawAnimation) {
- if (view != null) {
- view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRootImpl) {
- ((ViewRootImpl) parent).mIsAnimating = true;
- }
- }
-
- // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
- // flag coming from the child that initiated the invalidate
- if (view != null) {
- if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
- view.getSolidColor() == 0) {
- opaqueFlag = DIRTY;
- }
- if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
- view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
- }
- }
-
- parent = parent.invalidateChildInParent(location, dirty);
- if (view != null) {
- // Account for transform on current parent
- Matrix m = view.getMatrix();
- if (!m.isIdentity()) {
- RectF boundingRect = attachInfo.mTmpTransformRect;
- boundingRect.set(dirty);
- m.mapRect(boundingRect);
- dirty.set((int) boundingRect.left, (int) boundingRect.top,
- (int) (boundingRect.right + 0.5f),
- (int) (boundingRect.bottom + 0.5f));
- }
- }
- } while (parent != null);
+ return;
}
+
+ // Check whether the child that requests the invalidate is fully opaque
+ // Views being animated or transformed are not considered opaque because we may
+ // be invalidating their old position and need the parent to paint behind them.
+ Matrix childMatrix = child.getMatrix();
+ final boolean isOpaque = child.isOpaque() && !drawAnimation &&
+ child.getAnimation() == null && childMatrix.isIdentity();
+ // Mark the child as dirty, using the appropriate flag
+ // Make sure we do not set both flags at the same time
+ int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
+
+ if (child.mLayerType != LAYER_TYPE_NONE) {
+ mPrivateFlags |= INVALIDATED;
+ mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ child.mLocalDirtyRect.union(dirty);
+ }
+
+ final int[] location = attachInfo.mInvalidateChildLocation;
+ location[CHILD_LEFT_INDEX] = child.mLeft;
+ location[CHILD_TOP_INDEX] = child.mTop;
+ if (!childMatrix.isIdentity()) {
+ RectF boundingRect = attachInfo.mTmpTransformRect;
+ boundingRect.set(dirty);
+ //boundingRect.inset(-0.5f, -0.5f);
+ childMatrix.mapRect(boundingRect);
+ dirty.set((int) (boundingRect.left - 0.5f),
+ (int) (boundingRect.top - 0.5f),
+ (int) (boundingRect.right + 0.5f),
+ (int) (boundingRect.bottom + 0.5f));
+ }
+
+ do {
+ View view = null;
+ if (parent instanceof View) {
+ view = (View) parent;
+ if (view.mLayerType != LAYER_TYPE_NONE &&
+ view.getParent() instanceof View) {
+ final View grandParent = (View) view.getParent();
+ grandParent.mPrivateFlags |= INVALIDATED;
+ grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ }
+ }
+
+ if (drawAnimation) {
+ if (view != null) {
+ view.mPrivateFlags |= DRAW_ANIMATION;
+ } else if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).mIsAnimating = true;
+ }
+ }
+
+ // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
+ // flag coming from the child that initiated the invalidate
+ if (view != null) {
+ if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
+ view.getSolidColor() == 0) {
+ opaqueFlag = DIRTY;
+ }
+ if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+ view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+ }
+ }
+
+ parent = parent.invalidateChildInParent(location, dirty);
+ if (view != null) {
+ // Account for transform on current parent
+ Matrix m = view.getMatrix();
+ if (!m.isIdentity()) {
+ RectF boundingRect = attachInfo.mTmpTransformRect;
+ boundingRect.set(dirty);
+ m.mapRect(boundingRect);
+ dirty.set((int) (boundingRect.left - 0.5f),
+ (int) (boundingRect.top - 0.5f),
+ (int) (boundingRect.right + 0.5f),
+ (int) (boundingRect.bottom + 0.5f));
+ }
+ }
+ } while (parent != null);
}
}
@@ -4854,7 +4597,7 @@
* @param view The view whose animation has finished
* @param animation The animation, cannot be null
*/
- private void finishAnimatingView(final View view, Animation animation) {
+ void finishAnimatingView(final View view, Animation animation) {
final ArrayList<View> disappearingChildren = mDisappearingChildren;
if (disappearingChildren != null) {
if (disappearingChildren.contains(view)) {
@@ -5177,9 +4920,7 @@
}
@Override
- protected void resetResolvedTextDirection() {
- super.resetResolvedTextDirection();
-
+ public void onResetResolvedTextDirection() {
// Take care of resetting the children resolution too
final int count = getChildCount();
for (int i = 0; i < count; i++) {
@@ -5203,6 +4944,10 @@
return true;
}
+ /** @hide */
+ protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
+ }
+
/**
* LayoutParams are used by views to tell their parents how they want to be
* laid out. See
@@ -5411,49 +5156,52 @@
*/
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
/**
- * The left margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The left margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int leftMargin;
/**
- * The top margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The top margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int topMargin;
/**
- * The right margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The right margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int rightMargin;
/**
- * The bottom margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The bottom margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int bottomMargin;
/**
* The start margin in pixels of the child.
- *
- * @hide
- *
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
- protected int startMargin = DEFAULT_RELATIVE;
+ public int startMargin = DEFAULT_RELATIVE;
/**
* The end margin in pixels of the child.
- *
- * @hide
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
- protected int endMargin = DEFAULT_RELATIVE;
+ public int endMargin = DEFAULT_RELATIVE;
/**
* The default start and end margin.
@@ -5585,8 +5333,6 @@
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
*
* @return the start margin in pixels.
- *
- * @hide
*/
public int getMarginStart() {
return startMargin;
@@ -5598,8 +5344,6 @@
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
*
* @return the end margin in pixels.
- *
- * @hide
*/
public int getMarginEnd() {
return endMargin;
@@ -5612,8 +5356,6 @@
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
*
* @return true if either marginStart or marginEnd has been set
- *
- * @hide
*/
public boolean isMarginRelative() {
return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 873d4bb..8395f1b 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -261,4 +261,14 @@
* @return True if the event was sent.
*/
public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event);
+
+ /**
+ * Called when a child view now has or no longer is tracking transient state.
+ *
+ * @param child Child view whose state has changed
+ * @param hasTransientState true if this child has transient state
+ *
+ * @hide
+ */
+ public void childHasTransientStateChanged(View child, boolean hasTransientState);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cbf4b5a..84ce2a4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -61,6 +61,7 @@
import android.util.Pools;
import android.util.Slog;
import android.util.TypedValue;
+import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
@@ -96,9 +97,8 @@
* {@hide}
*/
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRootImpl extends Handler implements ViewParent,
- View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks,
- Choreographer.OnDrawListener {
+public final class ViewRootImpl implements ViewParent,
+ View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
private static final String TAG = "ViewRootImpl";
private static final boolean DBG = false;
private static final boolean LOCAL_LOGV = false;
@@ -213,6 +213,7 @@
final Rect mVisRect; // used to retrieve visible rect of focused view.
boolean mTraversalScheduled;
+ int mTraversalBarrier;
long mLastTraversalFinishedTimeNanos;
long mLastDrawFinishedTimeNanos;
boolean mWillDrawSoon;
@@ -380,7 +381,7 @@
new AccessibilityInteractionConnectionManager();
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
- mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
+ mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
@@ -463,8 +464,6 @@
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
- mChoreographer.addOnDrawListener(this);
-
mView = view;
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
@@ -841,18 +840,43 @@
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
- mChoreographer.scheduleDraw();
+ mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
+ scheduleFrame();
}
}
public void unscheduleTraversals() {
- mTraversalScheduled = false;
- }
-
- @Override
- public void onDraw() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
+ mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
+ }
+ }
+
+ void scheduleFrame() {
+ if (!mFrameScheduled) {
+ mFrameScheduled = true;
+ mChoreographer.postDrawCallback(mFrameRunnable);
+ }
+ }
+
+ void unscheduleFrame() {
+ unscheduleTraversals();
+
+ if (mFrameScheduled) {
+ mFrameScheduled = false;
+ mChoreographer.removeDrawCallback(mFrameRunnable);
+ }
+ }
+
+ void doFrame() {
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.consumeBatchedInputEvents();
+ }
+ doProcessInputEvents();
+
+ if (mTraversalScheduled) {
+ mTraversalScheduled = false;
+ mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
doTraversal();
}
}
@@ -891,8 +915,6 @@
}
private void doTraversal() {
- doProcessInputEvents();
-
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
@@ -1916,7 +1938,7 @@
sFirstDrawComplete = true;
final int count = sFirstDrawHandlers.size();
for (int i = 0; i< count; i++) {
- post(sFirstDrawHandlers.get(i));
+ mHandler.post(sFirstDrawHandlers.get(i));
}
}
}
@@ -2373,7 +2395,7 @@
mInputChannel = null;
}
- mChoreographer.removeOnDrawListener(this);
+ unscheduleFrame();
}
void updateConfiguration(Configuration config, boolean force) {
@@ -2428,283 +2450,289 @@
}
}
- public final static int DIE = 1001;
- public final static int RESIZED = 1002;
- public final static int RESIZED_REPORT = 1003;
- public final static int WINDOW_FOCUS_CHANGED = 1004;
- public final static int DISPATCH_KEY = 1005;
- public final static int DISPATCH_APP_VISIBILITY = 1008;
- public final static int DISPATCH_GET_NEW_SURFACE = 1009;
- public final static int IME_FINISHED_EVENT = 1010;
- public final static int DISPATCH_KEY_FROM_IME = 1011;
- public final static int FINISH_INPUT_CONNECTION = 1012;
- public final static int CHECK_FOCUS = 1013;
- public final static int CLOSE_SYSTEM_DIALOGS = 1014;
- public final static int DISPATCH_DRAG_EVENT = 1015;
- public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
- public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
- public final static int DISPATCH_GENERIC_MOTION = 1018;
- public final static int UPDATE_CONFIGURATION = 1019;
- public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1020;
- public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021;
- public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022;
- public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 1023;
- public final static int DO_PROCESS_INPUT_EVENTS = 1024;
+ private final static int MSG_INVALIDATE = 1;
+ private final static int MSG_INVALIDATE_RECT = 2;
+ private final static int MSG_DIE = 3;
+ private final static int MSG_RESIZED = 4;
+ private final static int MSG_RESIZED_REPORT = 5;
+ private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
+ private final static int MSG_DISPATCH_KEY = 7;
+ private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
+ private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
+ private final static int MSG_IME_FINISHED_EVENT = 10;
+ private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
+ private final static int MSG_FINISH_INPUT_CONNECTION = 12;
+ private final static int MSG_CHECK_FOCUS = 13;
+ private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
+ private final static int MSG_DISPATCH_DRAG_EVENT = 15;
+ private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
+ private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
+ private final static int MSG_UPDATE_CONFIGURATION = 18;
+ private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 19;
+ private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 20;
+ private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 21;
+ private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 22;
+ private final static int MSG_PROCESS_INPUT_EVENTS = 23;
- @Override
- public String getMessageName(Message message) {
- switch (message.what) {
- case DIE:
- return "DIE";
- case RESIZED:
- return "RESIZED";
- case RESIZED_REPORT:
- return "RESIZED_REPORT";
- case WINDOW_FOCUS_CHANGED:
- return "WINDOW_FOCUS_CHANGED";
- case DISPATCH_KEY:
- return "DISPATCH_KEY";
- case DISPATCH_APP_VISIBILITY:
- return "DISPATCH_APP_VISIBILITY";
- case DISPATCH_GET_NEW_SURFACE:
- return "DISPATCH_GET_NEW_SURFACE";
- case IME_FINISHED_EVENT:
- return "IME_FINISHED_EVENT";
- case DISPATCH_KEY_FROM_IME:
- return "DISPATCH_KEY_FROM_IME";
- case FINISH_INPUT_CONNECTION:
- return "FINISH_INPUT_CONNECTION";
- case CHECK_FOCUS:
- return "CHECK_FOCUS";
- case CLOSE_SYSTEM_DIALOGS:
- return "CLOSE_SYSTEM_DIALOGS";
- case DISPATCH_DRAG_EVENT:
- return "DISPATCH_DRAG_EVENT";
- case DISPATCH_DRAG_LOCATION_EVENT:
- return "DISPATCH_DRAG_LOCATION_EVENT";
- case DISPATCH_SYSTEM_UI_VISIBILITY:
- return "DISPATCH_SYSTEM_UI_VISIBILITY";
- case DISPATCH_GENERIC_MOTION:
- return "DISPATCH_GENERIC_MOTION";
- case UPDATE_CONFIGURATION:
- return "UPDATE_CONFIGURATION";
- case DO_PERFORM_ACCESSIBILITY_ACTION:
- return "DO_PERFORM_ACCESSIBILITY_ACTION";
- case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
- return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
- case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
- return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
- case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
- return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
- case DO_PROCESS_INPUT_EVENTS:
- return "DO_PROCESS_INPUT_EVENTS";
+ final class ViewRootHandler extends Handler {
+ @Override
+ public String getMessageName(Message message) {
+ switch (message.what) {
+ case MSG_INVALIDATE:
+ return "MSG_INVALIDATE";
+ case MSG_INVALIDATE_RECT:
+ return "MSG_INVALIDATE_RECT";
+ case MSG_DIE:
+ return "MSG_DIE";
+ case MSG_RESIZED:
+ return "MSG_RESIZED";
+ case MSG_RESIZED_REPORT:
+ return "MSG_RESIZED_REPORT";
+ case MSG_WINDOW_FOCUS_CHANGED:
+ return "MSG_WINDOW_FOCUS_CHANGED";
+ case MSG_DISPATCH_KEY:
+ return "MSG_DISPATCH_KEY";
+ case MSG_DISPATCH_APP_VISIBILITY:
+ return "MSG_DISPATCH_APP_VISIBILITY";
+ case MSG_DISPATCH_GET_NEW_SURFACE:
+ return "MSG_DISPATCH_GET_NEW_SURFACE";
+ case MSG_IME_FINISHED_EVENT:
+ return "MSG_IME_FINISHED_EVENT";
+ case MSG_DISPATCH_KEY_FROM_IME:
+ return "MSG_DISPATCH_KEY_FROM_IME";
+ case MSG_FINISH_INPUT_CONNECTION:
+ return "MSG_FINISH_INPUT_CONNECTION";
+ case MSG_CHECK_FOCUS:
+ return "MSG_CHECK_FOCUS";
+ case MSG_CLOSE_SYSTEM_DIALOGS:
+ return "MSG_CLOSE_SYSTEM_DIALOGS";
+ case MSG_DISPATCH_DRAG_EVENT:
+ return "MSG_DISPATCH_DRAG_EVENT";
+ case MSG_DISPATCH_DRAG_LOCATION_EVENT:
+ return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
+ case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
+ return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
+ case MSG_UPDATE_CONFIGURATION:
+ return "MSG_UPDATE_CONFIGURATION";
+ case MSG_PERFORM_ACCESSIBILITY_ACTION:
+ return "MSG_PERFORM_ACCESSIBILITY_ACTION";
+ case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
+ return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
+ case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
+ return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
+ case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
+ return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
+ case MSG_PROCESS_INPUT_EVENTS:
+ return "MSG_PROCESS_INPUT_EVENTS";
+ }
+ return super.getMessageName(message);
}
- return super.getMessageName(message);
- }
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case View.AttachInfo.INVALIDATE_MSG:
- ((View) msg.obj).invalidate();
- break;
- case View.AttachInfo.INVALIDATE_RECT_MSG:
- final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
- info.target.invalidate(info.left, info.top, info.right, info.bottom);
- info.release();
- break;
- case IME_FINISHED_EVENT:
- handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
- break;
- case DO_PROCESS_INPUT_EVENTS:
- mProcessInputEventsScheduled = false;
- doProcessInputEvents();
- break;
- case DISPATCH_APP_VISIBILITY:
- handleAppVisibility(msg.arg1 != 0);
- break;
- case DISPATCH_GET_NEW_SURFACE:
- handleGetNewSurface();
- break;
- case RESIZED:
- ResizedInfo ri = (ResizedInfo)msg.obj;
-
- if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
- && mPendingContentInsets.equals(ri.coveredInsets)
- && mPendingVisibleInsets.equals(ri.visibleInsets)
- && ((ResizedInfo)msg.obj).newConfig == null) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_INVALIDATE:
+ ((View) msg.obj).invalidate();
break;
- }
- // fall through...
- case RESIZED_REPORT:
- if (mAdded) {
- Configuration config = ((ResizedInfo)msg.obj).newConfig;
- if (config != null) {
- updateConfiguration(config, false);
- }
- mWinFrame.left = 0;
- mWinFrame.right = msg.arg1;
- mWinFrame.top = 0;
- mWinFrame.bottom = msg.arg2;
- mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
- mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
- if (msg.what == RESIZED_REPORT) {
- mReportNextDraw = true;
- }
+ case MSG_INVALIDATE_RECT:
+ final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
+ info.target.invalidate(info.left, info.top, info.right, info.bottom);
+ info.release();
+ break;
+ case MSG_IME_FINISHED_EVENT:
+ handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
+ break;
+ case MSG_PROCESS_INPUT_EVENTS:
+ mProcessInputEventsScheduled = false;
+ doProcessInputEvents();
+ break;
+ case MSG_DISPATCH_APP_VISIBILITY:
+ handleAppVisibility(msg.arg1 != 0);
+ break;
+ case MSG_DISPATCH_GET_NEW_SURFACE:
+ handleGetNewSurface();
+ break;
+ case MSG_RESIZED:
+ ResizedInfo ri = (ResizedInfo)msg.obj;
- if (mView != null) {
- forceLayout(mView);
+ if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
+ && mPendingContentInsets.equals(ri.coveredInsets)
+ && mPendingVisibleInsets.equals(ri.visibleInsets)
+ && ((ResizedInfo)msg.obj).newConfig == null) {
+ break;
}
- requestLayout();
- }
- break;
- case WINDOW_FOCUS_CHANGED: {
- if (mAdded) {
- boolean hasWindowFocus = msg.arg1 != 0;
- mAttachInfo.mHasWindowFocus = hasWindowFocus;
-
- profileRendering(hasWindowFocus);
+ // fall through...
+ case MSG_RESIZED_REPORT:
+ if (mAdded) {
+ Configuration config = ((ResizedInfo)msg.obj).newConfig;
+ if (config != null) {
+ updateConfiguration(config, false);
+ }
+ mWinFrame.left = 0;
+ mWinFrame.right = msg.arg1;
+ mWinFrame.top = 0;
+ mWinFrame.bottom = msg.arg2;
+ mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
+ mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
+ if (msg.what == MSG_RESIZED_REPORT) {
+ mReportNextDraw = true;
+ }
- if (hasWindowFocus) {
- boolean inTouchMode = msg.arg2 != 0;
- ensureTouchModeLocally(inTouchMode);
+ if (mView != null) {
+ forceLayout(mView);
+ }
+ requestLayout();
+ }
+ break;
+ case MSG_WINDOW_FOCUS_CHANGED: {
+ if (mAdded) {
+ boolean hasWindowFocus = msg.arg1 != 0;
+ mAttachInfo.mHasWindowFocus = hasWindowFocus;
- if (mAttachInfo.mHardwareRenderer != null &&
- mSurface != null && mSurface.isValid()) {
- mFullRedrawNeeded = true;
- try {
- mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
- mHolder);
- } catch (Surface.OutOfResourcesException e) {
- Log.e(TAG, "OutOfResourcesException locking surface", e);
+ profileRendering(hasWindowFocus);
+
+ if (hasWindowFocus) {
+ boolean inTouchMode = msg.arg2 != 0;
+ ensureTouchModeLocally(inTouchMode);
+
+ if (mAttachInfo.mHardwareRenderer != null &&
+ mSurface != null && mSurface.isValid()) {
+ mFullRedrawNeeded = true;
try {
- if (!sWindowSession.outOfMemory(mWindow)) {
- Slog.w(TAG, "No processes killed for memory; killing self");
- Process.killProcess(Process.myPid());
+ mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
+ mHolder);
+ } catch (Surface.OutOfResourcesException e) {
+ Log.e(TAG, "OutOfResourcesException locking surface", e);
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
}
- } catch (RemoteException ex) {
+ // Retry in a bit.
+ sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
+ return;
}
- // Retry in a bit.
- sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
- return;
}
}
- }
- mLastWasImTarget = WindowManager.LayoutParams
- .mayUseInputMethod(mWindowAttributes.flags);
+ mLastWasImTarget = WindowManager.LayoutParams
+ .mayUseInputMethod(mWindowAttributes.flags);
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (mView != null) {
- if (hasWindowFocus && imm != null && mLastWasImTarget) {
- imm.startGettingWindowFocus(mView);
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (mView != null) {
+ if (hasWindowFocus && imm != null && mLastWasImTarget) {
+ imm.startGettingWindowFocus(mView);
+ }
+ mAttachInfo.mKeyDispatchState.reset();
+ mView.dispatchWindowFocusChanged(hasWindowFocus);
}
- mAttachInfo.mKeyDispatchState.reset();
- mView.dispatchWindowFocusChanged(hasWindowFocus);
- }
- // Note: must be done after the focus change callbacks,
- // so all of the view state is set up correctly.
- if (hasWindowFocus) {
- if (imm != null && mLastWasImTarget) {
- imm.onWindowFocus(mView, mView.findFocus(),
- mWindowAttributes.softInputMode,
- !mHasHadWindowFocus, mWindowAttributes.flags);
- }
- // Clear the forward bit. We can just do this directly, since
- // the window manager doesn't care about it.
- mWindowAttributes.softInputMode &=
- ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
- ((WindowManager.LayoutParams)mView.getLayoutParams())
- .softInputMode &=
+ // Note: must be done after the focus change callbacks,
+ // so all of the view state is set up correctly.
+ if (hasWindowFocus) {
+ if (imm != null && mLastWasImTarget) {
+ imm.onWindowFocus(mView, mView.findFocus(),
+ mWindowAttributes.softInputMode,
+ !mHasHadWindowFocus, mWindowAttributes.flags);
+ }
+ // Clear the forward bit. We can just do this directly, since
+ // the window manager doesn't care about it.
+ mWindowAttributes.softInputMode &=
~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
- mHasHadWindowFocus = true;
- }
+ ((WindowManager.LayoutParams)mView.getLayoutParams())
+ .softInputMode &=
+ ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+ mHasHadWindowFocus = true;
+ }
- if (hasWindowFocus && mView != null) {
- sendAccessibilityEvents();
+ if (hasWindowFocus && mView != null) {
+ sendAccessibilityEvents();
+ }
}
+ } break;
+ case MSG_DIE:
+ doDie();
+ break;
+ case MSG_DISPATCH_KEY: {
+ KeyEvent event = (KeyEvent)msg.obj;
+ enqueueInputEvent(event, null, 0, true);
+ } break;
+ case MSG_DISPATCH_KEY_FROM_IME: {
+ if (LOCAL_LOGV) Log.v(
+ TAG, "Dispatching key "
+ + msg.obj + " from IME to " + mView);
+ KeyEvent event = (KeyEvent)msg.obj;
+ if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
+ // The IME is trying to say this event is from the
+ // system! Bad bad bad!
+ //noinspection UnusedAssignment
+ event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
+ }
+ enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
+ } break;
+ case MSG_FINISH_INPUT_CONNECTION: {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.reportFinishInputConnection((InputConnection)msg.obj);
+ }
+ } break;
+ case MSG_CHECK_FOCUS: {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.checkFocus();
+ }
+ } break;
+ case MSG_CLOSE_SYSTEM_DIALOGS: {
+ if (mView != null) {
+ mView.onCloseSystemDialogs((String)msg.obj);
+ }
+ } break;
+ case MSG_DISPATCH_DRAG_EVENT:
+ case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
+ DragEvent event = (DragEvent)msg.obj;
+ event.mLocalState = mLocalDragState; // only present when this app called startDrag()
+ handleDragEvent(event);
+ } break;
+ case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
+ handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
+ } break;
+ case MSG_UPDATE_CONFIGURATION: {
+ Configuration config = (Configuration)msg.obj;
+ if (config.isOtherSeqNewer(mLastConfiguration)) {
+ config = mLastConfiguration;
+ }
+ updateConfiguration(config, false);
+ } break;
+ case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
+ if (mView != null) {
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
+ }
+ } break;
+ case MSG_PERFORM_ACCESSIBILITY_ACTION: {
+ if (mView != null) {
+ getAccessibilityInteractionController()
+ .perfromAccessibilityActionUiThread(msg);
+ }
+ } break;
+ case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
+ if (mView != null) {
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfoByViewIdUiThread(msg);
+ }
+ } break;
+ case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
+ if (mView != null) {
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfosByTextUiThread(msg);
+ }
+ } break;
}
- } break;
- case DIE:
- doDie();
- break;
- case DISPATCH_KEY: {
- KeyEvent event = (KeyEvent)msg.obj;
- enqueueInputEvent(event, null, 0);
- } break;
- case DISPATCH_KEY_FROM_IME: {
- if (LOCAL_LOGV) Log.v(
- TAG, "Dispatching key "
- + msg.obj + " from IME to " + mView);
- KeyEvent event = (KeyEvent)msg.obj;
- if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
- // The IME is trying to say this event is from the
- // system! Bad bad bad!
- //noinspection UnusedAssignment
- event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
- }
- enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME);
- } break;
- case FINISH_INPUT_CONNECTION: {
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- imm.reportFinishInputConnection((InputConnection)msg.obj);
- }
- } break;
- case CHECK_FOCUS: {
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- imm.checkFocus();
- }
- } break;
- case CLOSE_SYSTEM_DIALOGS: {
- if (mView != null) {
- mView.onCloseSystemDialogs((String)msg.obj);
- }
- } break;
- case DISPATCH_DRAG_EVENT:
- case DISPATCH_DRAG_LOCATION_EVENT: {
- DragEvent event = (DragEvent)msg.obj;
- event.mLocalState = mLocalDragState; // only present when this app called startDrag()
- handleDragEvent(event);
- } break;
- case DISPATCH_SYSTEM_UI_VISIBILITY: {
- handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
- } break;
- case UPDATE_CONFIGURATION: {
- Configuration config = (Configuration)msg.obj;
- if (config.isOtherSeqNewer(mLastConfiguration)) {
- config = mLastConfiguration;
- }
- updateConfiguration(config, false);
- } break;
- case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
- if (mView != null) {
- getAccessibilityInteractionController()
- .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
- }
- } break;
- case DO_PERFORM_ACCESSIBILITY_ACTION: {
- if (mView != null) {
- getAccessibilityInteractionController()
- .perfromAccessibilityActionUiThread(msg);
- }
- } break;
- case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
- if (mView != null) {
- getAccessibilityInteractionController()
- .findAccessibilityNodeInfoByViewIdUiThread(msg);
- }
- } break;
- case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
- if (mView != null) {
- getAccessibilityInteractionController()
- .findAccessibilityNodeInfosByTextUiThread(msg);
- }
- } break;
}
}
+ final ViewRootHandler mHandler = new ViewRootHandler();
/**
* Something in the current window tells us we need to change the touch mode. For
@@ -2947,7 +2975,7 @@
case MotionEvent.ACTION_DOWN:
x.reset(2);
y.reset(2);
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -2955,7 +2983,7 @@
case MotionEvent.ACTION_UP:
x.reset(2);
y.reset(2);
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -3009,7 +3037,7 @@
+ keycode);
movement--;
int repeatCount = accelMovement - movement;
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -3019,11 +3047,11 @@
+ keycode);
movement--;
curTime = SystemClock.uptimeMillis();
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_DOWN, keycode, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_UP, keycode, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -3090,7 +3118,7 @@
if (xDirection != mLastJoystickXDirection) {
if (mLastJoystickXKeyCode != 0) {
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
mLastJoystickXKeyCode = 0;
@@ -3101,7 +3129,7 @@
if (xDirection != 0 && synthesizeNewKeys) {
mLastJoystickXKeyCode = xDirection > 0
? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
}
@@ -3109,7 +3137,7 @@
if (yDirection != mLastJoystickYDirection) {
if (mLastJoystickYKeyCode != 0) {
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
mLastJoystickYKeyCode = 0;
@@ -3120,7 +3148,7 @@
if (yDirection != 0 && synthesizeNewKeys) {
mLastJoystickYKeyCode = yDirection > 0
? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
}
@@ -3671,7 +3699,7 @@
if (immediate) {
doDie();
} else {
- sendEmptyMessage(DIE);
+ mHandler.sendEmptyMessage(MSG_DIE);
}
}
@@ -3708,8 +3736,8 @@
}
public void requestUpdateConfiguration(Configuration config) {
- Message msg = obtainMessage(UPDATE_CONFIGURATION, config);
- sendMessage(msg);
+ Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
+ mHandler.sendMessage(msg);
}
private void destroyHardwareRenderer() {
@@ -3721,10 +3749,15 @@
}
void dispatchImeFinishedEvent(int seq, boolean handled) {
- Message msg = obtainMessage(IME_FINISHED_EVENT);
+ Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT);
msg.arg1 = seq;
msg.arg2 = handled ? 1 : 0;
- sendMessage(msg);
+ mHandler.sendMessage(msg);
+ }
+
+ public void dispatchFinishInputConnection(InputConnection connection) {
+ Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
+ mHandler.sendMessage(msg);
}
public void dispatchResized(int w, int h, Rect coveredInsets,
@@ -3733,7 +3766,7 @@
+ " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
+ " reportDraw=" + reportDraw);
- Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
+ Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT :MSG_RESIZED);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(coveredInsets);
mTranslator.translateRectInScreenToAppWindow(visibleInsets);
@@ -3747,7 +3780,7 @@
ri.visibleInsets = new Rect(visibleInsets);
ri.newConfig = newConfig;
msg.obj = ri;
- sendMessage(msg);
+ mHandler.sendMessage(msg);
}
/**
@@ -3805,8 +3838,12 @@
}
}
+ void enqueueInputEvent(InputEvent event) {
+ enqueueInputEvent(event, null, 0, false);
+ }
+
void enqueueInputEvent(InputEvent event,
- InputEventReceiver receiver, int flags) {
+ InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
if (ViewDebug.DEBUG_LATENCY) {
@@ -3830,13 +3867,17 @@
last.mNext = q;
}
- scheduleProcessInputEvents();
+ if (processImmediately) {
+ doProcessInputEvents();
+ } else {
+ scheduleProcessInputEvents();
+ }
}
private void scheduleProcessInputEvents() {
if (!mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = true;
- sendEmptyMessage(DO_PROCESS_INPUT_EVENTS);
+ mHandler.sendEmptyMessage(MSG_PROCESS_INPUT_EVENTS);
}
}
@@ -3853,7 +3894,7 @@
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
- removeMessages(DO_PROCESS_INPUT_EVENTS);
+ mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
@@ -3912,6 +3953,16 @@
}
}
+ final class FrameRunnable implements Runnable {
+ @Override
+ public void run() {
+ mFrameScheduled = false;
+ doFrame();
+ }
+ }
+ final FrameRunnable mFrameRunnable = new FrameRunnable();
+ boolean mFrameScheduled;
+
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
@@ -3919,51 +3970,79 @@
@Override
public void onInputEvent(InputEvent event) {
- enqueueInputEvent(event, this, 0);
+ enqueueInputEvent(event, this, 0, true);
+ }
+
+ @Override
+ public void onBatchedInputEventPending() {
+ scheduleFrame();
}
}
WindowInputEventReceiver mInputEventReceiver;
+ public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
+ Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
+ mHandler.sendMessageDelayed(msg, delayMilliseconds);
+ }
+
+ public void cancelInvalidate(View view) {
+ mHandler.removeMessages(MSG_INVALIDATE, view);
+ }
+
+ public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
+ long delayMilliseconds) {
+ final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
+ mHandler.sendMessageDelayed(msg, delayMilliseconds);
+ }
+
public void dispatchKey(KeyEvent event) {
- enqueueInputEvent(event, null, 0);
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+
+ public void dispatchKeyFromIme(KeyEvent event) {
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
}
public void dispatchAppVisibility(boolean visible) {
- Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
msg.arg1 = visible ? 1 : 0;
- sendMessage(msg);
+ mHandler.sendMessage(msg);
}
public void dispatchGetNewSurface() {
- Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
- sendMessage(msg);
+ Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
+ mHandler.sendMessage(msg);
}
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Message msg = Message.obtain();
- msg.what = WINDOW_FOCUS_CHANGED;
+ msg.what = MSG_WINDOW_FOCUS_CHANGED;
msg.arg1 = hasFocus ? 1 : 0;
msg.arg2 = inTouchMode ? 1 : 0;
- sendMessage(msg);
+ mHandler.sendMessage(msg);
}
public void dispatchCloseSystemDialogs(String reason) {
Message msg = Message.obtain();
- msg.what = CLOSE_SYSTEM_DIALOGS;
+ msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
msg.obj = reason;
- sendMessage(msg);
+ mHandler.sendMessage(msg);
}
public void dispatchDragEvent(DragEvent event) {
final int what;
if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
- what = DISPATCH_DRAG_LOCATION_EVENT;
- removeMessages(what);
+ what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
+ mHandler.removeMessages(what);
} else {
- what = DISPATCH_DRAG_EVENT;
+ what = MSG_DISPATCH_DRAG_EVENT;
}
- Message msg = obtainMessage(what, event);
- sendMessage(msg);
+ Message msg = mHandler.obtainMessage(what, event);
+ mHandler.sendMessage(msg);
}
public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
@@ -3973,7 +4052,14 @@
args.globalVisibility = globalVisibility;
args.localValue = localValue;
args.localChanges = localChanges;
- sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, args));
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
+ }
+
+ public void dispatchCheckFocus() {
+ if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
+ // This will result in a call to checkFocus() below.
+ mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
+ }
}
/**
@@ -4004,7 +4090,7 @@
}
if (!mSendWindowContentChangedAccessibilityEvent.mIsPending) {
mSendWindowContentChangedAccessibilityEvent.mIsPending = true;
- postDelayed(mSendWindowContentChangedAccessibilityEvent,
+ mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
}
}
@@ -4015,7 +4101,7 @@
*/
private void removeSendWindowContentChangedCallback() {
if (mSendWindowContentChangedAccessibilityEvent != null) {
- removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
+ mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
}
}
@@ -4058,6 +4144,10 @@
return scrollToRectOrFocus(rectangle, immediate);
}
+ public void childHasTransientStateChanged(View child, boolean hasTransientState) {
+ // Do nothing.
+ }
+
class TakenSurfaceHolder extends BaseSurfaceHolder {
@Override
public boolean onAllowLockCanvas() {
@@ -4475,6 +4565,9 @@
}
/**
+ * The run queue is used to enqueue pending work from Views when no Handler is
+ * attached. The work is executed during the next call to performTraversals on
+ * the thread.
* @hide
*/
static final class RunQueue {
@@ -4733,8 +4826,8 @@
long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
long interrogatingTid) {
- Message message = Message.obtain();
- message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+ Message message = mHandler.obtainMessage();
+ message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
message.arg1 = interrogatingPid;
SomeArgs args = mPool.acquire();
args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
@@ -4748,11 +4841,10 @@
// client can handle the message to generate the result.
if (interrogatingPid == Process.myPid()
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
- message.setTarget(ViewRootImpl.this);
AccessibilityInteractionClient.getInstanceForThread(
interrogatingTid).setSameThreadMessage(message);
} else {
- sendMessage(message);
+ mHandler.sendMessage(message);
}
}
@@ -4791,8 +4883,8 @@
public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid) {
- Message message = Message.obtain();
- message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
+ Message message = mHandler.obtainMessage();
+ message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
SomeArgs args = mPool.acquire();
args.argi1 = viewId;
@@ -4805,11 +4897,10 @@
// client can handle the message to generate the result.
if (interrogatingPid == Process.myPid()
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
- message.setTarget(ViewRootImpl.this);
AccessibilityInteractionClient.getInstanceForThread(
interrogatingTid).setSameThreadMessage(message);
} else {
- sendMessage(message);
+ mHandler.sendMessage(message);
}
}
@@ -4848,8 +4939,8 @@
String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
long interrogatingTid) {
- Message message = Message.obtain();
- message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
+ Message message = mHandler.obtainMessage();
+ message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
SomeArgs args = mPool.acquire();
args.arg1 = text;
args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
@@ -4863,11 +4954,10 @@
// client can handle the message to generate the result.
if (interrogatingPid == Process.myPid()
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
- message.setTarget(ViewRootImpl.this);
AccessibilityInteractionClient.getInstanceForThread(
interrogatingTid).setSameThreadMessage(message);
} else {
- sendMessage(message);
+ mHandler.sendMessage(message);
}
}
@@ -4934,8 +5024,8 @@
public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
int interactionId, IAccessibilityInteractionConnectionCallback callback,
int interogatingPid, long interrogatingTid) {
- Message message = Message.obtain();
- message.what = DO_PERFORM_ACCESSIBILITY_ACTION;
+ Message message = mHandler.obtainMessage();
+ message.what = MSG_PERFORM_ACCESSIBILITY_ACTION;
message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
message.arg2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
SomeArgs args = mPool.acquire();
@@ -4949,11 +5039,10 @@
// client can handle the message to generate the result.
if (interogatingPid == Process.myPid()
&& interrogatingTid == Looper.getMainLooper().getThread().getId()) {
- message.setTarget(ViewRootImpl.this);
AccessibilityInteractionClient.getInstanceForThread(
interrogatingTid).setSameThreadMessage(message);
} else {
- sendMessage(message);
+ mHandler.sendMessage(message);
}
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 24a3066..9152cc3 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -91,6 +91,10 @@
private static final int MSG_VIBRATE = 4;
private static final int MSG_TIMEOUT = 5;
private static final int MSG_RINGER_MODE_CHANGED = 6;
+ private static final int MSG_MUTE_CHANGED = 7;
+
+ // Pseudo stream type for master volume
+ private static final int STREAM_MASTER = -100;
protected Context mContext;
private AudioManager mAudioManager;
@@ -148,7 +152,13 @@
R.string.volume_icon_description_notification,
R.drawable.ic_audio_notification,
R.drawable.ic_audio_notification_mute,
- true);
+ true),
+ // for now, use media resources for master volume
+ MasterStream(STREAM_MASTER,
+ R.string.volume_icon_description_media,
+ R.drawable.ic_audio_vol,
+ R.drawable.ic_audio_vol_mute,
+ false);
int streamType;
int descRes;
@@ -173,7 +183,8 @@
StreamResources.VoiceStream,
StreamResources.MediaStream,
StreamResources.NotificationStream,
- StreamResources.AlarmStream
+ StreamResources.AlarmStream,
+ StreamResources.MasterStream
};
/** Object that contains data for each slider */
@@ -195,6 +206,16 @@
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioService = volumeService;
+ // For now, only show master volume if master volume is supported
+ boolean useMasterVolume = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
+ if (useMasterVolume) {
+ for (int i = 0; i < STREAMS.length; i++) {
+ StreamResources streamRes = STREAMS[i];
+ streamRes.show = (streamRes.streamType == STREAM_MASTER);
+ }
+ }
+
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = mView = inflater.inflate(R.layout.volume_adjust, null);
@@ -245,7 +266,7 @@
mVibrator = new Vibrator();
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
- mShowCombinedVolumes = !mVoiceCapable;
+ mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
// If we don't want to show multiple volumes, hide the settings button and divider
if (!mShowCombinedVolumes) {
mMoreButton.setVisibility(View.GONE);
@@ -274,7 +295,43 @@
}
private boolean isMuted(int streamType) {
- return mAudioManager.isStreamMute(streamType);
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.isMasterMute();
+ } else {
+ return mAudioService.isStreamMute(streamType);
+ }
+ }
+
+ private int getStreamMaxVolume(int streamType) {
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.getMasterMaxVolume();
+ } else {
+ return mAudioService.getStreamMaxVolume(streamType);
+ }
+ }
+
+ private int getStreamVolume(int streamType) {
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.getMasterVolume();
+ } else {
+ return mAudioService.getStreamVolume(streamType);
+ }
+ }
+
+ private void setStreamVolume(int streamType, int index, int flags) {
+ if (streamType == STREAM_MASTER) {
+ mAudioService.setMasterVolume(index, flags);
+ } else {
+ mAudioService.setStreamVolume(streamType, index, flags);
+ }
+ }
+
+ private int getLastAudibleStreamVolume(int streamType) {
+ if (streamType == STREAM_MASTER) {
+ return mAudioService.getLastAudibleMasterVolume();
+ } else {
+ return mAudioService.getLastAudibleStreamVolume(streamType);
+ }
}
private void createSliders() {
@@ -301,7 +358,7 @@
sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
- sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(streamType) + plusOne);
+ sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
sc.seekbarView.setOnSeekBarChangeListener(this);
sc.seekbarView.setTag(sc);
mStreamControls.put(streamType, sc);
@@ -342,7 +399,7 @@
/** Update the mute and progress state of a slider */
private void updateSlider(StreamControl sc) {
- sc.seekbarView.setProgress(mAudioManager.getLastAudibleStreamVolume(sc.streamType));
+ sc.seekbarView.setProgress(getLastAudibleStreamVolume(sc.streamType));
final boolean muted = isMuted(sc.streamType);
sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
if (sc.streamType == AudioManager.STREAM_RING && muted
@@ -390,6 +447,23 @@
obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
}
+ public void postMasterVolumeChanged(int flags) {
+ postVolumeChanged(STREAM_MASTER, flags);
+ }
+
+ public void postMuteChanged(int streamType, int flags) {
+ if (hasMessages(MSG_VOLUME_CHANGED)) return;
+ if (mStreamControls == null) {
+ createSliders();
+ }
+ removeMessages(MSG_FREE_RESOURCES);
+ obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
+ }
+
+ public void postMasterMuteChanged(int flags) {
+ postMuteChanged(STREAM_MASTER, flags);
+ }
+
/**
* Override this if you have other work to do when the volume changes (for
* example, vibrating, playing a sound, etc.). Make sure to call through to
@@ -423,10 +497,22 @@
resetTimeout();
}
+ protected void onMuteChanged(int streamType, int flags) {
+
+ if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
+
+ StreamControl sc = mStreamControls.get(streamType);
+ if (sc != null) {
+ sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
+ }
+
+ onVolumeChanged(streamType, flags);
+ }
+
protected void onShowVolumeChanged(int streamType, int flags) {
- int index = mAudioService.isStreamMute(streamType) ?
- mAudioService.getLastAudibleStreamVolume(streamType)
- : mAudioService.getStreamVolume(streamType);
+ int index = isMuted(streamType) ?
+ getLastAudibleStreamVolume(streamType)
+ : getStreamVolume(streamType);
mRingIsSilent = false;
@@ -437,7 +523,7 @@
// get max volume for progress bar
- int max = mAudioService.getStreamMaxVolume(streamType);
+ int max = getStreamMaxVolume(streamType);
switch (streamType) {
@@ -571,6 +657,7 @@
* Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
*/
private ToneGenerator getOrCreateToneGenerator(int streamType) {
+ if (streamType == STREAM_MASTER) return null;
synchronized (this) {
if (mToneGenerators[streamType] == null) {
try {
@@ -620,6 +707,11 @@
break;
}
+ case MSG_MUTE_CHANGED: {
+ onMuteChanged(msg.arg1, msg.arg2);
+ break;
+ }
+
case MSG_FREE_RESOURCES: {
onFreeResources();
break;
@@ -671,8 +763,8 @@
final Object tag = seekBar.getTag();
if (fromUser && tag instanceof StreamControl) {
StreamControl sc = (StreamControl) tag;
- if (mAudioManager.getStreamVolume(sc.streamType) != progress) {
- mAudioManager.setStreamVolume(sc.streamType, progress, 0);
+ if (getStreamVolume(sc.streamType) != progress) {
+ setStreamVolume(sc.streamType, progress, 0);
}
}
resetTimeout();
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6bdc4e8..6dbdedb 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -480,9 +480,19 @@
try {
synchronized (this) {
if (mViews != null) {
- pw.println("View hierarchy:");
-
final int count = mViews.length;
+
+ pw.println("Profile data in ms:");
+
+ for (int i = 0; i < count; i++) {
+ ViewRootImpl root = mRoots[i];
+ HardwareRenderer renderer = root.getView().mAttachInfo.mHardwareRenderer;
+ if (renderer != null) {
+ renderer.dumpGfxInfo(pw);
+ }
+ }
+
+ pw.println("\nView hierarchy:");
int viewsCount = 0;
int displayListsSize = 0;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index bd02d62..89aba3c 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
import android.text.NoCopySpan;
@@ -497,15 +496,14 @@
*/
public boolean sendKeyEvent(KeyEvent event) {
synchronized (mIMM.mH) {
- Handler h = mTargetView != null ? mTargetView.getHandler() : null;
- if (h == null) {
+ ViewRootImpl viewRootImpl = mTargetView != null ? mTargetView.getViewRootImpl() : null;
+ if (viewRootImpl == null) {
if (mIMM.mServedView != null) {
- h = mIMM.mServedView.getHandler();
+ viewRootImpl = mIMM.mServedView.getViewRootImpl();
}
}
- if (h != null) {
- h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
- event));
+ if (viewRootImpl != null) {
+ viewRootImpl.dispatchKeyFromIme(event);
}
}
return false;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0985e14..c51d244 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -336,6 +336,7 @@
}
case MSG_UNBIND: {
final int sequence = msg.arg1;
+ boolean startInput = false;
synchronized (mH) {
if (mBindSequence == sequence) {
if (false) {
@@ -355,7 +356,12 @@
if (mServedView != null && mServedView.isFocused()) {
mServedConnecting = true;
}
+ if (mActive) {
+ startInput = true;
+ }
}
+ }
+ if (startInput) {
startInputInner();
}
return;
@@ -669,11 +675,10 @@
// longer the input target, so it can reset its state. Schedule
// this call on its window's Handler so it will be on the correct
// thread and outside of our lock.
- Handler vh = mServedView.getHandler();
- if (vh != null) {
+ ViewRootImpl viewRootImpl = mServedView.getViewRootImpl();
+ if (viewRootImpl != null) {
// This will result in a call to reportFinishInputConnection() below.
- vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
- mServedInputConnection));
+ viewRootImpl.dispatchFinishInputConnection(mServedInputConnection);
}
}
}
@@ -1124,31 +1129,36 @@
}
static void scheduleCheckFocusLocked(View view) {
- Handler vh = view.getHandler();
- if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) {
- // This will result in a call to checkFocus() below.
- vh.sendMessage(vh.obtainMessage(ViewRootImpl.CHECK_FOCUS));
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.dispatchCheckFocus();
}
}
-
+
/**
* @hide
*/
public void checkFocus() {
+ if (checkFocusNoStartInput()) {
+ startInputInner();
+ }
+ }
+
+ private boolean checkFocusNoStartInput() {
// This is called a lot, so short-circuit before locking.
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
- return;
+ return false;
}
InputConnection ic = null;
synchronized (mH) {
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
- return;
+ return false;
}
if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
+ " next=" + mNextServedView
+ " restart=" + mNextServedNeedsStart);
-
+
mNextServedNeedsStart = false;
if (mNextServedView == null) {
finishInputLocked();
@@ -1156,22 +1166,22 @@
// but no longer do. We should make sure the input method is
// no longer shown, since it serves no purpose.
closeCurrentInput();
- return;
+ return false;
}
-
+
ic = mServedInputConnection;
-
+
mServedView = mNextServedView;
mCurrentTextBoxAttribute = null;
mCompletions = null;
mServedConnecting = true;
}
-
+
if (ic != null) {
ic.finishComposingText();
}
-
- startInputInner();
+
+ return true;
}
void closeCurrentInput() {
@@ -1200,7 +1210,7 @@
focusInLocked(focusedView != null ? focusedView : rootView);
}
- checkFocus();
+ boolean startInput = checkFocusNoStartInput();
synchronized (mH) {
try {
@@ -1212,6 +1222,10 @@
} catch (RemoteException e) {
}
}
+
+ if (startInput) {
+ startInputInner();
+ }
}
/** @hide */
@@ -1593,6 +1607,27 @@
}
/**
+ * Force switch to the next input method and subtype. If there is no IME enabled except
+ * current IME and subtype, do nothing.
+ * @param imeToken Supplies the identifying token given to an input method when it was started,
+ * which allows it to perform this operation on itself.
+ * @param onlyCurrentIme if true, the framework will find the next subtype which
+ * belongs to the current IME
+ * @return true if the current input method and subtype was successfully switched to the next
+ * input method and subtype.
+ */
+ public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
+ synchronized (mH) {
+ try {
+ return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ return false;
+ }
+ }
+ }
+
+ /**
* Set additional input method subtypes. Only a process which shares the same uid with the IME
* can add additional input method subtypes to the IME.
* Please note that a subtype's status is stored in the system.
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 75ee338..95d9275 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -920,7 +920,10 @@
if (PERF_PROBE) {
mWebCoreThreadTime = SystemClock.currentThreadTimeMillis();
mWebCoreIdleTime = 0;
- Network.getInstance(mContext).startTiming();
+ if (!JniUtil.useChromiumHttpStack()) {
+ // Network is only used with the Android HTTP stack.
+ Network.getInstance(mContext).startTiming();
+ }
// un-comment this if PERF_PROBE is true
// Looper.myQueue().setWaitCallback(mIdleCallback);
}
@@ -938,7 +941,10 @@
Log.d("WebCore", "WebCore thread used " +
(SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime)
+ " ms and idled " + mWebCoreIdleTime + " ms");
- Network.getInstance(mContext).stopTiming();
+ if (!JniUtil.useChromiumHttpStack()) {
+ // Network is only used with the Android HTTP stack.
+ Network.getInstance(mContext).stopTiming();
+ }
}
Message msg = obtainMessage(PAGE_FINISHED, url);
sendMessage(msg);
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 9fa5593..c500a76 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -34,7 +34,8 @@
import java.util.TreeSet;
/**
- * CookieManager manages cookies according to RFC2109 spec.
+ * Manages the cookies used by an application's {@link WebView} instances.
+ * Cookies are manipulated according to RFC2109.
*/
public final class CookieManager {
@@ -99,7 +100,7 @@
private boolean mAcceptCookie = true;
- private int pendingCookieOperations = 0;
+ private int mPendingCookieOperations = 0;
/**
* This contains a list of 2nd-level domains that aren't allowed to have
@@ -246,12 +247,12 @@
}
/**
- * Get a singleton CookieManager. If this is called before any
- * {@link WebView} is created or outside of {@link WebView} context, the
- * caller needs to call {@link CookieSyncManager#createInstance(Context)}
+ * Gets the singleton CookieManager instance. If this method is used
+ * before the application instantiates a {@link WebView} instance,
+ * {@link CookieSyncManager#createInstance(Context)} must be called
* first.
*
- * @return CookieManager
+ * @return The singleton CookieManager instance
*/
public static synchronized CookieManager getInstance() {
if (sRef == null) {
@@ -261,8 +262,10 @@
}
/**
- * Control whether cookie is enabled or disabled
- * @param accept TRUE if accept cookie
+ * Sets whether the application's {@link WebView} instances should send and
+ * accept cookies.
+ * @param accept Whether {@link WebView} instances should send and accept
+ * cookies
*/
public synchronized void setAcceptCookie(boolean accept) {
if (JniUtil.useChromiumHttpStack()) {
@@ -274,8 +277,9 @@
}
/**
- * Return whether cookie is enabled
- * @return TRUE if accept cookie
+ * Gets whether the application's {@link WebView} instances send and accept
+ * cookies.
+ * @return True if {@link WebView} instances send and accept cookies
*/
public synchronized boolean acceptCookie() {
if (JniUtil.useChromiumHttpStack()) {
@@ -286,11 +290,13 @@
}
/**
- * Set cookie for a given url. The old cookie with same host/path/name will
- * be removed. The new cookie will be added if it is not expired or it does
- * not have expiration which implies it is session cookie.
- * @param url The url which cookie is set for
- * @param value The value for set-cookie: in http response header
+ * Sets a cookie for the given URL. Any existing cookie with the same host,
+ * path and name will be replaced with the new cookie. The cookie being set
+ * must not have expired and must not be a session cookie, otherwise it
+ * will be ignored.
+ * @param url The URL for which the cookie is set
+ * @param value The cookie as a string, using the format of the
+ * 'Set-Cookie' HTTP response header
*/
public void setCookie(String url, String value) {
if (JniUtil.useChromiumHttpStack()) {
@@ -310,15 +316,13 @@
}
/**
- * Set cookie for a given url. The old cookie with same host/path/name will
- * be removed. The new cookie will be added if it is not expired or it does
- * not have expiration which implies it is session cookie.
- * @param url The url which cookie is set for
- * @param value The value for set-cookie: in http response header
- * @param privateBrowsing cookie jar to use
- * @hide hiding private browsing
+ * See {@link setCookie(String, String)}
+ * @param url The URL for which the cookie is set
+ * @param value The value of the cookie, as a string, using the format of
+ * the 'Set-Cookie' HTTP response header
+ * @param privateBrowsing Whether to use the private browsing cookie jar
*/
- public void setCookie(String url, String value, boolean privateBrowsing) {
+ void setCookie(String url, String value, boolean privateBrowsing) {
if (!JniUtil.useChromiumHttpStack()) {
setCookie(url, value);
return;
@@ -336,15 +340,12 @@
}
/**
- * Set cookie for a given uri. The old cookie with same host/path/name will
- * be removed. The new cookie will be added if it is not expired or it does
- * not have expiration which implies it is session cookie.
- * @param uri The uri which cookie is set for
- * @param value The value for set-cookie: in http response header
- * @hide - hide this because it takes in a parameter of type WebAddress,
- * a system private class.
+ * See {@link setCookie(String, String)}
+ * @param uri The WebAddress for which the cookie is set
+ * @param value The value of the cookie, as a string, using the format of
+ * the 'Set-Cookie' HTTP response header
*/
- public synchronized void setCookie(WebAddress uri, String value) {
+ synchronized void setCookie(WebAddress uri, String value) {
if (JniUtil.useChromiumHttpStack()) {
nativeSetCookie(uri.toString(), value, false);
return;
@@ -450,10 +451,10 @@
}
/**
- * Get cookie(s) for a given url so that it can be set to "cookie:" in http
- * request header.
- * @param url The url needs cookie
- * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
+ * Gets the cookies for the given URL.
+ * @param url The URL for which the cookies are requested
+ * @return value The cookies as a string, using the format of the 'Cookie'
+ * HTTP request header
*/
public String getCookie(String url) {
if (JniUtil.useChromiumHttpStack()) {
@@ -472,12 +473,12 @@
}
/**
- * Get cookie(s) for a given url so that it can be set to "cookie:" in http
- * request header.
- * @param url The url needs cookie
- * @param privateBrowsing cookie jar to use
- * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
- * @hide Private mode is not very well exposed for now
+ * See {@link getCookie(String)}
+ * @param url The URL for which the cookies are requested
+ * @param privateBrowsing Whether to use the private browsing cookie jar
+ * @return value The cookies as a string, using the format of the 'Cookie'
+ * HTTP request header
+ * @hide Used by Browser, no intention to publish.
*/
public String getCookie(String url, boolean privateBrowsing) {
if (!JniUtil.useChromiumHttpStack()) {
@@ -499,10 +500,10 @@
/**
* Get cookie(s) for a given uri so that it can be set to "cookie:" in http
* request header.
- * @param uri The uri needs cookie
- * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
- * @hide - hide this because it has a parameter of type WebAddress, which
- * is a system private class.
+ * @param uri The WebAddress for which the cookies are requested
+ * @return value The cookies as a string, using the format of the 'Cookie'
+ * HTTP request header
+ * @hide Used by RequestHandle, no intention to publish.
*/
public synchronized String getCookie(WebAddress uri) {
if (JniUtil.useChromiumHttpStack()) {
@@ -579,13 +580,12 @@
/**
* Waits for pending operations to completed.
- * {@hide} Too late to release publically.
*/
- public void waitForCookieOperationsToComplete() {
+ void waitForCookieOperationsToComplete() {
// Note that this function is applicable for both the java
// and native http stacks, and works correctly with either.
synchronized (this) {
- while (pendingCookieOperations > 0) {
+ while (mPendingCookieOperations > 0) {
try {
wait();
} catch (InterruptedException e) { }
@@ -594,17 +594,18 @@
}
private synchronized void signalCookieOperationsComplete() {
- pendingCookieOperations--;
- assert pendingCookieOperations > -1;
+ mPendingCookieOperations--;
+ assert mPendingCookieOperations > -1;
notify();
}
private synchronized void signalCookieOperationsStart() {
- pendingCookieOperations++;
+ mPendingCookieOperations++;
}
/**
- * Remove all session cookies, which are cookies without expiration date
+ * Removes all session cookies, which are cookies without an expiration
+ * date.
*/
public void removeSessionCookie() {
signalCookieOperationsStart();
@@ -643,7 +644,7 @@
}
/**
- * Remove all cookies
+ * Removes all cookies.
*/
public void removeAllCookie() {
if (JniUtil.useChromiumHttpStack()) {
@@ -664,7 +665,8 @@
}
/**
- * Return true if there are stored cookies.
+ * Gets whether there are stored cookies.
+ * @return True if there are stored cookies.
*/
public synchronized boolean hasCookies() {
if (JniUtil.useChromiumHttpStack()) {
@@ -675,9 +677,9 @@
}
/**
- * Return true if there are stored cookies.
- * @param privateBrowsing cookie jar to use
- * @hide Hiding private mode
+ * See {@link hasCookies()}.
+ * @param privateBrowsing Whether to use the private browsing cookie jar
+ * @hide Used by Browser, no intention to publish.
*/
public synchronized boolean hasCookies(boolean privateBrowsing) {
if (!JniUtil.useChromiumHttpStack()) {
@@ -688,7 +690,7 @@
}
/**
- * Remove all expired cookies
+ * Removes all expired cookies.
*/
public void removeExpiredCookie() {
if (JniUtil.useChromiumHttpStack()) {
@@ -733,7 +735,10 @@
}
/**
- * Whether cookies are accepted for file scheme URLs.
+ * Gets whether the application's {@link WebView} instances send and accept
+ * cookies for file scheme URLs.
+ * @return True if {@link WebView} instances send and accept cookies for
+ * file scheme URLs
*/
public static boolean allowFileSchemeCookies() {
if (JniUtil.useChromiumHttpStack()) {
@@ -744,13 +749,14 @@
}
/**
- * Sets whether cookies are accepted for file scheme URLs.
- *
- * Use of cookies with file scheme URLs is potentially insecure. Do not use this feature unless
- * you can be sure that no unintentional sharing of cookie data can take place.
+ * Sets whether the application's {@link WebView} instances should send and
+ * accept cookies for file scheme URLs.
+ * Use of cookies with file scheme URLs is potentially insecure. Do not use
+ * this feature unless you can be sure that no unintentional sharing of
+ * cookie data can take place.
* <p>
- * Note that calls to this method will have no effect if made after a WebView or CookieManager
- * instance has been created.
+ * Note that calls to this method will have no effect if made after a
+ * {@link WebView} or CookieManager instance has been created.
*/
public static void setAcceptFileSchemeCookies(boolean accept) {
if (JniUtil.useChromiumHttpStack()) {
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 37e8bc0..4d7ade51 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -985,7 +985,7 @@
* be used. This is just for forward/back navigation to a POST
* URL.
*/
- static boolean willLoadFromCache(String url, long identifier) {
+ private static boolean willLoadFromCache(String url, long identifier) {
assert !JniUtil.useChromiumHttpStack();
boolean inCache =
CacheManager.getCacheFile(url, identifier, null) != null;
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index e786838..24e0d11 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -21,9 +21,9 @@
import java.io.InputStream;
/**
- * A WebResourceResponse is return by
- * {@link WebViewClient#shouldInterceptRequest} and
- * contains the response information for a particular resource.
+ * Encapsulates a resource response. Applications can return an instance of this
+ * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
+ * response when the WebView requests a particular resource.
*/
public class WebResourceResponse {
@@ -50,11 +50,13 @@
private InputStream mInputStream;
/**
- * Construct a response with the given mime type, encoding, and data.
- * @param mimeType The mime type of the data (i.e. text/html).
- * @param encoding The encoding of the bytes read from data.
- * @param data An InputStream for reading custom data. The implementation
- * must implement {@link InputStream#read(byte[])}.
+ * Constructs a resource response with the given MIME type, encoding, and
+ * input stream. Callers must implement
+ * {@link InputStream#read(byte[]) InputStream.read(byte[])} for the input
+ * stream.
+ * @param mimeType The resource response's MIME type, for example text/html
+ * @param encoding The resource response's encoding
+ * @param data The input stream that provides the resource response's data
*/
public WebResourceResponse(String mimeType, String encoding,
InputStream data) {
@@ -64,47 +66,50 @@
}
/**
- * Set the mime type of the response data (i.e. text/html).
- * @param mimeType
+ * Sets the resource response's MIME type, for example text/html.
+ * @param mimeType The resource response's MIME type
*/
public void setMimeType(String mimeType) {
mMimeType = mimeType;
}
/**
- * @see #setMimeType
+ * Gets the resource response's MIME type.
+ * @return The resource response's MIME type
*/
public String getMimeType() {
return mMimeType;
}
/**
- * Set the encoding of the response data (i.e. utf-8). This will be used to
- * decode the raw bytes from the input stream.
- * @param encoding
+ * Sets the resource response's encoding, for example UTF-8. This is used
+ * to decode the data from the input stream.
+ * @param encoding The resource response's encoding
*/
public void setEncoding(String encoding) {
mEncoding = encoding;
}
/**
- * @see #setEncoding
+ * Gets the resource response's encoding.
+ * @return The resource response's encoding
*/
public String getEncoding() {
return mEncoding;
}
/**
- * Set the input stream containing the data for this resource.
- * @param data An InputStream for reading custom data. The implementation
- * must implement {@link InputStream#read(byte[])}.
+ * Sets the input stream that provides the resource respone's data. Callers
+ * must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}.
+ * @param data The input stream that provides the resource response's data
*/
public void setData(InputStream data) {
mInputStream = data;
}
/**
- * @see #setData
+ * Gets the input stream that provides the resource respone's data.
+ * @return The input stream that provides the resource response's data
*/
public InputStream getData() {
return mInputStream;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fbafc64..e0f4f59 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -59,6 +59,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.provider.Settings;
+import android.security.KeyChain;
import android.speech.tts.TextToSpeech;
import android.text.Editable;
import android.text.InputType;
@@ -1303,6 +1304,7 @@
init();
setupPackageListener(context);
setupProxyListener(context);
+ setupTrustStorageListener(context);
updateMultiTouchSupport(context);
if (privateBrowsing) {
@@ -1312,6 +1314,41 @@
mAutoFillData = new WebViewCore.AutoFillData();
}
+ private static class TrustStorageListener extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ handleCertTrustChanged();
+ }
+ }
+ }
+ private static TrustStorageListener sTrustStorageListener;
+
+ /**
+ * Handles update to the trust storage.
+ */
+ private static void handleCertTrustChanged() {
+ // send a message for indicating trust storage change
+ WebViewCore.sendStaticMessage(EventHub.TRUST_STORAGE_UPDATED, null);
+ }
+
+ /*
+ * @param context This method expects this to be a valid context.
+ */
+ private static void setupTrustStorageListener(Context context) {
+ if (sTrustStorageListener != null ) {
+ return;
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
+ sTrustStorageListener = new TrustStorageListener();
+ Intent current =
+ context.getApplicationContext().registerReceiver(sTrustStorageListener, filter);
+ if (current != null) {
+ handleCertTrustChanged();
+ }
+ }
+
private static class ProxyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -4803,7 +4840,9 @@
if (layer == 0 || isPictureAfterFirstLayout) {
mWebViewCore.resumeWebKitDraw();
} else if (queueFull) {
- mWebViewCore.pauseWebKitDraw();
+ // temporarily disable webkit draw throttling
+ // TODO: re-enable
+ // mWebViewCore.pauseWebKitDraw();
}
if (mHTML5VideoViewProxy != null) {
@@ -5553,7 +5592,7 @@
return false;
}
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ if (isEnterActionKey(keyCode)) {
switchOutDrawHistory();
boolean wantsKeyEvents = nativeCursorNodePointer() == 0
|| nativeCursorWantsKeyEvents();
@@ -5702,33 +5741,35 @@
return true; // discard press if copy in progress
}
- // perform the single click
- Rect visibleRect = sendOurVisibleRect();
- // Note that sendOurVisibleRect calls viewToContent, so the
- // coordinates should be in content coordinates.
- if (!nativeCursorIntersects(visibleRect)) {
- return false;
- }
- WebViewCore.CursorData data = cursorData();
- mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
- playSoundEffect(SoundEffectConstants.CLICK);
- if (nativeCursorIsTextInput()) {
- rebuildWebTextView();
- centerKeyPressOnTextField();
- if (inEditingMode()) {
- mWebTextView.setDefaultSelection();
+ if (!sDisableNavcache) {
+ // perform the single click
+ Rect visibleRect = sendOurVisibleRect();
+ // Note that sendOurVisibleRect calls viewToContent, so the
+ // coordinates should be in content coordinates.
+ if (!nativeCursorIntersects(visibleRect)) {
+ return false;
}
- return true;
- }
- clearTextEntry();
- nativeShowCursorTimed();
- if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
- return true;
- }
- if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
- mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
- nativeCursorNodePointer());
- return true;
+ WebViewCore.CursorData data = cursorData();
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
+ playSoundEffect(SoundEffectConstants.CLICK);
+ if (nativeCursorIsTextInput()) {
+ rebuildWebTextView();
+ centerKeyPressOnTextField();
+ if (inEditingMode()) {
+ mWebTextView.setDefaultSelection();
+ }
+ return true;
+ }
+ clearTextEntry();
+ nativeShowCursorTimed();
+ if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+ return true;
+ }
+ if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
+ mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
+ nativeCursorNodePointer());
+ return true;
+ }
}
}
@@ -6111,7 +6152,7 @@
calcOurContentVisibleRectF(mVisibleContentRect);
nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
mGLViewportEmpty ? null : mViewRectViewport,
- mVisibleContentRect);
+ mVisibleContentRect, getScale());
}
/**
@@ -9885,7 +9926,7 @@
private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect,
Rect viewRect, RectF visibleRect, float scale, int extras);
private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect,
- RectF visibleRect);
+ RectF visibleRect, float scale);
private native void nativeExtendSelection(int x, int y);
private native int nativeFindAll(String findLower, String findUpper,
boolean sameAsLastSearch);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8a9c12d..b6c5612 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -26,6 +26,7 @@
import android.media.MediaFile;
import android.net.ProxyProperties;
import android.net.Uri;
+import android.net.http.CertificateChainValidator;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -333,6 +334,15 @@
}
/**
+ * Called by JNI when the focus node changed.
+ */
+ private void focusNodeChanged(WebKitHitTest hitTest) {
+ if (mWebView == null) return;
+ mWebView.mPrivateHandler.obtainMessage(WebView.HIT_TEST_RESULT, hitTest)
+ .sendToTarget();
+ }
+
+ /**
* Called by JNI. Open a file chooser to upload a file.
* @param acceptType The value of the 'accept' attribute of the
* input tag associated with this file picker.
@@ -614,7 +624,6 @@
int x, int y);
private native String nativeRetrieveImageSource(int nativeClass,
int x, int y);
- private native void nativeStopPaintingCaret(int nativeClass);
private native void nativeTouchUp(int nativeClass,
int touchGeneration, int framePtr, int nodePtr, int x, int y);
@@ -767,6 +776,11 @@
Message m = (Message)msg.obj;
m.sendToTarget();
break;
+ case EventHub.TRUST_STORAGE_UPDATED:
+ // post a task to network thread for updating trust manager
+ nativeCertTrustChanged();
+ CertificateChainValidator.handleTrustStorageUpdate();
+ break;
}
}
};
@@ -1125,6 +1139,9 @@
static final int SELECT_WORD_AT = 214;
static final int SELECT_ALL = 215;
+ // for updating state on trust storage change
+ static final int TRUST_STORAGE_UPDATED = 220;
+
// Private handler for WebCore messages.
private Handler mHandler;
// Message queue for containing messages before the WebCore thread is
@@ -1530,9 +1547,6 @@
nativeMoveMouseIfLatest(mNativeClass,
cData.mMoveGeneration,
cData.mFrame, cData.mX, cData.mY);
- if (msg.arg1 == 1) {
- nativeStopPaintingCaret(mNativeClass);
- }
break;
case REQUEST_CURSOR_HREF: {
@@ -3077,4 +3091,6 @@
private native void nativeClearTextSelection(int nativeClass);
private native void nativeSelectWordAt(int nativeClass, int x, int y);
private native void nativeSelectAll(int nativeClass);
+
+ private static native void nativeCertTrustChanged();
}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index ae2d617..369e883 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -258,6 +258,7 @@
// Remember the current zoom density before it gets changed.
final float originalDefault = mDefaultScale;
// set the new default density
+ mDisplayDensity = density;
setDefaultZoomScale(density);
float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e94b1cb..e7bc1e1 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,6 +36,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.LongSparseArray;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.StateSet;
import android.view.ActionMode;
@@ -87,6 +88,8 @@
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
+ private static final String TAG = "AbsListView";
+
/**
* Disables the transcript mode.
*
@@ -263,6 +266,11 @@
private RemoteViewsAdapter mRemoteAdapter;
/**
+ * If mAdapter != null, whenever this is true the adapter has stable IDs.
+ */
+ boolean mAdapterHasStableIds;
+
+ /**
* This flag indicates the a full notify is required when the RemoteViewsAdapter connects
*/
private boolean mDeferNotifyDataSetChanged = false;
@@ -812,7 +820,8 @@
@Override
public void setAdapter(ListAdapter adapter) {
if (adapter != null) {
- if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds() &&
+ mAdapterHasStableIds = mAdapter.hasStableIds();
+ if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds &&
mCheckedIdStates == null) {
mCheckedIdStates = new LongSparseArray<Integer>();
}
@@ -2011,6 +2020,11 @@
isScrap[0] = false;
View scrapView;
+ scrapView = mRecycler.getTransientStateView(position);
+ if (scrapView != null) {
+ return scrapView;
+ }
+
scrapView = mRecycler.getScrapView(position);
View child;
@@ -2021,6 +2035,13 @@
}
child = mAdapter.getView(position, scrapView, this);
+ if (mAdapterHasStableIds) {
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp == null) {
+ lp = (LayoutParams) generateDefaultLayoutParams();
+ }
+ lp.itemId = mAdapter.getItemId(position);
+ }
if (ViewDebug.TRACE_RECYCLER) {
ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW,
@@ -4543,7 +4564,9 @@
if (count > 0) {
detachViewsFromParent(start, count);
+ mRecycler.removeSkippedScrap();
}
+
offsetChildrenTopAndBottom(incrementalDeltaY);
if (down) {
@@ -4853,6 +4876,9 @@
confirmCheckedPositionsById();
}
+ // TODO: In the future we can recycle these views based on stable ID instead.
+ mRecycler.clearTransientStateViews();
+
if (count > 0) {
int newPos;
int selectablePos;
@@ -5735,6 +5761,11 @@
*/
int scrappedFromPosition;
+ /**
+ * The ID the view represents
+ */
+ long itemId = -1;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
@@ -5807,6 +5838,10 @@
private ArrayList<View> mCurrentScrap;
+ private ArrayList<View> mSkippedScrap;
+
+ private SparseArray<View> mTransientStateViews;
+
public void setViewTypeCount(int viewTypeCount) {
if (viewTypeCount < 1) {
throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
@@ -5838,6 +5873,12 @@
}
}
}
+ if (mTransientStateViews != null) {
+ final int count = mTransientStateViews.size();
+ for (int i = 0; i < count; i++) {
+ mTransientStateViews.valueAt(i).forceLayout();
+ }
+ }
}
public boolean shouldRecycleViewType(int viewType) {
@@ -5864,6 +5905,9 @@
}
}
}
+ if (mTransientStateViews != null) {
+ mTransientStateViews.clear();
+ }
}
/**
@@ -5910,6 +5954,28 @@
return null;
}
+ View getTransientStateView(int position) {
+ if (mTransientStateViews == null) {
+ return null;
+ }
+ final int index = mTransientStateViews.indexOfKey(position);
+ if (index < 0) {
+ return null;
+ }
+ final View result = mTransientStateViews.valueAt(index);
+ mTransientStateViews.removeAt(index);
+ return result;
+ }
+
+ /**
+ * Dump any currently saved views with transient state.
+ */
+ void clearTransientStateViews() {
+ if (mTransientStateViews != null) {
+ mTransientStateViews.clear();
+ }
+ }
+
/**
* @return A view from the ScrapViews collection. These are unordered.
*/
@@ -5926,7 +5992,7 @@
}
/**
- * Put a view into the ScapViews list. These views are unordered.
+ * Put a view into the ScrapViews list. These views are unordered.
*
* @param scrap The view to add
*/
@@ -5936,23 +6002,32 @@
return;
}
+ lp.scrappedFromPosition = position;
+
// Don't put header or footer views or views that should be ignored
// into the scrap heap
int viewType = lp.viewType;
- if (!shouldRecycleViewType(viewType)) {
- if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
- removeDetachedView(scrap, false);
+ final boolean scrapHasTransientState = scrap.hasTransientState();
+ if (!shouldRecycleViewType(viewType) || scrapHasTransientState) {
+ if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER || scrapHasTransientState) {
+ if (mSkippedScrap == null) {
+ mSkippedScrap = new ArrayList<View>();
+ }
+ mSkippedScrap.add(scrap);
+ }
+ if (scrapHasTransientState) {
+ if (mTransientStateViews == null) {
+ mTransientStateViews = new SparseArray<View>();
+ }
+ mTransientStateViews.put(position, scrap);
}
return;
}
- lp.scrappedFromPosition = position;
-
+ scrap.dispatchStartTemporaryDetach();
if (mViewTypeCount == 1) {
- scrap.dispatchStartTemporaryDetach();
mCurrentScrap.add(scrap);
} else {
- scrap.dispatchStartTemporaryDetach();
mScrapViews[viewType].add(scrap);
}
@@ -5962,6 +6037,20 @@
}
/**
+ * Finish the removal of any views that skipped the scrap heap.
+ */
+ void removeSkippedScrap() {
+ if (mSkippedScrap == null) {
+ return;
+ }
+ final int count = mSkippedScrap.size();
+ for (int i = 0; i < count; i++) {
+ removeDetachedView(mSkippedScrap.get(i), false);
+ }
+ mSkippedScrap.clear();
+ }
+
+ /**
* Move all views remaining in mActiveViews to mScrapViews.
*/
void scrapActiveViews() {
@@ -5980,11 +6069,19 @@
activeViews[i] = null;
- if (!shouldRecycleViewType(whichScrap)) {
+ final boolean scrapHasTransientState = victim.hasTransientState();
+ if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) {
// Do not move views that should be ignored
- if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
+ if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER ||
+ scrapHasTransientState) {
removeDetachedView(victim, false);
}
+ if (scrapHasTransientState) {
+ if (mTransientStateViews == null) {
+ mTransientStateViews = new SparseArray<View>();
+ }
+ mTransientStateViews.put(mFirstActivePosition + i, victim);
+ }
continue;
}
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index f7a6b272..de11fe9 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1031,7 +1031,9 @@
public void ensureImeVisible(boolean visible) {
mPopup.setInputMethodMode(visible
? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
- showDropDown();
+ if (mPopup.isDropDownAlwaysVisible() || (mFilter != null && enoughToFilter())) {
+ showDropDown();
+ }
}
/**
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 5c7e5a3..dd53325 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -142,12 +142,8 @@
resolvePadding();
}
- /**
- * @hide
- */
@Override
- protected void resolvePadding() {
- super.resolvePadding();
+ public void onResolvePadding(int layoutDirection) {
int newPadding = (mCheckMarkDrawable != null) ?
mCheckMarkWidth + mBasePadding : mBasePadding;
mNeedRequestlayout |= (mPaddingRight != newPadding);
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 326587e..83aa8ba 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -56,7 +56,7 @@
// Time it will take in ms for a pulled glow to decay to partial strength before release
private static final int PULL_DECAY_TIME = 1000;
- private static final float MAX_ALPHA = 0.8f;
+ private static final float MAX_ALPHA = 1.f;
private static final float HELD_EDGE_ALPHA = 0.7f;
private static final float HELD_EDGE_SCALE_Y = 0.5f;
private static final float HELD_GLOW_ALPHA = 0.5f;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 984ec79..fc08cc5 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -127,8 +127,7 @@
*
* GridLayout does not provide support for the principle of <em>weight</em>, as defined in
* {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
- * to configure a GridLayout to distribute excess space in non-trivial proportions between
- * multiple rows or columns.
+ * to configure a GridLayout to distribute excess space between multiple components.
* <p>
* Some common use-cases may nevertheless be accommodated as follows.
* To place equal amounts of space around a component in a cell group;
@@ -209,9 +208,9 @@
static final String TAG = GridLayout.class.getName();
static final boolean DEBUG = false;
- static final int PRF = 1;
static final int MAX_SIZE = 100000;
static final int DEFAULT_CONTAINER_MARGIN = 0;
+ static final int UNINITIALIZED_HASH = 0;
// Defaults
@@ -240,6 +239,7 @@
boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
int alignmentMode = DEFAULT_ALIGNMENT_MODE;
int defaultGap;
+ int lastLayoutParamsHashCode = UNINITIALIZED_HASH;
// Constructors
@@ -566,6 +566,10 @@
return FILL;
case AXIS_SPECIFIED:
return CENTER;
+ case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION):
+ return START;
+ case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION):
+ return END;
default:
return UNDEFINED_ALIGNMENT;
}
@@ -590,7 +594,8 @@
Spec spec = horizontal ? p.columnSpec : p.rowSpec;
Axis axis = horizontal ? horizontalAxis : verticalAxis;
Interval span = spec.span;
- boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
+ boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
+ boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
return getDefaultMargin(c, isAtEdge, horizontal, leading);
}
@@ -663,7 +668,7 @@
int[] maxSizes = new int[count];
for (int i = 0, N = getChildCount(); i < N; i++) {
- LayoutParams lp = getLayoutParams1(getChildAt(i));
+ LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
final Interval majorRange = majorSpec.span;
@@ -708,6 +713,7 @@
minor = minor + minorSpan;
}
+ lastLayoutParamsHashCode = computeLayoutParamsHashCode();
invalidateStructure();
}
@@ -728,8 +734,11 @@
}
}
- private LayoutParams getLayoutParams1(View c) {
- return (LayoutParams) c.getLayoutParams();
+ /** @hide */
+ @Override
+ protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) {
+ super.onSetLayoutParams(child, layoutParams);
+ invalidateStructure();
}
final LayoutParams getLayoutParams(View c) {
@@ -737,7 +746,7 @@
validateLayoutParams();
layoutParamsValid = true;
}
- return getLayoutParams1(c);
+ return (LayoutParams) c.getLayoutParams();
}
@Override
@@ -760,7 +769,12 @@
private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
int dx = getPaddingLeft();
int dy = getPaddingTop();
- graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+ if (isLayoutRtl()) {
+ int width = getWidth();
+ graphics.drawLine(width - dx - x1, dy + y1, width - dx - x2, dy + y2, paint);
+ } else {
+ graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+ }
}
private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
@@ -849,12 +863,29 @@
}
}
- // Measurement
-
- final boolean isGone(View c) {
- return c.getVisibility() == View.GONE;
+ private int computeLayoutParamsHashCode() {
+ int result = 1;
+ for (int i = 0, N = getChildCount(); i < N; i++) {
+ View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) continue;
+ LayoutParams lp = (LayoutParams) c.getLayoutParams();
+ result = 31 * result + lp.hashCode();
+ }
+ return result;
}
+ private void checkForLayoutParamsModification() {
+ int layoutParamsHashCode = computeLayoutParamsHashCode();
+ if (lastLayoutParamsHashCode != UNINITIALIZED_HASH &&
+ lastLayoutParamsHashCode != layoutParamsHashCode) {
+ invalidateStructure();
+ Log.w(TAG, "The fields of some layout parameters were modified in between layout " +
+ "operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
+ }
+ }
+
+ // Measurement
+
private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
int childWidth, int childHeight) {
int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
@@ -867,7 +898,7 @@
private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
if (firstPass) {
measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
@@ -892,6 +923,8 @@
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
+ checkForLayoutParamsModification();
+
/** If we have been called by {@link View#measure(int, int)}, one of width or height
* is likely to have changed. We must invalidate if so. */
invalidateValues();
@@ -922,16 +955,12 @@
resolveSizeAndState(measuredHeight, heightSpec, 0));
}
- private int protect(int alignment) {
- return (alignment == UNDEFINED) ? 0 : alignment;
- }
-
private int getMeasurement(View c, boolean horizontal) {
return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
}
final int getMeasurementIncludingMargin(View c, boolean horizontal) {
- if (isGone(c)) {
+ if (c.getVisibility() == View.GONE) {
return 0;
}
return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
@@ -945,7 +974,7 @@
final Alignment getAlignment(Alignment alignment, boolean horizontal) {
return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
- (horizontal ? LEFT : BASELINE);
+ (horizontal ? START : BASELINE);
}
// Layout container
@@ -964,6 +993,8 @@
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ checkForLayoutParamsModification();
+
int targetWidth = right - left;
int targetHeight = bottom - top;
@@ -980,7 +1011,7 @@
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
Spec columnSpec = lp.columnSpec;
Spec rowSpec = lp.rowSpec;
@@ -1003,42 +1034,31 @@
Alignment hAlign = getAlignment(columnSpec.alignment, true);
Alignment vAlign = getAlignment(rowSpec.alignment, false);
- int dx, dy;
-
- Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i);
- Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i);
+ Bounds boundsX = horizontalAxis.getGroupBounds().getValue(i);
+ Bounds boundsY = verticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
- //noinspection NullableProblems
- int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
- //noinspection NullableProblems
- int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
+ int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
+ int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true));
int leftMargin = getMargin(c, true, true);
int topMargin = getMargin(c, false, true);
int rightMargin = getMargin(c, true, false);
int bottomMargin = getMargin(c, false, false);
- // Same calculation as getMeasurementIncludingMargin()
- int mWidth = leftMargin + pWidth + rightMargin;
- int mHeight = topMargin + pHeight + bottomMargin;
-
// Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, mWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
+ int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin);
+ int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin);
- dx = c2ax + a2vx + leftMargin;
- dy = c2ay + a2vy + topMargin;
+ int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin);
+ int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin);
- cellWidth -= leftMargin + rightMargin;
- cellHeight -= topMargin + bottomMargin;
+ int dx = x1 + gravityOffsetX + alignmentOffsetX;
- int type = PRF;
- int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
- int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type);
+ int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx :
+ targetWidth - width - paddingRight - rightMargin - dx;
+ int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin;
- int cx = paddingLeft + x1 + dx;
- int cy = paddingTop + y1 + dy;
if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
}
@@ -1517,7 +1537,7 @@
int[] margins = leading ? leadingMargins : trailingMargins;
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
Interval span = spec.span;
@@ -1657,7 +1677,7 @@
* each cell group. The fundamental parameters associated with each cell group are
* gathered into their vertical and horizontal components and stored
* in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
- * {@link android.widget.GridLayout.Spec Specs} are immutable structures
+ * {@link GridLayout.Spec Specs} are immutable structures
* and may be shared between the layout parameters of different children.
* <p>
* The row and column specs contain the leading and trailing indices along each axis
@@ -1710,7 +1730,7 @@
* <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
* <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
* <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
- * <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li>
+ * <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
* </ul>
*
* See {@link GridLayout} for a more complete description of the conventions
@@ -1757,12 +1777,28 @@
/**
* The spec that defines the vertical characteristics of the cell group
* described by these layout parameters.
+ * If an assignment is made to this field after a measurement or layout operation
+ * has already taken place, a call to
+ * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
+ * must be made to notify GridLayout of the change. GridLayout is normally able
+ * to detect when code fails to observe this rule, issue a warning and take steps to
+ * compensate for the omission. This facility is implemented on a best effort basis
+ * and should not be relied upon in production code - so it is best to include the above
+ * calls to remove the warnings as soon as it is practical.
*/
public Spec rowSpec = Spec.UNDEFINED;
/**
* The spec that defines the horizontal characteristics of the cell group
* described by these layout parameters.
+ * If an assignment is made to this field after a measurement or layout operation
+ * has already taken place, a call to
+ * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
+ * must be made to notify GridLayout of the change. GridLayout is normally able
+ * to detect when code fails to observe this rule, issue a warning and take steps to
+ * compensate for the omission. This facility is implemented on a best effort basis
+ * and should not be relied upon in production code - so it is best to include the above
+ * calls to remove the warnings as soon as it is practical.
*/
public Spec columnSpec = Spec.UNDEFINED;
@@ -1883,7 +1919,7 @@
/**
* Describes how the child views are positioned. Default is {@code LEFT | BASELINE}.
- * See {@link android.view.Gravity}.
+ * See {@link Gravity}.
*
* @param gravity the new gravity value
*
@@ -1907,6 +1943,26 @@
final void setColumnSpecSpan(Interval span) {
columnSpec = columnSpec.copyWriteSpan(span);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LayoutParams that = (LayoutParams) o;
+
+ if (!columnSpec.equals(that.columnSpec)) return false;
+ if (!rowSpec.equals(that.rowSpec)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = rowSpec.hashCode();
+ result = 31 * result + columnSpec.hashCode();
+ return result;
+ }
}
/*
@@ -2049,7 +2105,7 @@
/*
For each group (with a given alignment) we need to store the amount of space required
before the alignment point and the amount of space required after it. One side of this
- calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
+ calculation is always 0 for START and END alignments but we don't make use of this.
For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
simple optimisations are possible.
@@ -2353,8 +2409,8 @@
* group is specified by the two alignments which act along each axis independently.
* <p>
* The GridLayout class defines the most common alignments used in general layout:
- * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link
- * #BASELINE} and {@link #FILL}.
+ * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START},
+ * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}.
*/
/*
* An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
@@ -2368,6 +2424,8 @@
Alignment() {
}
+ abstract int getGravityOffset(View view, int cellDelta);
+
/**
* Returns an alignment value. In the case of vertical alignments the value
* returned should indicate the distance from the top of the view to the
@@ -2390,12 +2448,9 @@
* @param view the view to which this alignment should be applied
* @param viewSize the measured size of the view
* @param cellSize the size of the cell into which this view will be placed
- * @param measurementType This parameter is currently unused as GridLayout only supports
- * one type of measurement: {@link View#measure(int, int)}.
- *
* @return the aligned size
*/
- int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
+ int getSizeInCell(View view, int viewSize, int cellSize) {
return viewSize;
}
@@ -2405,18 +2460,44 @@
}
static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return UNDEFINED;
+ }
+
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
};
+ /**
+ * Indicates that a view should be aligned with the <em>start</em>
+ * edges of the other views in its cell group.
+ */
private static final Alignment LEADING = new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return 0;
+ }
+
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return 0;
}
};
+ /**
+ * Indicates that a view should be aligned with the <em>end</em>
+ * edges of the other views in its cell group.
+ */
private static final Alignment TRAILING = new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return cellDelta;
+ }
+
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return viewSize;
}
@@ -2435,16 +2516,42 @@
public static final Alignment BOTTOM = TRAILING;
/**
- * Indicates that a view should be aligned with the <em>right</em>
+ * Indicates that a view should be aligned with the <em>start</em>
* edges of the other views in its cell group.
*/
- public static final Alignment RIGHT = TRAILING;
+ public static final Alignment START = LEADING;
+
+ /**
+ * Indicates that a view should be aligned with the <em>end</em>
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment END = TRAILING;
+
+ private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) {
+ return new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta);
+ }
+
+ @Override
+ public int getAlignmentValue(View view, int viewSize) {
+ return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize);
+ }
+ };
+ }
/**
* Indicates that a view should be aligned with the <em>left</em>
* edges of the other views in its cell group.
*/
- public static final Alignment LEFT = LEADING;
+ public static final Alignment LEFT = createSwitchingAlignment(START, END);
+
+ /**
+ * Indicates that a view should be aligned with the <em>right</em>
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment RIGHT = createSwitchingAlignment(END, START);
/**
* Indicates that a view should be <em>centered</em> with the other views in its cell group.
@@ -2452,6 +2559,12 @@
* LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment CENTER = new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return cellDelta >> 1;
+ }
+
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return viewSize >> 1;
}
@@ -2465,10 +2578,13 @@
* @see View#getBaseline()
*/
public static final Alignment BASELINE = new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return 0; // baseline gravity is top
+ }
+
+ @Override
public int getAlignmentValue(View view, int viewSize) {
- if (view == null) {
- return UNDEFINED;
- }
int baseline = view.getBaseline();
return (baseline == -1) ? UNDEFINED : baseline;
}
@@ -2515,12 +2631,18 @@
* {@link LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment FILL = new Alignment() {
+ @Override
+ int getGravityOffset(View view, int cellDelta) {
+ return 0;
+ }
+
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
@Override
- public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
+ public int getSizeInCell(View view, int viewSize, int cellSize) {
return cellSize;
}
};
@@ -2530,6 +2652,5 @@
}
private static final int INFLEXIBLE = 0;
-
private static final int CAN_STRETCH = 2;
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index be2df8e..6bc5a15 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1205,6 +1205,7 @@
// Clear out old views
//removeAllViewsInLayout();
detachAllViewsFromParent();
+ recycleBin.removeSkippedScrap();
switch (mLayoutMode) {
case LAYOUT_SET_SELECTION:
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 67fd059..46c2c07 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1591,6 +1591,7 @@
// Clear out old views
detachAllViewsFromParent();
+ recycleBin.removeSkippedScrap();
switch (mLayoutMode) {
case LAYOUT_SET_SELECTION:
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 570f0f9..909f383 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -426,7 +426,8 @@
}
// A new word has been created across the interval boundaries with this edit.
- // Previous spans (ended on start / started on end) removed, not valid anymore
+ // The previous spans (that ended on start / started on end) are not valid
+ // anymore and must be removed.
if (wordStart < start && wordEnd > start) {
removeSpansAt(editable, start, spellCheckSpans);
removeSpansAt(editable, start, suggestionSpans);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 99349b0..f66da29 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3472,6 +3472,9 @@
if (mText.length() == 0) {
invalidate();
}
+
+ // Invalidate display list if hint will be used
+ if (mText.length() == 0 && mHint != null) mTextDisplayListIsValid = false;
}
/**
@@ -3804,21 +3807,21 @@
}
}
- Handler h = getHandler();
- if (h != null) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
long eventTime = SystemClock.uptimeMillis();
- h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+ viewRootImpl.dispatchKeyFromIme(
new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
- | KeyEvent.FLAG_EDITOR_ACTION)));
- h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+ | KeyEvent.FLAG_EDITOR_ACTION));
+ viewRootImpl.dispatchKeyFromIme(
new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
- | KeyEvent.FLAG_EDITOR_ACTION)));
+ | KeyEvent.FLAG_EDITOR_ACTION));
}
}
@@ -4634,19 +4637,25 @@
// Alpha is supported if and only if the drawing can be done in one pass.
// TODO text with spans with a background color currently do not respect this alpha.
if (getBackground() == null) {
- mCurrentAlpha = alpha;
- final Drawables dr = mDrawables;
- if (dr != null) {
- if (dr.mDrawableLeft != null) dr.mDrawableLeft.mutate().setAlpha(alpha);
- if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha);
- if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha);
- if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha);
- if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha);
- if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha);
+ if (mCurrentAlpha != alpha) {
+ mCurrentAlpha = alpha;
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ if (dr.mDrawableLeft != null) dr.mDrawableLeft.mutate().setAlpha(alpha);
+ if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha);
+ if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha);
+ if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha);
+ if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha);
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha);
+ }
+ mTextDisplayListIsValid = false;
}
return true;
}
+ if (mCurrentAlpha != 255) {
+ mTextDisplayListIsValid = false;
+ }
mCurrentAlpha = 255;
return false;
}
@@ -5013,15 +5022,19 @@
hardwareCanvas.setViewport(width, height);
// The dirty rect should always be null for a display list
hardwareCanvas.onPreDraw(null);
+ hardwareCanvas.translate(-mScrollX, -mScrollY);
layout.draw(hardwareCanvas, highlight, mHighlightPaint, cursorOffsetVertical);
+ hardwareCanvas.translate(mScrollX, mScrollY);
} finally {
hardwareCanvas.onPostDraw();
mTextDisplayList.end();
mTextDisplayListIsValid = true;
}
}
- ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList,
- mScrollX + width, mScrollY + height, null);
+ canvas.translate(mScrollX, mScrollY);
+ ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, width, height, null,
+ DisplayList.FLAG_CLIP_CHILDREN);
+ canvas.translate(-mScrollX, -mScrollY);
} else {
layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
}
@@ -11398,7 +11411,7 @@
}
@Override
- protected void resolveTextDirection() {
+ public void onResolveTextDirection() {
if (hasPasswordTransformationMethod()) {
mTextDir = TextDirectionHeuristics.LOCALE;
return;
@@ -11407,9 +11420,6 @@
// Always need to resolve layout direction first
final boolean defaultIsRtl = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL);
- // Then resolve text direction on the parent
- super.resolveTextDirection();
-
// Now, we can select the heuristic
int textDir = getResolvedTextDirection();
switch (textDir) {
@@ -11438,7 +11448,6 @@
* drawables depending on the layout direction.
*
* A call to the super method will be required from the subclasses implementation.
- *
*/
protected void resolveDrawables() {
// No need to resolve twice
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index f3d891d..02dc27b 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -501,7 +501,7 @@
} else {
- ViewRootImpl viewRoot = getOwnerViewRootImpl();
+ ViewRootImpl viewRoot = mOwnerView.getViewRootImpl();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
}
@@ -526,20 +526,6 @@
}
}
- private ViewRootImpl getOwnerViewRootImpl() {
- View rootViewOfOwner = mOwnerView.getRootView();
- if (rootViewOfOwner == null) {
- return null;
- }
-
- ViewParent parentOfRootView = rootViewOfOwner.getParent();
- if (parentOfRootView instanceof ViewRootImpl) {
- return (ViewRootImpl) parentOfRootView;
- } else {
- return null;
- }
- }
-
/**
* @hide The ZoomButtonsController implements the OnTouchListener, but this
* does not need to be shown in its public API.
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 683aca5..5d80b79 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -67,6 +67,7 @@
InputMethodSubtype getCurrentInputMethodSubtype();
boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
boolean switchToLastInputMethod(in IBinder token);
+ boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
boolean setInputMethodEnabled(String id, boolean enabled);
oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 6893ffb..acc3c1c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -857,11 +857,6 @@
* @return Whether biometric weak lock is installed and that the front facing camera exists
*/
public boolean isBiometricWeakInstalled() {
- // Check that the system flag was set
- if (!OPTION_ENABLE_FACELOCK.equals(getString(LOCKSCREEN_OPTIONS))) {
- return false;
- }
-
// Check that it's installed
PackageManager pm = mContext.getPackageManager();
try {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 2e7810f..26518eb 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -147,7 +147,7 @@
}
private void sendKeyEventsToTarget(int character) {
- Handler handler = mTargetView.getHandler();
+ ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents(
new char[] { (char) character });
if (events != null) {
@@ -156,22 +156,22 @@
KeyEvent event = events[i];
event = KeyEvent.changeFlags(event, event.getFlags()
| KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
- handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY, event));
+ viewRootImpl.dispatchKey(event);
}
}
}
public void sendDownUpKeyEvents(int keyEventCode) {
long eventTime = SystemClock.uptimeMillis();
- Handler handler = mTargetView.getHandler();
- handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+ ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
+ viewRootImpl.dispatchKeyFromIme(
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
- handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
+ viewRootImpl.dispatchKeyFromIme(
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
}
public void onKey(int primaryCode, int[] keyCodes) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 39b84bb..78e8df3 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -126,6 +126,7 @@
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
+ android_hardware_SerialPort.cpp \
android_hardware_UsbDevice.cpp \
android_hardware_UsbDeviceConnection.cpp \
android_hardware_UsbRequest.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8a3063f..3067e75 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -76,6 +76,7 @@
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
+extern int register_android_hardware_SerialPort(JNIEnv *env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1157,6 +1158,7 @@
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_SensorManager),
+ REG_JNI(register_android_hardware_SerialPort),
REG_JNI(register_android_hardware_UsbDevice),
REG_JNI(register_android_hardware_UsbDeviceConnection),
REG_JNI(register_android_hardware_UsbRequest),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index ea35006..4b64bf3 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -15,8 +15,8 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
-#include <utils/Asset.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/ResourceTypes.h>
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/stat.h>
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index d437929..682877a 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -37,7 +37,7 @@
#include <binder/Parcel.h>
#include <jni.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
#include <sys/stat.h>
#if 0
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index c1acaa3..4f64ff8 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -5,8 +5,8 @@
#include "SkUtils.h"
#include "CreateJavaOutputStreamAdaptor.h"
-#include <utils/Asset.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/ResourceTypes.h>
#include <netinet/in.h>
#if 0
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index f3b28a9..684b1c1 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "9patch"
#define LOG_NDEBUG 1
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/Log.h>
#include "SkCanvas.h"
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index 1d0bb506..ff0eb45 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "NinePatch"
#define LOG_NDEBUG 1
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/Log.h>
#include "SkBitmap.h"
diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h
index 8567e23..207536c 100644
--- a/core/jni/android/graphics/NinePatchPeeker.h
+++ b/core/jni/android/graphics/NinePatchPeeker.h
@@ -18,7 +18,7 @@
#define NinePatchPeeker_h
#include "SkImageDecoder.h"
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
using namespace android;
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index b25598a..7f4c37b 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -2,10 +2,10 @@
#include <android_runtime/AndroidRuntime.h>
#include "GraphicsJNI.h"
-#include <android_runtime/android_util_AssetManager.h>
#include "SkStream.h"
#include "SkTypeface.h"
-#include <utils/AssetManager.h>
+#include <android_runtime/android_util_AssetManager.h>
+#include <androidfw/AssetManager.h>
using namespace android;
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index 9a7a697..75ceaa2 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -22,7 +22,7 @@
#include "android_util_Binder.h"
#include <jni.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
namespace android {
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index ac4fe5b..4b3324b 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -27,7 +27,7 @@
#include <android_runtime/android_util_AssetManager.h>
#include <surfaceflinger/Surface.h>
#include <ui/egl/android_natives.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include <utils/Looper.h>
#include "JNIHelp.h"
@@ -130,21 +130,21 @@
void AInputQueue::attachLooper(ALooper* looper, int ident,
ALooper_callbackFunc callback, void* data) {
mLooper = static_cast<android::Looper*>(looper);
- mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
+ mLooper->addFd(mConsumer.getChannel()->getFd(),
ident, ALOOPER_EVENT_INPUT, callback, data);
mLooper->addFd(mDispatchKeyRead,
ident, ALOOPER_EVENT_INPUT, callback, data);
}
void AInputQueue::detachLooper() {
- mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
+ mLooper->removeFd(mConsumer.getChannel()->getFd());
mLooper->removeFd(mDispatchKeyRead);
}
int32_t AInputQueue::hasEvents() {
struct pollfd pfd[2];
- pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
+ pfd[0].fd = mConsumer.getChannel()->getFd();
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = mDispatchKeyRead;
@@ -172,7 +172,7 @@
in_flight_event inflight;
inflight.event = kevent;
inflight.seq = -1;
- inflight.doFinish = false;
+ inflight.finishSeq = 0;
mInFlightEvents.push(inflight);
}
if (mFinishPreDispatches.size() > 0) {
@@ -200,27 +200,22 @@
return 0;
}
}
-
- int32_t res = mConsumer.receiveDispatchSignal();
- if (res != android::OK) {
- ALOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
- mConsumer.getChannel()->getName().string(), res);
- return -1;
- }
+ uint32_t consumerSeq;
InputEvent* myEvent = NULL;
- res = mConsumer.consume(this, &myEvent);
+ status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent);
if (res != android::OK) {
- ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
- mConsumer.getChannel()->getName().string(), res);
- mConsumer.sendFinishedSignal(false);
+ if (res != android::WOULD_BLOCK) {
+ ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
+ mConsumer.getChannel()->getName().string(), res);
+ }
return -1;
}
in_flight_event inflight;
inflight.event = myEvent;
inflight.seq = -1;
- inflight.doFinish = true;
+ inflight.finishSeq = consumerSeq;
mInFlightEvents.push(inflight);
*outEvent = myEvent;
@@ -262,8 +257,8 @@
for (size_t i=0; i<N; i++) {
const in_flight_event& inflight(mInFlightEvents[i]);
if (inflight.event == event) {
- if (inflight.doFinish) {
- int32_t res = mConsumer.sendFinishedSignal(handled);
+ if (inflight.finishSeq) {
+ status_t res = mConsumer.sendFinishedSignal(inflight.finishSeq, handled);
if (res != android::OK) {
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
mConsumer.getChannel()->getName().string(), res);
@@ -481,11 +476,6 @@
android_view_InputChannel_getInputChannel(env, _channel);
if (ic != NULL) {
nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
- if (nativeInputQueue->getConsumer().initialize() != android::OK) {
- delete nativeInputQueue;
- nativeInputQueue = NULL;
- return UNKNOWN_ERROR;
- }
} else {
return UNKNOWN_ERROR;
}
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index 066a23e..2ca645a 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -21,7 +21,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
#include <string.h>
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 2fb0076..25b0007 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -20,7 +20,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
namespace android
{
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index f4b5dca..e8f0fb8 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -20,7 +20,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
namespace android
{
@@ -52,7 +52,6 @@
if (keyUTF == NULL) {
return -1;
}
-
err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
env->ReleaseStringUTFChars(key, keyUTF);
diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
index 0dfd8db..bb3a751 100644
--- a/core/jni/android_backup_FileBackupHelperBase.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -20,7 +20,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
namespace android
{
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
old mode 100755
new mode 100644
diff --git a/core/jni/android_bluetooth_c.c b/core/jni/android_bluetooth_c.c
old mode 100755
new mode 100644
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 8837538..5d51ee2 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -18,7 +18,7 @@
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/ObbFile.h>
+#include <androidfw/ObbFile.h>
#include "jni.h"
#include "JNIHelp.h"
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
new file mode 100644
index 0000000..7f40a5c
--- /dev/null
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SerialPortJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+static void
+android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)
+{
+ switch (speed) {
+ case 50:
+ speed = B50;
+ break;
+ case 75:
+ speed = B75;
+ break;
+ case 110:
+ speed = B110;
+ break;
+ case 134:
+ speed = B134;
+ break;
+ case 150:
+ speed = B150;
+ break;
+ case 200:
+ speed = B200;
+ break;
+ case 300:
+ speed = B300;
+ break;
+ case 600:
+ speed = B600;
+ break;
+ case 1200:
+ speed = B1200;
+ break;
+ case 1800:
+ speed = B1800;
+ break;
+ case 2400:
+ speed = B2400;
+ break;
+ case 4800:
+ speed = B4800;
+ break;
+ case 9600:
+ speed = B9600;
+ break;
+ case 19200:
+ speed = B19200;
+ break;
+ case 38400:
+ speed = B38400;
+ break;
+ case 57600:
+ speed = B57600;
+ break;
+ case 115200:
+ speed = B115200;
+ break;
+ case 230400:
+ speed = B230400;
+ break;
+ case 460800:
+ speed = B460800;
+ break;
+ case 500000:
+ speed = B500000;
+ break;
+ case 576000:
+ speed = B576000;
+ break;
+ case 921600:
+ speed = B921600;
+ break;
+ case 1000000:
+ speed = B1000000;
+ break;
+ case 1152000:
+ speed = B1152000;
+ break;
+ case 1500000:
+ speed = B1500000;
+ break;
+ case 2000000:
+ speed = B2000000;
+ break;
+ case 2500000:
+ speed = B2500000;
+ break;
+ case 3000000:
+ speed = B3000000;
+ break;
+ case 3500000:
+ speed = B3500000;
+ break;
+ case 4000000:
+ speed = B4000000;
+ break;
+ default:
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Unsupported serial port speed");
+ return;
+ }
+
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
+ fd = dup(fd);
+ if (fd < 0) {
+ jniThrowException(env, "java/io/IOException", "Could not open serial port");
+ return;
+ }
+ env->SetIntField(thiz, field_context, fd);
+
+ struct termios tio;
+ if (tcgetattr(fd, &tio))
+ memset(&tio, 0, sizeof(tio));
+
+ tio.c_cflag = speed | CS8 | CLOCAL | CREAD;
+ // Disable output processing, including messing with end-of-line characters.
+ tio.c_oflag &= ~OPOST;
+ tio.c_iflag = IGNPAR;
+ tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */
+ /* no timeout but request at least one character per read */
+ tio.c_cc[VTIME] = 0;
+ tio.c_cc[VMIN] = 1;
+ tcsetattr(fd, TCSANOW, &tio);
+ tcflush(fd, TCIFLUSH);
+}
+
+static void
+android_hardware_SerialPort_close(JNIEnv *env, jobject thiz)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ close(fd);
+ env->SetIntField(thiz, field_context, -1);
+}
+
+static jint
+android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ jbyte* buf = (jbyte *)malloc(length);
+ if (!buf) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return -1;
+ }
+
+ int ret = read(fd, buf, length);
+ if (ret > 0) {
+ // copy data from native buffer to Java buffer
+ env->SetByteArrayRegion(buffer, 0, ret, buf);
+ }
+
+ free(buf);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+ return ret;
+}
+
+static jint
+android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+
+ jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
+ if (!buf) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
+ return -1;
+ }
+
+ int ret = read(fd, buf, length);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+ return ret;
+}
+
+static void
+android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ jbyte* buf = (jbyte *)malloc(length);
+ if (!buf) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+ env->GetByteArrayRegion(buffer, 0, length, buf);
+
+ jint ret = write(fd, buf, length);
+ free(buf);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+}
+
+static void
+android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
+{
+ int fd = env->GetIntField(thiz, field_context);
+
+ jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
+ if (!buf) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
+ return;
+ }
+ int ret = write(fd, buf, length);
+ if (ret < 0)
+ jniThrowException(env, "java/io/IOException", NULL);
+}
+
+static void
+android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz)
+{
+ int fd = env->GetIntField(thiz, field_context);
+ tcsendbreak(fd, 0);
+}
+
+static JNINativeMethod method_table[] = {
+ {"native_open", "(Ljava/io/FileDescriptor;I)V",
+ (void *)android_hardware_SerialPort_open},
+ {"native_close", "()V", (void *)android_hardware_SerialPort_close},
+ {"native_read_array", "([BI)I",
+ (void *)android_hardware_SerialPort_read_array},
+ {"native_read_direct", "(Ljava/nio/ByteBuffer;I)I",
+ (void *)android_hardware_SerialPort_read_direct},
+ {"native_write_array", "([BI)V",
+ (void *)android_hardware_SerialPort_write_array},
+ {"native_write_direct", "(Ljava/nio/ByteBuffer;I)V",
+ (void *)android_hardware_SerialPort_write_direct},
+ {"native_send_break", "()V", (void *)android_hardware_SerialPort_send_break},
+};
+
+int register_android_hardware_SerialPort(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/hardware/SerialPort");
+ if (clazz == NULL) {
+ ALOGE("Can't find android/hardware/SerialPort");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ ALOGE("Can't find SerialPort.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort",
+ method_table, NELEM(method_table));
+}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 547607e..68a8de8 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -220,7 +220,7 @@
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
goto native_init_failure;
}
- // read the audio session ID back from AudioTrack in case a new session was created during set()
+ // read the audio session ID back from AudioRecord in case a new session was created during set()
nSession[0] = lpRecorder->getSessionId();
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6b4c5e8..ee5eb7e 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+/*
**
** Copyright 2006, The Android Open Source Project
**
@@ -204,6 +204,38 @@
return index;
}
+static int
+android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
+{
+ return check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
+}
+
+static jfloat
+android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
+{
+ float value;
+ if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
+ value = -1.0;
+ }
+ return value;
+}
+
+static int
+android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
+{
+ return check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
+}
+
+static jfloat
+android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
+{
+ bool mute;
+ if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
+ mute = false;
+ }
+ return mute;
+}
+
static jint
android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
{
@@ -226,6 +258,10 @@
{"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
{"setStreamVolumeIndex","(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
{"getStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
+ {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
+ {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
+ {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
+ {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
{"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
};
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 26e82aa..544b4c0 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+/*
**
** Copyright 2008, The Android Open Source Project
**
@@ -39,7 +39,7 @@
static fields_t fields;
static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType, jint durationMs) {
- ALOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_startTone: %x", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
@@ -52,12 +52,12 @@
}
static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) {
- ALOGV("android_media_ToneGenerator_stopTone: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_stopTone: %x", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
- ALOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+ ALOGV("ToneGenerator lpToneGen: %x", (unsigned int)lpToneGen);
if (lpToneGen == NULL) {
jniThrowRuntimeException(env, "Method called after release()");
return;
@@ -68,13 +68,11 @@
static void android_media_ToneGenerator_release(JNIEnv *env, jobject thiz) {
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
- ALOGV("android_media_ToneGenerator_release lpToneGen: %x\n", (int)lpToneGen);
+ ALOGV("android_media_ToneGenerator_release lpToneGen: %x", (int)lpToneGen);
env->SetIntField(thiz, fields.context, 0);
- if (lpToneGen) {
- delete lpToneGen;
- }
+ delete lpToneGen;
}
static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
@@ -83,17 +81,17 @@
env->SetIntField(thiz, fields.context, 0);
- ALOGV("android_media_ToneGenerator_native_setup jobject: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_native_setup jobject: %x", (int)thiz);
if (lpToneGen == NULL) {
- ALOGE("ToneGenerator creation failed \n");
+ ALOGE("ToneGenerator creation failed");
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
- ALOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+ ALOGV("ToneGenerator lpToneGen: %x", (unsigned int)lpToneGen);
if (!lpToneGen->isInited()) {
- ALOGE("ToneGenerator init failed \n");
+ ALOGE("ToneGenerator init failed");
jniThrowRuntimeException(env, "Init failed");
return;
}
@@ -101,18 +99,18 @@
// Stow our new C++ ToneGenerator in an opaque field in the Java object.
env->SetIntField(thiz, fields.context, (int)lpToneGen);
- ALOGV("ToneGenerator fields.context: %x\n", env->GetIntField(thiz, fields.context));
+ ALOGV("ToneGenerator fields.context: %x", env->GetIntField(thiz, fields.context));
}
static void android_media_ToneGenerator_native_finalize(JNIEnv *env,
jobject thiz) {
- ALOGV("android_media_ToneGenerator_native_finalize jobject: %x\n", (int)thiz);
+ ALOGV("android_media_ToneGenerator_native_finalize jobject: %x", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
fields.context);
- if (lpToneGen) {
- ALOGV("delete lpToneGen: %x\n", (int)lpToneGen);
+ if (lpToneGen != NULL) {
+ ALOGV("delete lpToneGen: %p", lpToneGen);
delete lpToneGen;
}
}
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 2ac3ca8..c5ff16e 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -116,14 +116,9 @@
return (jboolean)(::wifi_unload_driver() == 0);
}
-static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject)
+static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
{
- return (jboolean)(::wifi_start_supplicant() == 0);
-}
-
-static jboolean android_net_wifi_startP2pSupplicant(JNIEnv* env, jobject)
-{
- return (jboolean)(::wifi_start_p2p_supplicant() == 0);
+ return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0);
}
static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
@@ -207,8 +202,7 @@
{ "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
{ "isDriverLoaded", "()Z", (void *)android_net_wifi_isDriverLoaded },
{ "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver },
- { "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant },
- { "startP2pSupplicant", "()Z", (void *)android_net_wifi_startP2pSupplicant },
+ { "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant },
{ "killSupplicant", "()Z", (void *)android_net_wifi_killSupplicant },
{ "connectToSupplicant", "(Ljava/lang/String;)Z",
(void *)android_net_wifi_connectToSupplicant },
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index dc16990..48845f6 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -15,13 +15,18 @@
** limitations under the License.
*/
+#define LOG_TAG "Power-JNI"
+
#include "JNIHelp.h"
#include "jni.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
+#include <hardware/power.h>
#include <hardware_legacy/power.h>
#include <cutils/android_reboot.h>
+static struct power_module *sPowerModule;
+
namespace android
{
@@ -65,7 +70,9 @@
static int
setScreenState(JNIEnv *env, jobject clazz, jboolean on)
{
- return set_screen_state(on);
+ if (sPowerModule)
+ sPowerModule->setInteractive(sPowerModule, on);
+ return 0;
}
static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
@@ -85,12 +92,26 @@
jniThrowIOException(env, errno);
}
+static int android_os_Power_init(JNIEnv *env, jobject clazz)
+{
+ status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&sPowerModule);
+ ALOGE_IF(err, "couldn't load %s module (%s)",
+ POWER_HARDWARE_MODULE_ID, strerror(-err));
+
+ if (!err)
+ sPowerModule->init(sPowerModule);
+
+ return err;
+}
+
static JNINativeMethod method_table[] = {
{ "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },
{ "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },
{ "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
{ "setScreenState", "(Z)I", (void*)setScreenState },
{ "shutdown", "()V", (void*)android_os_Power_shutdown },
+ { "powerInitNative", "()I", (void*)android_os_Power_init },
{ "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
};
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 9292fc0..8a69ba4 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -164,7 +164,6 @@
ALOGE("%s: out of memory!", __FUNCTION__);
return;
}
- memset(nat, 0, sizeof(native_data_t));
pthread_mutex_init(&(nat->thread_mutex), NULL);
@@ -722,24 +721,20 @@
return JNI_FALSE;
}
- nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
- DEFAULT_INITIAL_POLLFD_COUNT);
+ nat->pollData = (struct pollfd *)calloc(
+ DEFAULT_INITIAL_POLLFD_COUNT, sizeof(struct pollfd));
if (!nat->pollData) {
ALOGE("out of memory error starting EventLoop!");
goto done;
}
- nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
- DEFAULT_INITIAL_POLLFD_COUNT);
+ nat->watchData = (DBusWatch **)calloc(
+ DEFAULT_INITIAL_POLLFD_COUNT, sizeof(DBusWatch *));
if (!nat->watchData) {
ALOGE("out of memory error starting EventLoop!");
goto done;
}
- memset(nat->pollData, 0, sizeof(struct pollfd) *
- DEFAULT_INITIAL_POLLFD_COUNT);
- memset(nat->watchData, 0, sizeof(DBusWatch *) *
- DEFAULT_INITIAL_POLLFD_COUNT);
nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
nat->pollMemberCount = 1;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 17130af..7146667 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -31,9 +31,9 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <utils/Asset.h>
-#include <utils/AssetManager.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
#include <stdio.h>
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index 958ddb2..28746ce 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -23,7 +23,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <stdio.h>
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 45728db..ad6033b 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -19,12 +19,11 @@
#include "jni.h"
#include "JNIHelp.h"
-#include <utils/misc.h>
#include <android_runtime/AndroidRuntime.h>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/Log.h>
-
-#include <utils/ResourceTypes.h>
+#include <utils/misc.h>
#include <stdio.h>
diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp
index 366a52e..f076cc8 100644
--- a/core/jni/android_view_Display.cpp
+++ b/core/jni/android_view_Display.cpp
@@ -28,6 +28,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <utils/Log.h>
+#include <cutils/properties.h>
// ----------------------------------------------------------------------------
@@ -44,6 +45,7 @@
jfieldID ydpi;
};
static offsets_t offsets;
+static bool headless = false;
// ----------------------------------------------------------------------------
@@ -51,10 +53,19 @@
JNIEnv* env, jobject clazz, jint dpy)
{
DisplayInfo info;
- status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
- if (err < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
+ if (headless) {
+ // initialize dummy display with reasonable values
+ info.pixelFormatInfo.format = 1; // RGB_8888
+ info.fps = 60;
+ info.density = 160;
+ info.xdpi = 160;
+ info.ydpi = 160;
+ } else {
+ status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
+ if (err < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
}
env->SetIntField(clazz, offsets.pixelFormat,info.pixelFormatInfo.format);
env->SetFloatField(clazz, offsets.fps, info.fps);
@@ -66,6 +77,7 @@
static jint android_view_Display_getRawWidthNative(
JNIEnv* env, jobject clazz)
{
+ if (headless) return 640;
DisplayID dpy = env->GetIntField(clazz, offsets.display);
return SurfaceComposerClient::getDisplayWidth(dpy);
}
@@ -73,6 +85,7 @@
static jint android_view_Display_getRawHeightNative(
JNIEnv* env, jobject clazz)
{
+ if (headless) return 480;
DisplayID dpy = env->GetIntField(clazz, offsets.display);
return SurfaceComposerClient::getDisplayHeight(dpy);
}
@@ -80,6 +93,7 @@
static jint android_view_Display_getOrientation(
JNIEnv* env, jobject clazz)
{
+ if (headless) return 0; // Surface.ROTATION_0
DisplayID dpy = env->GetIntField(clazz, offsets.display);
return SurfaceComposerClient::getDisplayOrientation(dpy);
}
@@ -87,6 +101,7 @@
static jint android_view_Display_getDisplayCount(
JNIEnv* env, jclass clazz)
{
+ if (headless) return 1;
return SurfaceComposerClient::getNumberOfDisplays();
}
@@ -113,6 +128,12 @@
void nativeClassInit(JNIEnv* env, jclass clazz)
{
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.config.headless", value, "0");
+ if (strcmp(value, "1") == 0)
+ headless = true;
+
offsets.display = env->GetFieldID(clazz, "mDisplay", "I");
offsets.pixelFormat = env->GetFieldID(clazz, "mPixelFormat", "I");
offsets.fps = env->GetFieldID(clazz, "mRefreshRate", "F");
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 25397b5..8a1c4a9 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -59,21 +59,20 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
- bool mFdCallbackRegistered;
};
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<Looper>& looper) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mLooper(looper), mWaitingForVsync(false), mFdCallbackRegistered(false) {
+ mLooper(looper), mWaitingForVsync(false) {
ALOGV("receiver %p ~ Initializing input event receiver.", this);
}
NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
ALOGV("receiver %p ~ Disposing display event receiver.", this);
- if (mFdCallbackRegistered) {
+ if (!mReceiver.initCheck()) {
mLooper->removeFd(mReceiver.getFd());
}
@@ -88,6 +87,11 @@
return result;
}
+ int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
+ handleReceiveCallback, this);
+ if (rc < 0) {
+ return UNKNOWN_ERROR;
+ }
return OK;
}
@@ -113,15 +117,6 @@
return status;
}
- if (!mFdCallbackRegistered) {
- int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
- handleReceiveCallback, this);
- if (rc < 0) {
- return UNKNOWN_ERROR;
- }
- mFdCallbackRegistered = true;
- }
-
mWaitingForVsync = true;
}
return OK;
@@ -133,7 +128,6 @@
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x", events);
- r->mFdCallbackRegistered = false;
return 0; // remove the callback
}
@@ -150,7 +144,7 @@
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
while ((n = r->mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- ALOGV("receiver %p ~ Read %d events.", this, int(n));
+ ALOGV("receiver %p ~ Read %d events.", data, int(n));
while (n-- > 0) {
if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
vsyncTimestamp = buf[n].header.timestamp;
@@ -161,20 +155,20 @@
}
if (vsyncTimestamp < 0) {
- ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
+ ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", data);
return 1; // keep the callback, did not obtain a vsync pulse
}
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
- this, vsyncTimestamp, vsyncCount);
+ data, vsyncTimestamp, vsyncCount);
r->mWaitingForVsync = false;
JNIEnv* env = AndroidRuntime::getJNIEnv();
- ALOGV("receiver %p ~ Invoking vsync handler.", this);
+ ALOGV("receiver %p ~ Invoking vsync handler.", data);
env->CallVoidMethod(r->mReceiverObjGlobal,
gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
- ALOGV("receiver %p ~ Returned from vsync handler.", this);
+ ALOGV("receiver %p ~ Returned from vsync handler.", data);
if (env->ExceptionCheck()) {
ALOGE("An exception occurred while dispatching a vsync event.");
@@ -182,13 +176,7 @@
env->ExceptionClear();
}
- // Check whether dispatchVsync called scheduleVsync reentrantly and set mWaitingForVsync.
- // If so, keep the callback, otherwise remove it.
- if (r->mWaitingForVsync) {
- return 1; // keep the callback
- }
- r->mFdCallbackRegistered = false;
- return 0; // remove the callback
+ return 1; // keep the callback
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e19bb38..cdce4f9 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -24,7 +24,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
#include <cutils/properties.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <gui/SurfaceTexture.h>
@@ -652,9 +652,9 @@
static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
- jint width, jint height, jobject dirty) {
+ jint width, jint height, jobject dirty, jint flags) {
android::uirenderer::Rect bounds;
- bool redraw = renderer->drawDisplayList(displayList, width, height, bounds);
+ bool redraw = renderer->drawDisplayList(displayList, width, height, bounds, flags);
if (redraw && dirty != NULL) {
env->CallVoidMethod(dirty, gRectClassInfo.set,
int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
@@ -901,7 +901,7 @@
{ "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize },
{ "nSetDisplayListName", "(ILjava/lang/String;)V",
(void*) android_view_GLES20Canvas_setDisplayListName },
- { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
+ { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;I)Z",
(void*) android_view_GLES20Canvas_drawDisplayList },
{ "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index fce432b..8350e73 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -21,7 +21,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include "android_view_InputChannel.h"
#include "android_util_Binder.h"
@@ -199,32 +199,16 @@
bool isInitialized = parcel->readInt32();
if (isInitialized) {
String8 name = parcel->readString8();
- int32_t parcelAshmemFd = parcel->readFileDescriptor();
- int32_t ashmemFd = dup(parcelAshmemFd);
- if (ashmemFd < 0) {
- ALOGE("Error %d dup ashmem fd %d.", errno, parcelAshmemFd);
- }
- int32_t parcelReceivePipeFd = parcel->readFileDescriptor();
- int32_t receivePipeFd = dup(parcelReceivePipeFd);
- if (receivePipeFd < 0) {
- ALOGE("Error %d dup receive pipe fd %d.", errno, parcelReceivePipeFd);
- }
- int32_t parcelSendPipeFd = parcel->readFileDescriptor();
- int32_t sendPipeFd = dup(parcelSendPipeFd);
- if (sendPipeFd < 0) {
- ALOGE("Error %d dup send pipe fd %d.", errno, parcelSendPipeFd);
- }
- if (ashmemFd < 0 || receivePipeFd < 0 || sendPipeFd < 0) {
- if (ashmemFd >= 0) ::close(ashmemFd);
- if (receivePipeFd >= 0) ::close(receivePipeFd);
- if (sendPipeFd >= 0) ::close(sendPipeFd);
+ int rawFd = parcel->readFileDescriptor();
+ int dupFd = dup(rawFd);
+ if (dupFd < 0) {
+ ALOGE("Error %d dup channel fd %d.", errno, rawFd);
jniThrowRuntimeException(env,
"Could not read input channel file descriptors from parcel.");
return;
}
- InputChannel* inputChannel = new InputChannel(name, ashmemFd,
- receivePipeFd, sendPipeFd);
+ InputChannel* inputChannel = new InputChannel(name, dupFd);
NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
@@ -243,9 +227,7 @@
parcel->writeInt32(1);
parcel->writeString8(inputChannel->getName());
- parcel->writeDupFileDescriptor(inputChannel->getAshmemFd());
- parcel->writeDupFileDescriptor(inputChannel->getReceivePipeFd());
- parcel->writeDupFileDescriptor(inputChannel->getSendPipeFd());
+ parcel->writeDupFileDescriptor(inputChannel->getFd());
} else {
parcel->writeInt32(0);
}
diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h
index fa2d282..0967021 100644
--- a/core/jni/android_view_InputChannel.h
+++ b/core/jni/android_view_InputChannel.h
@@ -19,7 +19,7 @@
#include "jni.h"
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
namespace android {
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index ed0acce..e7d4244 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -28,7 +28,7 @@
#include <utils/Log.h>
#include <utils/Looper.h>
#include <utils/threads.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
@@ -40,6 +40,7 @@
jclass clazz;
jmethodID dispatchInputEvent;
+ jmethodID dispatchBatchedInputEventPending;
} gInputEventReceiverClassInfo;
@@ -50,7 +51,8 @@
const sp<Looper>& looper);
status_t initialize();
- status_t finishInputEvent(bool handled);
+ status_t finishInputEvent(uint32_t seq, bool handled);
+ status_t consumeEvents(bool consumeBatches);
static int handleReceiveCallback(int receiveFd, int events, void* data);
protected:
@@ -60,8 +62,8 @@
jobject mReceiverObjGlobal;
InputConsumer mInputConsumer;
sp<Looper> mLooper;
- bool mEventInProgress;
PreallocatedInputEventFactory mInputEventFactory;
+ bool mBatchedInputEventPending;
const char* getInputChannelName() {
return mInputConsumer.getChannel()->getName().string();
@@ -72,7 +74,8 @@
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mInputConsumer(inputChannel), mLooper(looper), mEventInProgress(false) {
+ mInputConsumer(inputChannel), mLooper(looper),
+ mBatchedInputEventPending(false) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
#endif
@@ -83,45 +86,29 @@
ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
#endif
- mLooper->removeFd(mInputConsumer.getChannel()->getReceivePipeFd());
- if (mEventInProgress) {
- mInputConsumer.sendFinishedSignal(false); // ignoring result
- }
+ mLooper->removeFd(mInputConsumer.getChannel()->getFd());
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mReceiverObjGlobal);
}
status_t NativeInputEventReceiver::initialize() {
- status_t result = mInputConsumer.initialize();
- if (result) {
- ALOGW("Failed to initialize input consumer for input channel '%s', status=%d",
- getInputChannelName(), result);
- return result;
- }
-
- int32_t receiveFd = mInputConsumer.getChannel()->getReceivePipeFd();
+ int receiveFd = mInputConsumer.getChannel()->getFd();
mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
return OK;
}
-status_t NativeInputEventReceiver::finishInputEvent(bool handled) {
- if (mEventInProgress) {
+status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
+ ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
#endif
- mEventInProgress = false;
- status_t status = mInputConsumer.sendFinishedSignal(handled);
- if (status) {
- ALOGW("Failed to send finished signal on channel '%s'. status=%d",
- getInputChannelName(), status);
- }
- return status;
- } else {
- ALOGW("Ignoring attempt to finish input event while no event is in progress.");
- return OK;
+ status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
+ if (status) {
+ ALOGW("Failed to send finished signal on channel '%s'. status=%d",
+ getInputChannelName(), status);
}
+ return status;
}
int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -139,86 +126,101 @@
return 1;
}
- status_t status = r->mInputConsumer.receiveDispatchSignal();
- if (status) {
- ALOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
- r->getInputChannelName(), status);
- return 0; // remove the callback
- }
+ status_t status = r->consumeEvents(false /*consumeBatches*/);
+ return status == OK || status == NO_MEMORY ? 1 : 0;
+}
- if (r->mEventInProgress) {
- ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
- r->getInputChannelName());
- return 1;
- }
+status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) {
+#if DEBUG_DISPATCH_CYCLE
+ ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s.", getInputChannelName(),
+ consumeBatches ? "true" : "false");
+#endif
- InputEvent* inputEvent;
- status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent);
- if (status) {
- ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
- r->getInputChannelName(), status);
- r->mInputConsumer.sendFinishedSignal(false);
- return 1;
+ if (consumeBatches) {
+ mBatchedInputEventPending = false;
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject inputEventObj;
- switch (inputEvent->getType()) {
- case AINPUT_EVENT_TYPE_KEY:
+ for (;;) {
+ uint32_t seq;
+ InputEvent* inputEvent;
+ status_t status = mInputConsumer.consume(&mInputEventFactory,
+ consumeBatches, &seq, &inputEvent);
+ if (status) {
+ if (status == WOULD_BLOCK) {
+ if (mInputConsumer.hasPendingBatch() && !mBatchedInputEventPending) {
+ // There is a pending batch. Come back later.
+ mBatchedInputEventPending = true;
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Received key event.",
- r->getInputChannelName());
+ ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
+ getInputChannelName());
#endif
- inputEventObj = android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- break;
+ env->CallVoidMethod(mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
- case AINPUT_EVENT_TYPE_MOTION:
+ if (env->ExceptionCheck()) {
+ ALOGE("channel '%s' ~ An exception occurred while dispatching that "
+ "batched input events are pending.", getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
+ mBatchedInputEventPending = false; // try again later
+ }
+ }
+ return OK;
+ }
+ ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
+ getInputChannelName(), status);
+ return status;
+ }
+ assert(inputEvent);
+
+ jobject inputEventObj;
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY:
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Received motion event.",
- r->getInputChannelName());
+ ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
#endif
- inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
- static_cast<MotionEvent*>(inputEvent));
- break;
+ inputEventObj = android_view_KeyEvent_fromNative(env,
+ static_cast<KeyEvent*>(inputEvent));
+ break;
- default:
- assert(false); // InputConsumer should prevent this from ever happening
- inputEventObj = NULL;
- }
+ case AINPUT_EVENT_TYPE_MOTION:
+#if DEBUG_DISPATCH_CYCLE
+ ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
+#endif
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<MotionEvent*>(inputEvent));
+ break;
- if (!inputEventObj) {
- ALOGW("channel '%s' ~ Failed to obtain event object.",
- r->getInputChannelName());
- r->mInputConsumer.sendFinishedSignal(false);
- return 1;
- }
+ default:
+ assert(false); // InputConsumer should prevent this from ever happening
+ inputEventObj = NULL;
+ }
- r->mEventInProgress = true;
+ if (!inputEventObj) {
+ ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
+ mInputConsumer.sendFinishedSignal(seq, false);
+ return NO_MEMORY;
+ }
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Invoking input handler.", r->getInputChannelName());
+ ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
#endif
- env->CallVoidMethod(r->mReceiverObjGlobal,
- gInputEventReceiverClassInfo.dispatchInputEvent, inputEventObj);
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Returned from input handler.", r->getInputChannelName());
-#endif
+ env->CallVoidMethod(mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
- if (env->ExceptionCheck()) {
- ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
- r->getInputChannelName());
- LOGE_EX(env);
- env->ExceptionClear();
+ env->DeleteLocalRef(inputEventObj);
- if (r->mEventInProgress) {
- r->mInputConsumer.sendFinishedSignal(false);
- r->mEventInProgress = false;
+ if (env->ExceptionCheck()) {
+ ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
+ getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
+
+ mInputConsumer.sendFinishedSignal(seq, false);
+ return OK;
}
}
-
- env->DeleteLocalRef(inputEventObj);
- return 1;
}
@@ -257,28 +259,41 @@
receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
}
-static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, jboolean handled) {
+static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
+ jint seq, jboolean handled) {
sp<NativeInputEventReceiver> receiver =
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
- status_t status = receiver->finishInputEvent(handled);
- if (status) {
+ status_t status = receiver->finishInputEvent(seq, handled);
+ if (status && status != DEAD_OBJECT) {
String8 message;
message.appendFormat("Failed to finish input event. status=%d", status);
jniThrowRuntimeException(env, message.string());
}
}
+static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ status_t status = receiver->consumeEvents(true /*consumeBatches*/);
+ if (status && status != DEAD_OBJECT) {
+ String8 message;
+ message.appendFormat("Failed to consume batched input event. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ }
+}
+
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
(void*)nativeInit },
- { "nativeDispose",
- "(I)V",
+ { "nativeDispose", "(I)V",
(void*)nativeDispose },
- { "nativeFinishInputEvent", "(IZ)V",
- (void*)nativeFinishInputEvent }
+ { "nativeFinishInputEvent", "(IIZ)V",
+ (void*)nativeFinishInputEvent },
+ { "nativeConsumeBatchedInputEvents", "(I)V",
+ (void*)nativeConsumeBatchedInputEvents },
};
#define FIND_CLASS(var, className) \
@@ -299,7 +314,10 @@
GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
gInputEventReceiverClassInfo.clazz,
- "dispatchInputEvent", "(Landroid/view/InputEvent;)V");
+ "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
+ GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchBatchedInputEventPending,
+ gInputEventReceiverClassInfo.clazz,
+ "dispatchBatchedInputEventPending", "()V");
return 0;
}
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index b9f3738..7245d9d 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <ui/KeyCharacterMap.h>
-#include <ui/Input.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/Input.h>
#include <android_runtime/AndroidRuntime.h>
#include <nativehelper/jni.h>
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 27469a2..36a98f9 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -20,7 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include "android_view_KeyEvent.h"
namespace android {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 2def1d1..0fb1b17 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -20,7 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include "android_view_MotionEvent.h"
#include "android_util_Binder.h"
#include "android/graphics/Matrix.h"
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bba4b47..18bcea1 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -572,7 +572,7 @@
}
static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers)
+ jint minLayer, jint maxLayer)
{
return doScreenshot(env, clazz, width, height, minLayer, maxLayer, false);
}
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 0da90d7..668d3bb 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -20,7 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include "android_view_MotionEvent.h"
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index b68c97a..afbcfc2 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -21,7 +21,7 @@
#include <utils/Log.h>
#include <ScopedUtfChars.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileRO.h>
#include <zlib.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 97658a1..a2b1117 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -717,6 +717,13 @@
android:label="@string/permlab_removeTasks"
android:description="@string/permdesc_removeTasks" />
+ <!-- @hide Change the screen compatibility mode of applications -->
+ <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature"
+ android:label="@string/permlab_setScreenCompatibility"
+ android:description="@string/permdesc_setScreenCompatibility" />
+
<!-- Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
@@ -1507,6 +1514,24 @@
android:description="@string/permdesc_bindPackageVerifier"
android:protectionLevel="signature" />
+ <!-- Allows applications to access serial ports via the SerialManager.
+ @hide -->
+ <permission android:name="android.permission.SERIAL_PORT"
+ android:label="@string/permlab_serialPort"
+ android:description="@string/permdesc_serialPort"
+ android:protectionLevel="normal" />
+
+ <!-- Allows the holder to access content providers from outside an ApplicationThread.
+ This permission is enforced by the ActivityManagerService on the corresponding APIs,
+ in particular ActivityManagerService#getContentProviderExternal(String) and
+ ActivityManagerService#removeContentProviderExternal(String).
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
+ android:label="@string/permlab_accessContentProvidersExternally"
+ android:description="@string/permdesc_accessContentProvidersExternally"
+ android:protectionLevel="signature" />
+
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/anim/recents_fade_in.xml b/core/res/res/anim/recents_fade_in.xml
new file mode 100644
index 0000000..c516fadb
--- /dev/null
+++ b/core/res/res/anim/recents_fade_in.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/recents_fade_in.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@interpolator/decelerate_quad"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="150" />
diff --git a/core/res/res/anim/recents_fade_out.xml b/core/res/res/anim/recents_fade_out.xml
new file mode 100644
index 0000000..7468cc19
--- /dev/null
+++ b/core/res/res/anim/recents_fade_out.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/recents_fade_out.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="150" />
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
index c2e4b78..cb08eed 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
index 51b839f..ea065c3 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..d3ba98c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..153c6ad
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..ec6bc54
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..9fd4f33
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f21c6b8..6f861fb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -215,6 +215,10 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Laat die program toe om take na die voorgrond en agtergrond te skuif. Kwaadwillige programme kan hulself sonder jou beheer na vore dwing."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stop lopende programme"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Laat die program toe om take te verwyder en hul programme te dood. Kwaadwillige programme kan die gedrag van ander programme ontwrig."</string>
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktiveer programontfouting"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Laat die program toe om ontfouting vir \'n ander program af te skakel. Kwaadwillige programme kan dit dalk gebruik om ander programme te dood."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"Verander jou UI-instellings"</string>
@@ -539,30 +543,30 @@
<item msgid="1735177144948329370">"Tuisfaks"</item>
<item msgid="603878674477207394">"Roeper"</item>
<item msgid="1650824275177931637">"Ander"</item>
- <item msgid="9192514806975898961">"Gepasmaakte"</item>
+ <item msgid="9192514806975898961">"Gepasmaak"</item>
</string-array>
<string-array name="emailAddressTypes">
<item msgid="8073994352956129127">"Tuis"</item>
<item msgid="7084237356602625604">"Werk"</item>
<item msgid="1112044410659011023">"Ander"</item>
- <item msgid="2374913952870110618">"Gepasmaakte"</item>
+ <item msgid="2374913952870110618">"Gepasmaak"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="6880257626740047286">"Tuis"</item>
<item msgid="5629153956045109251">"Werk"</item>
<item msgid="4966604264500343469">"Ander"</item>
- <item msgid="4932682847595299369">"Gepasmaakte"</item>
+ <item msgid="4932682847595299369">"Gepasmaak"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="1738585194601476694">"Tuis"</item>
<item msgid="1359644565647383708">"Werk"</item>
<item msgid="7868549401053615677">"Ander"</item>
- <item msgid="3145118944639869809">"Gepasmaakte"</item>
+ <item msgid="3145118944639869809">"Gepasmaak"</item>
</string-array>
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"Werk"</item>
<item msgid="4378074129049520373">"Ander"</item>
- <item msgid="3455047468583965104">"Gepasmaakte"</item>
+ <item msgid="3455047468583965104">"Gepasmaak"</item>
</string-array>
<string-array name="imProtocols">
<item msgid="8595261363518459565">"AIM"</item>
@@ -574,7 +578,7 @@
<item msgid="2506857312718630823">"ICQ"</item>
<item msgid="1648797903785279353">"Jabber"</item>
</string-array>
- <string name="phoneTypeCustom" msgid="1644738059053355820">"Gepasmaakte"</string>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"Gepasmaak"</string>
<string name="phoneTypeHome" msgid="2570923463033985887">"Tuis"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"Mobiel"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"Werk"</string>
@@ -595,24 +599,24 @@
<string name="phoneTypeWorkPager" msgid="649938731231157056">"Werkroeper"</string>
<string name="phoneTypeAssistant" msgid="5596772636128562884">"Assistent"</string>
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
- <string name="eventTypeCustom" msgid="7837586198458073404">"Gepasmaakte"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"Gepasmaak"</string>
<string name="eventTypeBirthday" msgid="2813379844211390740">"Verjaardag"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Herdenking"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"Ander"</string>
- <string name="emailTypeCustom" msgid="8525960257804213846">"Gepasmaakte"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"Gepasmaak"</string>
<string name="emailTypeHome" msgid="449227236140433919">"Tuis"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"Werk"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"Ander"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"Mobiel"</string>
- <string name="postalTypeCustom" msgid="8903206903060479902">"Gepasmaakte"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"Gepasmaak"</string>
<string name="postalTypeHome" msgid="8165756977184483097">"Tuis"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"Werk"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"Ander"</string>
- <string name="imTypeCustom" msgid="2074028755527826046">"Gepasmaakte"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"Gepasmaak"</string>
<string name="imTypeHome" msgid="6241181032954263892">"Tuis"</string>
<string name="imTypeWork" msgid="1371489290242433090">"Werk"</string>
<string name="imTypeOther" msgid="5377007495735915478">"Ander"</string>
- <string name="imProtocolCustom" msgid="6919453836618749992">"Gepasmaakte"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"Gepasmaak"</string>
<string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
<string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
@@ -624,8 +628,8 @@
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
<string name="orgTypeWork" msgid="29268870505363872">"Werk"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Ander"</string>
- <string name="orgTypeCustom" msgid="225523415372088322">"Gepasmaakte"</string>
- <string name="relationTypeCustom" msgid="3542403679827297300">"Gepasmaakte"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"Gepasmaak"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"Gepasmaak"</string>
<string name="relationTypeAssistant" msgid="6274334825195379076">"Assistent"</string>
<string name="relationTypeBrother" msgid="8757913506784067713">"Broer"</string>
<string name="relationTypeChild" msgid="1890746277276881626">"Kind"</string>
@@ -640,7 +644,7 @@
<string name="relationTypeRelative" msgid="1799819930085610271">"Familielid"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Suster"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Eggenoot"</string>
- <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaakte"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaak"</string>
<string name="sipAddressTypeHome" msgid="6093598181069359295">"Tuis"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Werk"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Ander"</string>
@@ -760,6 +764,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Laat die program toe om te verifieer dat \'n pakket installeerbaar is."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind aan \'n pakkieverifieerder"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Wil jy hê die blaaier moet hierdie wagwoord onthou?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nie nou nie"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthou"</string>
@@ -972,6 +982,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Begin Wi-Fi Direct. Dit sal die Wi-Fi-kliënt/warmkol afskakel."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kon nie Wi-Fi Direct begin nie."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direk is aan"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Raak vir instellings"</string>
<string name="accept" msgid="1645267259272829559">"Aanvaar"</string>
<string name="decline" msgid="2112225451706137894">"Weier"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging gestuur"</string>
@@ -980,8 +992,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Aan:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer die vereiste PIN in:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direk is aan"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Raak vir instellings"</string>
<string name="select_character" msgid="3365550120617701745">"Voeg karakter in"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekend program"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Stuur SMS-boodskappe"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9b32c0d..bb6246a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"ወደ ግንባር ዎይ እና ዳራ ስራዎችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡ ያለአንተ ቁጥጥር ተንኮል አዘል መተግበሪያዎች ራሳቸውን ወደፊት መምጣት ሊያስገድዱ ይችላሉ፡፡"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"የማያ ገጽ ተኳኋኝነት መድብ"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"መተግበሪያው የሌሎች መተግበሪያዎች የማያ ገጽ ተኳኋኝነት ሁናቴ እንዲቆጣጠር ይፈቅዳል። ተንኮለኛ መተግበሪያዎች የሌሎች መተግበሪያዎች ባህሪ ሊሰብሩ ይችላሉ።"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"የትግበራ ማረሚያ አንቃ"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"ለሌላ መተግበሪያ አርምን አብራ ለመተግበሪያው ይፈቅዳሉ። ሌሎች መተግበሪያዎች ለመግደል ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙት ይችላሉ።"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"የUI ቅንብሮችን ለውጥ"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ፓኬጅ መጫን የሚችል መሆኑን ለማረጋገጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"በፓኬጅ አረጋጋጭ የተወሰነ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"አሳሹ ይህን ይለፍ ቃል እንዲያስታወስ ይፈልጋሉ?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"አሁን አይደለም"</string>
<string name="save_password_remember" msgid="6491879678996749466">"አስታውስ"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"የWi-Fi በቀጥታ ጀምር።ይህ የWi-Fi ደንበኛ /ድረስ ነጥብ ያጠፋል።"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"በቀጥታ Wi-Fi ማስጀመር አልተቻለም።"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"የWi-Fi ቀጥታ በርቷል"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ለቅንብሮች ንካ"</string>
<string name="accept" msgid="1645267259272829559">"ተቀበል"</string>
<string name="decline" msgid="2112225451706137894">"ውድቅ አድርግ"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ግብዣ ተልኳል"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"ለ፦"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"የሚፈለገውን ፒን ተይብ፦"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ፒን፦"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"የWi-Fi ቀጥታ በርቷል"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ለቅንብሮች ንካ"</string>
<string name="select_character" msgid="3365550120617701745">"ቁምፊ አስገባ"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"ያልታወቀ መተግበሪያ"</string>
<string name="sms_control_title" msgid="7296612781128917719">"የSMS መልዕክቶች መበላክ ላይ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b8cd094..580f9bc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"للسماح لتطبيق ما بنقل المهام إلى المقدمة والخلفية. قد تفرض التطبيقات الضارة نفسها إلى المقدمة بدون تحكم منك."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تعيين توافق الشاشة"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"السماح للتطبيق بالتحكم في وضع التوافق مع شاشة التطبيقات الأخرى. قد تتسبب التطبيقات الضارة في تعطيل سلوك التطبيقات الأخرى."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"تمكين تصحيح أخطاء التطبيق"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"للسماح للتطبيق بتشغيل تصحيح الأخطاء لتطبيق آخر. قد تستخدم التطبيقات الضارة هذا لإنهاء التطبيقات الأخرى."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغيير إعدادات واجهة المستخدم"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"السماح للتطبيق بالتحقق من إمكانية تثبيت حزمة."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"الالتزام بمحقق حزمة"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"هل تريد من المتصفح تذكر كلمة المرور هذه؟"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"ليس الآن"</string>
<string name="save_password_remember" msgid="6491879678996749466">"تذكّر"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"اتصال Wi-Fi مباشر"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"تعذر بدء Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"تم تشغيل اتصال Wi-Fi المباشر"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"المس للحصول على الإعدادات"</string>
<string name="accept" msgid="1645267259272829559">"قبول"</string>
<string name="decline" msgid="2112225451706137894">"رفض"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"تم إرسال الدعوة"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"إلى:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"اكتب رقم التعريف الشخصي المطلوب:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"رقم التعريف الشخصي:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"تم تشغيل اتصال Wi-Fi المباشر"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"المس للحصول على الإعدادات"</string>
<string name="select_character" msgid="3365550120617701745">"إدراج حرف"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"تطبيق غير معروف"</string>
<string name="sms_control_title" msgid="7296612781128917719">"إرسال رسائل قصيرة SMS"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 8479324..8de1cf5 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць заданні на пярэдні план і фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"спыніць запушчаныя прыкладанні"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дазваляе прыкладанням выдаляць заданні і спыняць прыкладанні, якія іх выкарыстоўваюць. Шкоднасныя прыкладаннi могуць перашкодзiць працы іншых прыкладанняў."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"усталяваць сумяшчальнасць экранаў"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дазваляе прыкладанню кіраваць рэжымам сумяшчальнасці экранаў іншых прыкладанняў. Шкоднаснае ПЗ можа перашкодзiць працы іншых прыкладанняў."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"уключыць адладку прыкладання"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дазваляе прыкладанням уключаць адладку для іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць іншыя прыкладанні."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змяняць налады карыстальніцкага інтэрфейса"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дазваляе прыкладанням правяраць магчымасць усталявання пакету."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прывязаць да верыфікатару пакету"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"атрымаць доступ да паслядоўных партоў"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Дазваляе ўладальніку атрымліваць доступ да паслядоўных партоў з дапамогай API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
<string name="accept" msgid="1645267259272829559">"Прыняць"</string>
<string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
<string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6bec103..ec2e0bf 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Разрешава на приложението да прехвърля задачи на преден и на заден план. Злонамерените приложения могат сами да се изведат на преден план без ваша намеса."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"спиране на изпълняваните приложения"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Разрешава на приложението да премахва задачи и да прекратява приложенията им. Злонамерените приложения могат да нарушат поведението на други приложения."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"задаване на съвместимост на екрана"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Разрешава на приложението да контролира режима на съвместимост на екрана на други приложения. Злонамерените програми могат да нарушат поведението на други приложения."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"активиране на отстраняването на грешки в приложения"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Разрешава на приложението да включва отстраняването на грешки за друго приложение. Злонамерените приложения могат да използват това, за да прекратят други приложения."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промяна на настройките ви за потребителския интерфейс"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Разрешава на приложението да провери дали пакетът може да се инсталира."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обвързване с верификатор на пакета"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Искате ли браузърът да запомни тази парола?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сега"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомняне"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Стартиране на Wi-Fi Direct. Това ще изключи клиентската програма/точката за достъп до Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct не можа да се стартира."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е включено"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Докоснете за настройки"</string>
<string name="accept" msgid="1645267259272829559">"Приемам"</string>
<string name="decline" msgid="2112225451706137894">"Отхвърлям"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Поканата е изпратена"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"До:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Въведете задължителния ПИН:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ПИН:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е включено"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Докоснете за настройки"</string>
<string name="select_character" msgid="3365550120617701745">"Вмъкване на знак"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестно приложение"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Изпращане на SMS съобщения"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8dced70..173f1fc 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet que l\'aplicació desplaci tasques en primer o segon pla. Les aplicacions malicioses poden aparèixer en primer pla sense el teu consentiment."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definició de la compatibilitat de pantalla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permet que l\'aplicació controli el mode de compatibilitat de pantalla d\'altres aplicacions. És possible que les aplicacions malicioses interrompin el comportament d\'altres aplicacions."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activa la depuració d\'aplicacions"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet que una aplicació activi la depuració per a una altra aplicació. Les aplicacions malicioses poden utilitzar aquesta funció per finalitzar altres aplicacions."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"canviar la configuració de la IU"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet que l\'aplicació verifiqui si un paquet es pot instal·lar."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincula a un verificador de paquets"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Voleu que el navegador recordi aquesta contrasenya?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ara no"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recorda-ho"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Això desactivarà el client/la zona Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No s\'ha pogut iniciar Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct està activat"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca per accedir a la configuració"</string>
<string name="accept" msgid="1645267259272829559">"Accepta"</string>
<string name="decline" msgid="2112225451706137894">"Rebutja"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"S\'ha enviat la invitació"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Per a:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introdueix el PIN sol·licitat:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct està activat"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca per accedir a la configuració"</string>
<string name="select_character" msgid="3365550120617701745">"Insereix un caràcter"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicació desconeguda"</string>
<string name="sms_control_title" msgid="7296612781128917719">"S\'estan enviant missatges SMS"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e21de4b..d3b5276 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Škodlivé aplikace mohou vynutit zobrazení na popředí bez vašeho svolení."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavit kompatibilitu obrazovky"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Umožňuje aplikaci ovládat režim kompatibility obrazovky v ostatních aplikacích. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"povolení ladění aplikací"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikaci zapnout ladění jiné aplikace. Škodlivé aplikace mohou toto oprávnění použít k ukončení ostatních aplikací."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"změna vašeho nastavení uživatelského rozhraní"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikaci ověřit, zda balíček lze nainstalovat."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"navázat na ověřovatele balíčků"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Přímé připojení sítě Wi-Fi"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustit přímé připojení sítě Wi-Fi. Tato možnost vypne provoz sítě Wi-Fi v režimu klient/hotspot."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Přímé připojení sítě Wi-Fi se nepodařilo spustit."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Přímé připojení sítě Wi-Fi je zapnuto"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavení otevřete dotykem"</string>
<string name="accept" msgid="1645267259272829559">"Přijmout"</string>
<string name="decline" msgid="2112225451706137894">"Odmítnout"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka odeslána."</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadejte požadovaný kód PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Přímé připojení sítě Wi-Fi je zapnuto"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavení otevřete dotykem"</string>
<string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznámá aplikace"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 1175cbb..78aff33 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Ondsindede apps kan tvinge sig selv i forgrunden uden din kontrol."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"indstil skærmens kompatibilitet"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Tillader, at appen kontrollerer kompatibilitetstilstanden for skærme i andre applikationer. Ondsindede applikationer kan forstyrre andre applikationers adfærd."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere fejlretning af appen"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillader, at appen kan slå fejlretning til for en anden app. Ondsindede apps kan bruge dette til at afslutte andre apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift indstillinger for brugergrænsefladen"</string>
@@ -755,11 +757,17 @@
<string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføj telefonsvarer"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Tillader, at appen kan tilføje beskeder på din telefonsvarer."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geografisk placering i Browser"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websteder."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websites."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"bekræft pakker"</string>
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette slår Wi-Fi-klient/hotspot fra."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct kunne ikke startes."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slået til"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryk for indstillinger"</string>
<string name="accept" msgid="1645267259272829559">"Accepter"</string>
<string name="decline" msgid="2112225451706137894">"Afvis"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitationen er sendt"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv den påkrævede pinkode:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pinkode:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slået til"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryk for indstillinger"</string>
<string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukendt app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Sender sms-beskeder"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 953897c..78845c4 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Apps können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Bildschirmkompatibilität festlegen"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ermöglicht der App, den Bildschirmkompatibilitätsmodus anderer Apps zu steuern. Schädliche Apps können das Verhalten anderer Apps stören."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Fehlerbeseitigung für App aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ermöglicht der App, die Fehlerbeseitigung für eine andere App zu aktivieren. Schädliche Apps können so andere Apps beenden."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ermöglicht der App die Überprüfung, ob ein Paket installiert werden kann"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"An Paketprüfung binden"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Starten von Wi-Fi Direct nicht möglich"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ist aktiviert."</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Zum Aufrufen der Einstellungen berühren"</string>
<string name="accept" msgid="1645267259272829559">"Akzeptieren"</string>
<string name="decline" msgid="2112225451706137894">"Ablehnen"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Einladung gesendet"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"An:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Geben Sie die erforderliche PIN ein:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ist aktiviert."</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Zum Aufrufen der Einstellungen berühren"</string>
<string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Unbekannte App"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 458517c..9244dab 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Τυχόν κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ρύθμιση συμβατότητας οθόνης"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Επιτρέπει στην εφαρμογή να ελέγξει τη λειτουργία συμβατότητας της οθόνης με άλλες εφαρμογές. Οι κακόβουλες εφαρμογές μπορεί να επηρεάσουν τη συμπεριφορά άλλων εφαρμογών."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Επιτρέπει στην εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τον τερματισμό άλλων εφαρμογών."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των ρυθμίσεων του UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Επιτρέπει στην εφαρμογή να επαληθεύσει τη δυνατότητα εγκατάστασης ενός πακέτου."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"δέσμευση με επαλήθευση πακέτου"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Διατήρηση"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ξεκινήστε τη λειτουργία Wi-Fi Direct. Θα απενεργοποιηθεί η λειτουργία πελάτη/φορητού σημείου πρόσβασης Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Δεν ήταν δυνατή η εκκίνηση του Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Το Wi-Fi Direct έχει ενεργοποιηθεί"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Αγγίξτε για ρυθμίσεις"</string>
<string name="accept" msgid="1645267259272829559">"Αποδοχή"</string>
<string name="decline" msgid="2112225451706137894">"Απόρριψη"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Η πρόσκληση στάλθηκε"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Προς:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Το Wi-Fi Direct έχει ενεργοποιηθεί"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Αγγίξτε για ρυθμίσεις"</string>
<string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Άγνωστη εφαρμογή"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d48f544..dbd2218 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Allows the app to move tasks to the foreground and background. Malicious apps may force themselves to the front without your control."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"set screen compatibility"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Allows the app to control the screen compatibility mode of other applications. Malicious applications may break the behaviour of other applications."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"enable app debugging"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Allows the app to turn on debugging for another app. Malicious apps may use this to kill other apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"change your UI settings"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Do you want the browser to remember this password?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Not now"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Remember"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Touch for settings"</string>
<string name="accept" msgid="1645267259272829559">"Accept"</string>
<string name="decline" msgid="2112225451706137894">"Decline"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Touch for settings"</string>
<string name="select_character" msgid="3365550120617701745">"Insert character"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Unknown app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c66dc8e..42cc24a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas al primero o segundo plano. Las aplicaciones maliciosas pueden forzar su paso al primer plano sin que tú las controles."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Definir compatibilidad de pantalla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite a la aplicación controlar el modo de compatibilidad de las pantallas de otras aplicaciones. Las aplicaciones malintencionadas pueden interrumpir el funcionamiento de otras aplicaciones."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Vincular a un verificador de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se pudo iniciar Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Se activó Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para ajustar los parámetros de configuración"</string>
<string name="accept" msgid="1645267259272829559">"Aceptar"</string>
<string name="decline" msgid="2112225451706137894">"Rechazar"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Se envió la invitación."</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Se activó Wi-Fi Direct."</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para ajustar los parámetros de configuración"</string>
<string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0c526ff..a09a6bf 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas a segundo o a primer plano. Algunas aplicaciones malintencionadas pueden aparecer en primer plano sin el control del usuario."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"establecer compatibilidad de pantalla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que la aplicación controle el modo de compatibilidad de la pantalla de otras aplicaciones. Las aplicaciones malintencionadas pueden influir de forma negativa en el funcionamiento de otras aplicaciones."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"enlazar con un detector de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"¿Quieres que el navegador recuerde esta contraseña?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se ha podido iniciar Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activado"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca para acceder a Ajustes"</string>
<string name="accept" msgid="1645267259272829559">"Aceptar"</string>
<string name="decline" msgid="2112225451706137894">"Rechazar"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitación enviada"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activado"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca para acceder a Ajustes"</string>
<string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 5591289..07e732a 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Võimaldab rakendusel teisaldada ülesanded esiplaanile ja taustale. Pahatahtlikud rakendused võivad sundida end esiplaanile tulema teie loata."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käitatud rakenduste peatamine"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Võimaldab rakendusel eemaldada ülesanded ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"kuva ühilduvuse seadmine"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Võimaldab rakendusel juhtida teiste rakenduste kuva ühilduvuse režiimi. Pahatahtlikud rakendused võivad teisi rakendusi häirida."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Rakenduse silumise lubamine"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuda UI-seadeid"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Võimaldab rakendusel kinnitada, et paketti saab installida."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sidumine paketi kinnitajaga"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Kas soovite, et brauser jätaks selle parooli meelde?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Mitte praegu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Pidage meeles"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string>
<string name="accept" msgid="1645267259272829559">"Nõustu"</string>
<string name="decline" msgid="2112225451706137894">"Keeldu"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutse on saadetud"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Saaja:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string>
<string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Tundmatu rakendus"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-sõnumite saatmine"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 7097e43..ddb0438 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"به برنامه اجازه میدهد تا کارها را به پیش زمینه و پس زمینه منتقل کند. برنامههای مخرب میتوانند بدون کنترل به اجبار خود را به جلو منتقل کنند."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"متوقف کردن برنامههای در حال اجرا"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"به برنامه اجازه میدهد تا کارها را حذف کند و برنامههای آنها را متوقف کند. برنامههای مخرب میتوانند در اجرای برنامههای دیگر اختلال ایجاد کنند."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تنظیم سازگاری با صفحه نمایش"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"به برنامه کاربردی اجازه کنترل حالت سازگاری صفحه نمایش برای برنامههای دیگر را میدهد. برنامههای خرابکار ممکن است باعث کارکرد نادرست دیگر برنامهها شوند."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"فعال کردن عیبیابی برنامه"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"به برنامه اجازه میدهد تا عیبیابی را برای برنامهای دیگر فعال کند. برنامههای مخرب میتوانند از آن استفاده کنند تا اجرای برنامههای دیگر را متوقف کنند."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغییر تنظیمات UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"به برنامه اجازه میدهد قابل نصب بودن بسته را تأیید کند."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"اتصال به یک تأیید کننده بسته"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"به دارنده اجازه میدهد تا تاییدکنندگان بسته را درخواست کند. برای برنامههای عادی نیاز نیست."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاههای سریال"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"به دارنده اجازه میدهد با استفاده از SerialManager API به درگاههای سریال دسترسی داشته باشد."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"می خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"اکنون خیر"</string>
<string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct را شروع کنید. این کار نقطه اتصال/سرویس گیرنده Wi-Fi را غیرفعال خواهد کرد."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct شروع نشد."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct روشن است"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"لمس کردن برای تنظیمات"</string>
<string name="accept" msgid="1645267259272829559">"پذیرش"</string>
<string name="decline" msgid="2112225451706137894">"عدم پذیرش"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"دعوتنامه ارسال شد"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"به:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"پین لازم را تایپ کنید:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"پین:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct روشن است"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"لمس کردن برای تنظیمات"</string>
<string name="select_character" msgid="3365550120617701745">"درج نویسه"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"برنامه ناشناخته"</string>
<string name="sms_control_title" msgid="7296612781128917719">"ارسال پیامک ها"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5a4d2f0..b837c5a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Antaa sovelluksen siirtää tehtäviä etualalle ja taustalle. Haitalliset sovellukset voivat pakottaa itsensä etualalle ilman käyttäjän hallintaa."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käynnissä olevien sovellusten pysäyttäminen"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Antaa sovelluksen poistaa tehtäviä ja lopettaa niiden sovelluksia. Haitalliset sovellukset voivat häiritä muiden sovellusten toimintaa."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"aseta näytön yhteensopivuus"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Sallii sovelluksen hallita toisten sovellusten näytön yhteensopivuustilaa. Haittasovellukset voivat häiritä toisten sovellusten toimintaa."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"sovellusten vianetsinnän käyttöönotto"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Antaa sovelluksen ottaa vianetsinnän käyttöön toisessa sovelluksessa. Haitalliset ohjelmat voivat lopettaa tällä muita sovelluksia."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuta käyttöliittymäsi asetuksia"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Antaa sovelluksen vahvistaa, että pakkaus on asennettavissa."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sitoudu paketin vahvistajaan"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Haluatko selaimen muistavan tämän salasanan?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ei nyt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Muista"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wifi-asiakas/-hotspot poistetaan käytöstä."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran wifi-yhteyden käynnistäminen epäonnistui."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string>
<string name="accept" msgid="1645267259272829559">"Hyväksy"</string>
<string name="decline" msgid="2112225451706137894">"Hylkää"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutsu lähetetty."</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Kohde:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string>
<string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Tuntematon sovellus"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d32f487..aebe460 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet à l\'application de faire passer les tâches de premier plan en arrière-plan. Des applications malveillantes peuvent exploiter cette fonctionnalité pour passer au premier plan sans votre consentement."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"arrêter les applications en cours d\'exécution"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet à l\'application de supprimer des tâches et de fermer les applications qui les exécutent. Des applications malveillantes peuvent exploiter cette fonctionnalité pour perturber le comportement des autres applications."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"définir la compatibilité de l\'écran"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permettre de contrôler le mode de compatibilité de l\'écran des autres applications. Des applications malveillantes peuvent perturber le fonctionnement d\'autres applications."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activer le débogage des applications"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet à l\'application d\'activer le débogage d\'une autre application. Des applications malveillantes peuvent exploiter cette fonctionnalité pour en fermer d\'autres."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un package peut être installé."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associer à un vérificateur de package"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Mémoriser"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Appuyez pour accéder aux paramètres."</string>
<string name="accept" msgid="1645267259272829559">"Accepter"</string>
<string name="decline" msgid="2112225451706137894">"Refuser"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation envoyée"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"À :"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le code PIN requis :"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Code PIN :"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Appuyez pour accéder aux paramètres."</string>
<string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Application inconnue"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 7a4f706..11bad07 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"एप्लिकेशन को अग्रभूमि और पृष्ठभूमि में कार्यों को ले जाने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके नियंत्रण के बिना स्वयं को बलपूर्वक आगे कर सकते हैं."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्लिकेशन को कार्यों को निकालने और उनके एप्लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्क्रीन संगतता सेट करें"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्लिकेशन को अन्य एप्लिकेशन के स्क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्लिकेशन डीबग करना सक्षम करें"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्लिकेशन को अन्य एप्लिकेशन के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग अन्य एप्लिकेशन को समाप्त करने के लिए कर सकते हैं."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"अपनी UI सेटिंग बदलें"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्लिकेशन को इंस्टॉल करने योग्य पैकेज सत्यापित करने देता है."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"क्या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
<string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi प्रत्यक्ष"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi डायरेक्ट प्रारंभ करें. इससे Wi-Fi क्लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi डायरेक्ट प्रारंभ नहीं किया जा सका."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi प्रत्यक्ष चालू है"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"सेटिंग के लिए स्पर्श करें"</string>
<string name="accept" msgid="1645267259272829559">"स्वीकार करें"</string>
<string name="decline" msgid="2112225451706137894">"अस्वीकार करें"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"आमंत्रण भेजा गया"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"प्रति:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्यक पिन लिखें:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi प्रत्यक्ष चालू है"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"सेटिंग के लिए स्पर्श करें"</string>
<string name="select_character" msgid="3365550120617701745">"वर्ण सम्मिलित करें"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"अज्ञात एप्लिकेशन"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS संदेश भेज रहा है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e37be22..462cb52 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Omogućuje aplikaciji da premjesti zadatke u prednji plan ili pozadinu. Zlonamjerne aplikacije mogu na silu doći u prednji plan bez vašeg nadzora."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje kompatibilnosti sa zaslonom"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti aplikacija sa zaslonom. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"omogućavanje rješavanja programskih pogrešaka u aplikaciji"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Omogućuje aplikaciji uključivanje uklanjanja programskih pogrešaka za drugu aplikaciju. Zlonamjerne aplikacije mogu na taj način ukloniti druge aplikacije."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogućuje da provjeri je li paket moguće instalirati."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vezano uz paketnu provjeru"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Želite li da preglednik zapamti ovu zaporku?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Izravni Wi-Fi"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni izravan rad s Wi-Fi mrežom. To će isključiti rad s Wi-Fi klijentom/žarišnom točkom."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Pokretanje izravne Wi-Fi veze nije moguće."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct uključen"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string>
<string name="accept" msgid="1645267259272829559">"Prihvaćam"</string>
<string name="decline" msgid="2112225451706137894">"Odbaci"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslana"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Prima:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Upišite potreban PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct uključen"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string>
<string name="select_character" msgid="3365550120617701745">"Umetni znak"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Nepoznata aplikacija"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9b3eb54..c74ef36 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lehetővé teszi az alkalmazás számára, hogy feladatokat helyezzen át az előtérből a háttérbe és fordítva. A rosszindulatú alkalmazások az előtérbe helyezhetik magukat az Ön engedélye nélkül."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"futó alkalmazások leállítása"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Lehetővé teszi, hogy az alkalmazás feladatokat távolítson el és leállítsa azok alkalmazásait. Rosszindulatú alkalmazások megzavarhatják más alkalmazások viselkedését."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Képernyő-kompatibilitás beállítása"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Lehetővé teszi, hogy az alkalmazás szabályozza az egyéb alkalmazások képernyő-kompatibilitási módját. A kártékony alkalmazások megzavarhatják a többi alkalmazás viselkedését."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"alkalmazások hibakeresésének bekapcsolása"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lehetővé teszi az alkalmazás számára, hogy hibakeresést végezzen egy másik alkalmazáson. A rosszindulatú alkalmazások ezzel leállíthatnak más alkalmazásokat."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"a felhasználói felület beállításainak módosítása"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lehetővé teszi az alkalmazás számára, hogy ellenőrizze, egy csomag telepíthető-e."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"egy csomaghitelesítőhöz kötődnek"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Szeretné, hogy a böngésző megjegyezze a jelszót?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Most nem"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Megjegyzés"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct elindítása. A Wi-Fi kliens/hotspot ettől leáll."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nem sikerült elindítani a Wi-Fi Direct kapcsolatot."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"A Wi-Fi Direct be van kapcsolva"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"A beállításokhoz érintse meg"</string>
<string name="accept" msgid="1645267259272829559">"Elfogadás"</string>
<string name="decline" msgid="2112225451706137894">"Elutasítás"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Meghívó elküldve"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Címzett:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Adja meg a szükséges PIN kódot:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kód:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"A Wi-Fi Direct be van kapcsolva"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"A beállításokhoz érintse meg"</string>
<string name="select_character" msgid="3365550120617701745">"Karakter beszúrása"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Ismeretlen alkalmazás"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-ek küldése"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b61fb42..068356e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Mengizinkan apl memindah tugas ke latar depan dan latar belakang. Apl berbahaya dapat memaksa berpindah ke depan tanpa kontrol Anda."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"menghentikan apl yang berjalan"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Memungkinkan apl menghapus tugas dan menutup aplikasinya. Apl berbahaya dapat mengganggu perilaku apl lain."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"menyetel kompatibilitas layar"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Memungkinkan apl mengontrol mode kompatibilitas layar aplikasi lain. Aplikasi berbahaya dapat merusak perilaku aplikasi lain."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"mengaktifkan debugging apl"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Mengizinkan apl mengaktifkan debugging untuk apl lain. Apl berbahaya dapat menggunakan cara ini untuk menutup apl lain."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ubah setelan UI Anda"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Mengizinkan apl memverifikasi bahwa suatu paket dapat dipasang."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"mengikat ke pemverifikasi paket"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Memulai Wi-Fi Langsung. Opsi ini akan mematikan hotspot/klien Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulai Wi-Fi Langsung."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Langsung aktif"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk setelan"</string>
<string name="accept" msgid="1645267259272829559">"Terima"</string>
<string name="decline" msgid="2112225451706137894">"Tolak"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Undangan terkirim"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ketik PIN yang diminta:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Langsung aktif"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk setelan"</string>
<string name="select_character" msgid="3365550120617701745">"Sisipkan huruf"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tak dikenal"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Mengirim pesan SMS"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ebf7223..221fff0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Consente all\'applicazione di spostare attività in primo piano e in background. Le applicazioni dannose potrebbero forzare la loro impostazione in primo piano senza il tuo controllo."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"impostazione compatibilità schermo"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Consente all\'applicazione di controllare la modalità di compatibilità dello schermo di altre applicazioni. Le applicazioni dannose potrebbero disturbare il comportamento di altre applicazioni."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"attivazione debug delle applicazioni"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Consente all\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose potrebbero farne uso per terminare altre applicazioni."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Consente all\'applicazione di verificare se un pacchetto è installabile."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associazione a verifica pacchetto"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Avvia Wi-Fi Direct. Verrà disattivato il client/hotspot Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Avvio di Wi-Fi Direct non riuscito."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct è attivo"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocca per le impostazioni"</string>
<string name="accept" msgid="1645267259272829559">"Accetto"</string>
<string name="decline" msgid="2112225451706137894">"Rifiuto"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invito inviato"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"A:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Inserisci il PIN richiesto:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct è attivo"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocca per le impostazioni"</string>
<string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Applicazione sconosciuta"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 69d506e..c1d7d82 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"מאפשר ליישום להעביר משימות לחזית ולרקע. יישומים זדוניים עלולים לאלץ את עצמם לעבור לחזית ללא שליטה מצדך."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"הגדרת תאימות מסך"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"מאפשר ליישום לשלוט במצב תאימות המסך של יישומים אחרים. יישומים זדוניים עלולים לפגוע בהתנהגות של יישומים אחרים."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"הפעלה של ניקוי באגים ביישומים"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"הרשאה זו מאפשרת ליישום להפעיל ניקוי באגים עבור יישום אחר. יישומים זדוניים עלולים להשתמש באפשרות זו כדי לסגור יישומים אחרים."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"שנה את הגדרות ממשק המשתמש שלך"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"מאפשר ליישום לאמת שחבילה ניתנת להתקנה."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"הכפפה למאמת חבילה"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"האם ברצונך שהדפדפן יזכור סיסמה זו?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"לא כעת"</string>
<string name="save_password_remember" msgid="6491879678996749466">"זכור"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ישיר"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"הפעל Wi-Fi ישיר. פעולה זו תכבה את הלקוח/הנקודה החמה של ה-Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"לא ניתן להפעיל Wi-Fi ישיר"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ישיר מופעל"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"גע עבור הגדרות"</string>
<string name="accept" msgid="1645267259272829559">"קבל"</string>
<string name="decline" msgid="2112225451706137894">"דחה"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ההזמנה נשלחה"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"אל:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"הקלד את קוד ה-PIN הנדרש."</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ישיר מופעל"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"גע עבור הגדרות"</string>
<string name="select_character" msgid="3365550120617701745">"הוסף תו"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"יישום לא ידוע"</string>
<string name="sms_control_title" msgid="7296612781128917719">"שולח הודעות SMS"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index cb958e4..b3476db 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。この許可を悪意のあるアプリに利用されると、悪意のあるアプリが強制的に優先される恐れがあります。"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"実行中のアプリの停止"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"タスクの削除とアプリの終了をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリの動作が妨害される恐れがあります。"</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"画面互換性の設定"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"他のアプリの画面互換性モードをコントロールすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリの動作が中断される恐れがあります。"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"アプリのデバッグの有効化"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"別のアプリをデバッグモードにすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリが強制終了される恐れがあります。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"パッケージがインストール可能かどうか確認することをアプリに許可します。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"パッケージベリファイアにバインド"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"このパスワードをブラウザで保存しますか?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"今は保存しない"</string>
<string name="save_password_remember" msgid="6491879678996749466">"保存"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directを開始します。これによりWi-Fiクライアント/アクセスポイントがOFFになります。"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directを開始できませんでした。"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi DirectはONです"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"設定を表示するにはタップしてください"</string>
<string name="accept" msgid="1645267259272829559">"同意する"</string>
<string name="decline" msgid="2112225451706137894">"同意しない"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"招待状を送信しました"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"必要なPINを入力してください:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi DirectはONです"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"設定を表示するにはタップしてください"</string>
<string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"不明なアプリ"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 216ac76..aeca1ed 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"앱이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"실행 중인 앱 중지"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"애플리케이션이 작업을 삭제하거나 다른 애플리케이션을 중지시킬 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"화면 호환성 설정"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"앱이 다른 애플리케이션의 화면 호환성 모드를 제어할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"앱 디버깅 사용"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"애플리케이션이 다른 애플리케이션에 대해 디버깅을 사용할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션을 중지시킬 수 있습니다."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"앱이 패키지가 설치 가능한지 확인할 수 있도록 허용합니다."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"패키지 인증 연결"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string>
<string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct 작업을 시작합니다. 이 작업을 하면 Wi-Fi 클라이언트/핫스팟 작업이 중지됩니다."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct를 시작하지 못했습니다."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 켜짐"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"설정으로 이동하려면 터치하세요."</string>
<string name="accept" msgid="1645267259272829559">"동의"</string>
<string name="decline" msgid="2112225451706137894">"거부"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"초대장을 보냈습니다."</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"받는사람:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"필수 PIN 입력:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 켜짐"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"설정으로 이동하려면 터치하세요."</string>
<string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"알 수 없는 앱"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 7f0370f..739dca8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Leidžiama programai užduotis perkelti į priekinį planą ir į foną. Kenkėjiškos programos gali priverstinai persikelti į priekį be jūsų įsikišimo."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"sustabdyti vykdomas programas"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Leidžiama programai pašalinti užduotis ir panaikinti jų programas. Kenkėjiškos programos gali trikdyti kitų programų veikimą."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nustatyti ekrano suderinamumo režimą"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Programai leidžiama valdyti kitų programų ekrano suderinamumo režimą. Kenkėjiškos programos gali kliudyti veikti kitoms programoms."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"įgalinti programos derinimą"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Leidžiama programai įjungti kitos programos derinimą. Kenkėjiškos programos gali tai naudoti, kad išjungtų kitas programas."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"keisti UI nustatymus"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leidžiama programai patikrinti, ar paketą galima įdiegti."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"susaistyti su paketo tikrinimo programa"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Ar norite, kad naršyklė atsimintų šį slaptažodį?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne dabar"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Atsiminti"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Paleiskite „Wi-Fi Direct“. Bus išjungta „Wi-Fi“ programa / viešosios interneto prieigos taškas."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nepavyko paleisti „Wi-Fi Direct“."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"„Wi-Fi Direct“ įjungta"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Jei norite peržiūrėti nustatymus, palieskite"</string>
<string name="accept" msgid="1645267259272829559">"Sutikti"</string>
<string name="decline" msgid="2112225451706137894">"Atmesti"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pakvietimas išsiųstas"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Skirta:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Įveskite reikiamą PIN kodą:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kodas:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"„Wi-Fi Direct“ įjungta"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Jei norite peržiūrėti nustatymus, palieskite"</string>
<string name="select_character" msgid="3365550120617701745">"Įterpti simbolį"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Nežinoma programa"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS pranešimų siuntimas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a052481..c36434c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ļauj lietotnei pārvietot uzdevumus priekšplānā un fonā. Ļaunprātīgas lietotnes var tikt izvirzītas priekšplānā bez jūsu vadības."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"apturēt izmantoto lietotņu darbību"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Ļauj lietotnei noņemt uzdevumus un pārtraukt to lietotņu darbību. Ļaunprātīgas lietotnes var traucēt citu lietotņu darbību."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Ekrāna saderības noteikšana"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ļauj lietotnei kontrolēt citu lietotņu ekrāna saderības režīmu. Ļaunprātīgas lietojumprogrammas var mainīt citu lietojumprogrammu darbību."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"iespējot lietotnes atkļūdošanu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ļauj lietotnei ieslēgt citas lietotnes atkļūdošanu. Ļaunprātīgas lietotnes to var izmantot, lai pārtrauktu citu lietotņu darbību."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"mainīt lietotāja saskarnes iestatījumus"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ļauj lietotnei verificēt, vai pakotne ir instalējama."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"saistīšana ar pakotnes verificētāju"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Vai vēlaties, lai pārlūkprogrammā tiktu saglabāta šī parole?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne tagad"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Atcerēties"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Palaist programmu Wi-Fi Direct. Tādējādi tiks izslēgta Wi-Fi klienta/tīklāja darbība."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nevarēja palaist programmu Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ir ieslēgts"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pieskarieties, lai piekļūtu iestatījumiem."</string>
<string name="accept" msgid="1645267259272829559">"Piekrist"</string>
<string name="decline" msgid="2112225451706137894">"Noraidīt"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Ielūgums ir nosūtīts."</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Kam:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ierakstiet pieprasīto PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ir ieslēgts"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pieskarieties, lai piekļūtu iestatījumiem."</string>
<string name="select_character" msgid="3365550120617701745">"Ievietojiet rakstzīmi"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Nezināma lietotne"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Īsziņu sūtīšana"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index f6189f2..6d0f5fd 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Membenarkan apl untuk memindahkan tugasan ke latar depan dan latar belakang. Apl hasad boleh memaksa diri mereka ke hadapan tanpa kawalan anda."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"hentikan apl yang sedang dijalankan"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Membenarkan apl untuk mengalih keluar tugasan dan melupuskan aplnya. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"tetapkan keserasian skrin"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Membenarkan apl mengawal mod keserasian skrin aplikasi lain. Aplikasi hasad mungkin mematahkan kelakuan aplikasi lain."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"dayakan penyahpepijatan apl"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Membenarkan apl untuk menghidupkan penyahpepijatan untuk apl lain. Apl hasad boleh menggunakannya untuk menghapuskan apl lain."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"tukar tetapan UI anda"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Membenarkan apl untuk mengesahkan bahawa pakej boleh dipasang."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ikat kepada pengesah pakej"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Adakah anda mahu penyemak imbas mengingati kata laluan ini?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Bukan sekarang"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Mulakan Wi-Fi Langsung. Hal ini akan mematikan pengendalian klien/liputan Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulakan Wi-Fi Langsung."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct dihidupkan"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk tetapan"</string>
<string name="accept" msgid="1645267259272829559">"Terima"</string>
<string name="decline" msgid="2112225451706137894">"Tolak"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Jemputan dihantar"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Taipkan PIN yang diperlukan:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct dihidupkan"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk tetapan"</string>
<string name="select_character" msgid="3365550120617701745">"Masukkan aksara"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tidak diketahui"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Menghantar mesej SMS"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e03b735..41ff046 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Ondsinnede apper kan tvinge seg frem til forgrunnen utenfor din kontroll."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"angi skjermkompatibilitet"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Lar appen kontrollere modus for skjermkompatibilitet i andre apper. Skadelige apper kan ødelegge funksjoner i andre apper."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere feilsøking av app"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lar appen slå av feilsøking for andre apper. Ondsinnede apper kan bruke dette til å avslutte andre apper."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lar appen bekrefte om en pakke kan installeres."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en pakkeverifikator"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"tilgang til serielle porter"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette deaktiverer Wi-Fi-klienten/-sonen."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kunne ikke starte Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slått på"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Berør for å se innstillinger"</string>
<string name="accept" msgid="1645267259272829559">"Godta"</string>
<string name="decline" msgid="2112225451706137894">"Avslå"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitasjonen er sendt"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv inn påkrevd PIN-kode:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slått på"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Berør for å se innstillinger"</string>
<string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukjent app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3a43b8e..8e5e8bc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. Schadelijke apps kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"schermcompatibiliteit instellen"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Toestaan dat de app de schermcompatibiliteitsmodus van andere apps beheert. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"foutopsporing in apps inschakelen"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Hiermee kan de app de foutopsporing voor een andere app inschakelen. Schadelijke apps kunnen dit gebruiken om andere apps af te sluiten."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
@@ -760,6 +762,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Hiermee kan de app controleren of een pakket kan worden geïnstalleerd."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"koppelen aan pakketcontroleprogramma"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string>
+ <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externe toegang tot inhoudsproviders"</string>
+ <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Hiermee kan de houder toegang krijgen tot inhoudsproviders via de shell. Nooit vereist voor normale apps."</string>
<string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
@@ -972,6 +978,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wifi Direct starten. Hierdoor wordt de wifi-client/hotspot uitgeschakeld."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kan Wifi Direct niet starten."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is actief"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Aanraken voor instellingen"</string>
<string name="accept" msgid="1645267259272829559">"Accepteren"</string>
<string name="decline" msgid="2112225451706137894">"Weigeren"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging verzonden"</string>
@@ -980,8 +988,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Naar:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer de gewenste pincode in:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pincode"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is actief"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Aanraken voor instellingen"</string>
<string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekende app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e73f7d6..694ed75 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pozwala aplikacji na przenoszenie zadań między tłem i pierwszym planem. Złośliwe aplikacje mogą wymusić przeniesienie się na pierwszy plan bez Twojego udziału."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ustaw zgodność ekranu"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych programów."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"włączenie debugowania aplikacji"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Złośliwe aplikacje mogą to wykorzystać do kończenia pracy innych programów."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pozwala aplikacji na zweryfikowanie, czy pakiet można zainstalować."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"powiązanie z weryfikatorem pakietów"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Uruchom Wi-Fi Direct. Spowoduje to wyłączenie klienta lub punktu dostępu Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nie można uruchomić Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct włączone"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotknij, aby zmienić ustawienia"</string>
<string name="accept" msgid="1645267259272829559">"Akceptuj"</string>
<string name="decline" msgid="2112225451706137894">"Odrzuć"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Wysłano zaproszenie"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Do:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Wpisz wymagany kod PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Kod PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct włączone"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotknij, aby zmienić ustawienia"</string>
<string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Nieznana aplikacja"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 800013d..3fa89d3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite à aplicação mover tarefas para primeiro e segundo plano. As aplicações maliciosas podem impor-se em primeiro plano sem o controlo do utilizador."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir compatibilidade de ecrã"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que a aplicação controle o modo de compatibilidade de ecrã de outras aplicações. As aplicações maliciosas poderão afetar o comportamento de outras aplicações."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração da aplicação"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que a aplicação ative a depuração para outra aplicação. As aplicações maliciosas podem utilizar isto para eliminar outras aplicações."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que a aplicação verifique se um pacote é instalável."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacotes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Esta opção desativará o cliente/zona Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"O Wi-Fi Direct está ativado"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toque para aceder às definições"</string>
<string name="accept" msgid="1645267259272829559">"Aceitar"</string>
<string name="decline" msgid="2112225451706137894">"Recusar"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduza o PIN solicitado:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"O Wi-Fi Direct está ativado"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toque para aceder às definições"</string>
<string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicação desconhecida"</string>
<string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c907929..d99bc60 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que o aplicativo mova tarefas para o primeiro plano e para o plano de fundo. Aplicativos maliciosos podem forçar-se para a primeiro plano sem que você tenha controle sobre a ação."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"parar os aplicativos em execução"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que um aplicativo remova tarefas e elimine seus aplicativos. Aplicativos maliciosos podem interferir no comportamento de outros aplicativos."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir a compatibilidade de tela"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que o aplicativo controle o modo de compatibilidade de tela de outros aplicativos. Aplicativos maliciosos podem interromper o comportamento de outros aplicativos."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração do aplicativo"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que o aplicativo ative a depuração para outro aplicativo. Aplicativos maliciosos podem usar esse recurso para cancelar outros aplicativos."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que o aplicativo verifique se um pacote pode ser instalado."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacote"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para aplicativos normais."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para acessar configurações"</string>
<string name="accept" msgid="1645267259272829559">"Aceitar"</string>
<string name="decline" msgid="2112225451706137894">"Recusar"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para acessar configurações"</string>
<string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicativo desconhecido"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index bc8d4fb..5b8efa6 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -278,6 +278,10 @@
<skip />
<!-- no translation found for permdesc_removeTasks (1394714352062635493) -->
<skip />
+ <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+ <skip />
+ <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+ <skip />
<!-- no translation found for permlab_setDebugApp (3022107198686584052) -->
<skip />
<!-- no translation found for permdesc_setDebugApp (4474512416299013256) -->
@@ -1147,6 +1151,14 @@
<skip />
<!-- no translation found for permdesc_bindPackageVerifier (3180741773233862126) -->
<skip />
+ <!-- no translation found for permlab_serialPort (546083327654631076) -->
+ <skip />
+ <!-- no translation found for permdesc_serialPort (2991639985224598193) -->
+ <skip />
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Vulais Vus ch\'il navigatur memorisescha quest pled-clav?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Betg ussa"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Memorisar"</string>
@@ -1416,6 +1428,10 @@
<skip />
<!-- no translation found for wifi_p2p_failed_message (3763669677935623084) -->
<skip />
+ <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
+ <skip />
+ <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
+ <skip />
<!-- no translation found for accept (1645267259272829559) -->
<skip />
<!-- no translation found for decline (2112225451706137894) -->
@@ -1432,10 +1448,6 @@
<skip />
<!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
<skip />
- <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
- <skip />
- <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
- <skip />
<string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string>
<!-- no translation found for sms_control_default_app_name (3058577482636640465) -->
<skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ecee96d..d870d58 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite aplicaţiei să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău intenţionate pot să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"oprire aplicaţii care rulează"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite aplicaţiei să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setaţi compatibilitatea ecranului"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite aplicaţiei să controleze modul de compatibilitate a ecranului pentru alte aplicaţii. Aplicaţiile rău intenţionate pot afecta comportamentul altor aplicaţii."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activare depanare aplicaţie"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite aplicaţiei să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite aplicaţiei să verifice dacă un pachet poate fi instalat."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"conectare la un verificator de pachete"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Doriţi ca browserul să reţină această parolă?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeţi pentru setări"</string>
<string name="accept" msgid="1645267259272829559">"Acceptaţi"</string>
<string name="decline" msgid="2112225451706137894">"Refuzaţi"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitaţia a fost trimisă."</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Către:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeţi pentru setări"</string>
<string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicaţie necunoscută"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7b95291..0b63de1 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Приложение сможет перемещать задачи в режим активного или фонового выполнения. Вредоносные программы смогут переводить себя в активный режим без вашего ведома."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"остановка запущенных приложений"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Приложение сможет удалять задачи и собственные программы. Вредоносное ПО при этом сможет нарушать работу других приложений."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Установка режима совместимости"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Приложение сможет управлять режимом совместимости экрана других приложений. Вредоносное ПО может привести к сбоям в работе других программ."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"включение отладки приложений"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Приложение сможет включать отладку для другой программы. Вредоносное ПО сможет таким образом останавливать работу других приложений."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменять настройки пользовательского интерфейса"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Приложение сможет проверять возможность установки пакетов."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"связываться с верификатором пакетов"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"доступ к последовательным портам"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Вы хотите, чтобы браузер запомнил этот пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сейчас"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Начать соединение через Wi-Fi Direct. Модуль Wi-Fi будет отключен."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не удалось запустить Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct включен"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Нажмите, чтобы открыть настройки"</string>
<string name="accept" msgid="1645267259272829559">"Принять"</string>
<string name="decline" msgid="2112225451706137894">"Отклонить"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Приглашение отправлено"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введите PIN-код:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct включен"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Нажмите, чтобы открыть настройки"</string>
<string name="select_character" msgid="3365550120617701745">"Введите символ"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестное приложение"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index aafaa9e..df25ac7 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikácii presúvať úlohy do popredia a pozadia. Škodlivé aplikácie sa môžu pretlačiť do popredia bez vášho vedomia."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastaviť kompatibilitu obrazovky"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Umožňuje aplikácii ovládať režim kompatibility obrazovky v ostatných aplikáciách. Škodlivé aplikácie môžu narušiť správanie ostatných aplikácií."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"povoliť ladenie aplikácií"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikácii zapnúť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikácii overiť, či je možné balík nainštalovať."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"naviazať na overovateľa balíka"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prehliadač zapamätal toto heslo?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Teraz nie"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamätať"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi-Fi"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustiť priame pripojenie siete Wi-Fi. Táto možnosť vypne sieť Wi-Fi v režime klient alebo hotspot."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Priame pripojenie siete Wi-Fi sa nepodarilo spustiť"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Priame pripojenie siete Wi-Fi je zapnuté"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavenia otvoríte dotykom"</string>
<string name="accept" msgid="1645267259272829559">"Prijať"</string>
<string name="decline" msgid="2112225451706137894">"Odmietnuť"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka bola odoslaná"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadajte požadovaný kód PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Priame pripojenie siete Wi-Fi je zapnuté"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavenia otvoríte dotykom"</string>
<string name="select_character" msgid="3365550120617701745">"Vkladanie znakov"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznáma aplikácia"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Odosielanie správ SMS"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index aa98c80..88d02ab 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Programu omogoča premikanje opravil v ospredje in ozadje. Zlonamerni programi se lahko brez vašega nadzora vsilijo v ospredje."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavitev združljivosti zaslona"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Programu omogoča nadzor združljivostnega načina zaslona drugih programov. Zlonamerni programi lahko prekinejo delovanje drugih programov."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"omogočanje iskanja in odpravljanja napak v programu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Programu omogoča vklop funkcije za odpravljanje napak za drug program. Zlonamerni programi lahko to uporabijo za zapiranje drugih programov."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"spreminjanje nastavitev UV"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Programu omogoča, da preveri, ali je paket mogoče namestiti."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"poveži s preverjanjem paketov"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne programe."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Ali želite, da si brskalnik zapomni to geslo?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne zdaj"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapomni si"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Zaženite Wi-Fi Direct. S tem boste izklopili odjemalca/dostopno točko Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string>
<string name="accept" msgid="1645267259272829559">"Sprejmi"</string>
<string name="decline" msgid="2112225451706137894">"Zavrni"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Za:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Vnesite zahtevano kodo PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string>
<string name="select_character" msgid="3365550120617701745">"Vstavljanje znaka"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznan program"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Pošiljanje sporočil SMS"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7ba8503..7d0b9f5 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозвољава апликацији да премешта задатке у први план и у позадину. Злонамерне апликације могу на тај начин да принудно пређу у први план без ваше контроле."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"подешавање компатибилности екрана"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дозвољава апликацији да контролише режим компатибилности екрана других апликација. Злонамерне апликације могу да угрозе понашање других апликација."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"омогућавање отклањања грешака у апликацији"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозвољава апликацији да укључи уклањање грешака за другу апликацију. Злонамерне апликације могу то да искористе за онемогућавање других апликација."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промена подешавања корисничког интерфејса"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозвољава апликацији да верификује да ли је пакет могуће инсталирати."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обавезивање на верификатор пакета"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Желите ли да прегледач запамти ову лозинку?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сада"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запамти"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Покрените Wi-Fi Direct. Тиме ћете искључити клијента/хотспот за Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Није могуће покренути Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct је укључен"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Додирните за подешавања"</string>
<string name="accept" msgid="1645267259272829559">"Прихвати"</string>
<string name="decline" msgid="2112225451706137894">"Одбиј"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Позивница је послата"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Коме:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Унесите потребни PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct је укључен"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Додирните за подешавања"</string>
<string name="select_character" msgid="3365550120617701745">"Уметање знака"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Непозната апликација"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Слање SMS порука"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 4d3cea5..ee6295f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillåter att appen flyttar uppgifter till förgrunden eller bakgrunden. Skadliga appar kan tvinga sig till förgrunden utan att du kan styra det."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"avsluta appar som körs"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillåter att appen tar bort uppgifter och avslutar appar. Skadliga appar kan störa funktionen i andra appar."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ange skärmkompatibilitet"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Tillåter att appen styr skärmkompatibilitetsläget i andra appar. Skadliga appar kan störa andra appars funktion."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivera felsökning av appar"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillåter att appen aktiverar felsökning för en annan app. Skadliga appar kan använda detta för att avsluta andra appar."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillåter att appen kontrollerar om ett paket går att installera."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"binda till en paketverifierare"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Starta direkt Wi-Fi-användning. Detta inaktiverar Wi-Fi-användning med klient/trådlös surfzon."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Det gick inte att starta Wi-Fi direkt."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct är aktiverat"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryck om du vill visa inställningar"</string>
<string name="accept" msgid="1645267259272829559">"Godkänn"</string>
<string name="decline" msgid="2112225451706137894">"Avvisa"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Inbjudan har skickats"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Till:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ange den obligatoriska PIN-koden:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kod:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct är aktiverat"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryck om du vill visa inställningar"</string>
<string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Okänd app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a9a8679..70b7c2e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Inaruhusu programu kusongesha kazi kwenye mandhari-mbele na mandhari-nyuma. Programu hasidi zinaweza kujilazimisha mbele bila udhibiti wako."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"weka utangamano wa skrini"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Huruhusu programu kudhibiti hali ya utangamano wa skrini ya programu zingine. Programu hasidi zinaweza kuvunja mwenendo wa programu zingine."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"wezesha utatuaji wa programu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Huruhusu programu kuwasha kueua cha programu nyingine. Programu hasidi huenda zikatumia hii ili kuua programu nyingine."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"badilisha mipangilio yako ya onyesho"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Inaruhusu programu kuthibitisha kuwa furushi linaweza kusakinishwa."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Funga kwa kithibitishaji cha furushi"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Unataka kuvinjari ili ukumbuke nenosiri hili?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Si Sasa"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Mtandao hewa Moja kwa moja"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Anzisha Wi-Fi Moja kwa Moja. Hii itazima mteja/mtandao-hewa wa Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Haikuweza kuanzisha Wi-Fi Moja kwa Moja."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ya Moja kwa Moja imewashwa"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Gusa kwa ajili ya mipangilio"</string>
<string name="accept" msgid="1645267259272829559">"Kubali"</string>
<string name="decline" msgid="2112225451706137894">"Kataa"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Mwaliko umetumwa"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Kwa:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Charaza PIN inayohitajika:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ya Moja kwa Moja imewashwa"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Gusa kwa ajili ya mipangilio"</string>
<string name="select_character" msgid="3365550120617701745">"Ingiza kibambo"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Programu isiyojulikana"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Inatuma ujumbe wa SMS"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 6a8431c..0acd104 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"อนุญาตให้แอปพลิเคชันย้ายงานไปยังส่วนหน้าและพื้นหลัง แอปพลิเคชันที่เป็นอันตรายอาจบังคับตัวเองให้ไปที่ส่วนหน้าโดยไม่มีการควบคุมจากคุณ"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"หยุดแอปพลิเคชันที่ทำงานอยู่"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"อนุญาตให้แอปพลิเคชันลบงานออกและยุติแอปพลิเคชันต่างๆ ของงานนั้น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นๆ ทำงานได้ไม่ถูกต้อง"</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ตั้งค่าความเข้ากันได้ของหน้าจอ"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"อนุญาตให้แอปพลิเคชันควบคุมโหมดความเข้ากันได้ของหน้าจอของแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นทำงานผิดพลาด"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"เปิดใช้งานการแก้ไขบกพร่องของแอปพลิเคชัน"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"อนุญาตให้แอปพลิเคชันเปิดการแก้ไขข้อบกพร่องสำหรับแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติการทำงานของแอปพลิเคชันอื่นๆ ได้"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"เปลี่ยนการตั้งค่า UI ของคุณ"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"คุณต้องการให้เบราว์เซอร์จำรหัสผ่านนี้หรือไม่"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"ยังไม่ใช้งานขณะนี้"</string>
<string name="save_password_remember" msgid="6491879678996749466">"จำไว้"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"เริ่มการทำงาน WiFi Direct ซึ่งจะเป็นการปิดการทำงาน WiFi ไคลเอ็นต์/ฮอตสปอต"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ไม่สามารถเริ่ม WiFi Direct ได้"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"เปิด Wi-Fi Direct อยู่"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"แตะเพื่อตั้งค่า"</string>
<string name="accept" msgid="1645267259272829559">"ยอมรับ"</string>
<string name="decline" msgid="2112225451706137894">"ปฏิเสธ"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ส่งข้อความเชิญแล้ว"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"ถึง:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"พิมพ์ PIN ที่ต้องการ:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"เปิด Wi-Fi Direct อยู่"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"แตะเพื่อตั้งค่า"</string>
<string name="select_character" msgid="3365550120617701745">"ใส่อักขระ"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"แอปพลิเคชันที่ไม่รู้จัก"</string>
<string name="sms_control_title" msgid="7296612781128917719">"กำลังส่งข้อความ SMS"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 04635c8..3bde5c8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pinapayagan ang app na ilipat ang mga gawain sa foreground at background. Maaaring puwersahin ng nakakahamak na apps ang mga sarili nito sa harapan nang wala ang iyong pagkontrol."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"ihinto ang pagpapatakbo ng apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Pinapayagan ang app na mag-alis ng mga gawain at i-off ang apps nito. Maaaring maantala ng nakakahamak na apps ang pagkilos ng iba pang apps."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"itakda ang pagkakatugma ng screen"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pinapayagan ang app na kontrolin ang mode ng pagkakatugma ng screen ng iba pang mga application. Maaaring sirain ng mga nakakahamak na application ang pag-uugali ng iba pang mga application."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"paganahin ang pag-debug ng app"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pinapayagan ang app na i-on ang pag-debug para sa isa pang app. Maaari itong gamitin ng nakakahamak na apps upang i-off ang iba pang apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"baguhin ang iyong mga setting ng UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pinapayagan ang app na i-verify kung ang isang package ay nai-install."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sumailalim sa taga-verify ng package"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Gusto mo bang tandaan ng browser ang password na ito?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Hindi ngayon"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Tandaan"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Simulan ang Wi-Fi Direct. I-o-off nito ang client/hotspot ng Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Hindi masimulan ang Wi-Fi Direct"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Ang Wi-Fi Direct ay naka-on"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pindutin para sa mga setting"</string>
<string name="accept" msgid="1645267259272829559">"Tanggapin"</string>
<string name="decline" msgid="2112225451706137894">"Tanggihan"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Naipadala ang imbitasyon"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Kay:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"I-type ang kinakailangang PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Ang Wi-Fi Direct ay naka-on"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pindutin para sa mga setting"</string>
<string name="select_character" msgid="3365550120617701745">"Magpasok ng character"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Hindi kilalang app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Nagpapadala ng mga SMS na mensahe"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bfe9c0a..1b27dbd 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında ön plana taşıyabilir."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ekran uyumluluğunu ayarla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Uygulamaya diğer uygulamaların ekran uyumluluk modunu denetleme izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışma şeklini bozabilir."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"uygulama hata ayıklamayı etkinleştir"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Uygulamaya, başka bir uygulama için hata ayıklamayı açma izni verir. Kötü amaçlı uygulamalar diğer uygulamaları kaldırmak için bunu kullanabilir."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Uygulamaya, bir paketin yüklenebilir olduğunu doğrulama izni verir."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paket doğrulayıcıya bağlan"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Şimdi değil"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantıyı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan bağlantı başlatılamadı."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string>
<string name="accept" msgid="1645267259272829559">"Kabul et"</string>
<string name="decline" msgid="2112225451706137894">"Reddet"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Davetiye gönderildi"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Alıcı:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gerekli PIN\'i yazın:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string>
<string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Bilinmeyen uygulama"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6708893..eb22ec8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Шкідливі програми можуть примусово ставати активними без вашого відома."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"установити сумісність екрана"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дозволяє програмі контролювати режим сумісності екрана інших програм. Шкідливі програми можуть переривати роботу інших програм."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"вмикати налагодження програми"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозволяє програмі вмикати налагодження для іншої програми. Шкідливі програми можуть використовувати це для примусового припинення роботи інших програм."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змін. налашт. інтерф. кор."</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволяє програмі перевіряти можливість встановлення пакета."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прив’язуватися до програми перевірки пакетів"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Хочете, щоб переглядач запам\'ятав цей пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не зараз"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запам\'ятати"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Запустити Wi-Fi Direct. Це вимкне з’єднання Wi-Fi клієнт/точка доступу."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не вдалося запустити Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct увімкнено"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Торкніться, щоб побачити налаштування"</string>
<string name="accept" msgid="1645267259272829559">"Прийняти"</string>
<string name="decline" msgid="2112225451706137894">"Відхилити"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрошення надіслано"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введіть потрібний PIN-код:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct увімкнено"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Торкніться, щоб побачити налаштування"</string>
<string name="select_character" msgid="3365550120617701745">"Вставл-ня символу"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Невідома програма"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Надсил. SMS повідомлень"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 6da402ce..583d216 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Cho phép ứng dụng di chuyển công việc sang nền trước và nền sau. Ứng dụng độc hại có thể tự hiển thị ở nền trước mà không chịu sự kiểm soát của bạn."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"dừng các ứng dụng đang chạy"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Cho phép ứng dụng xóa công việc và loại bỏ các ứng dụng của chúng. Ứng dụng độc hại có thể làm gián đoạn hoạt động của các ứng dụng khác."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"đặt độ tương thích màn hình"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Cho phép ứng dụng kiểm soát chế độ tương thích màn hình của ứng dụng khác. Các ứng dụng độc hại có thể phá vỡ hoạt động của các ứng dụng khác."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"bật gỡ lỗi ứng dụng"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Cho phép ứng dụng bật gỡ lỗi cho một ứng dụng khác. Ứng dụng độc hại có thể sử dụng quyền này để loại bỏ những ứng dụng khác."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"thay đổi cài đặt giao diện người dùng của bạn"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Cho phép ứng dụng xác minh gói có thể cài đặt."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"liên kết với trình xác minh gói"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Bạn có muốn trình duyệt nhớ mật khẩu này không?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Không phải bây giờ"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Nhớ"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Khởi động Wi-Fi Direct. Việc này sẽ tắt hoạt động của ứng dụng khách/điểm phát sóng Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Không thể khởi động Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct được bật"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Chạm để cài đặt"</string>
<string name="accept" msgid="1645267259272829559">"Đồng ý"</string>
<string name="decline" msgid="2112225451706137894">"Từ chối"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Đã gửi thư mời"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Người nhận:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Nhập PIN bắt buộc:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Mã PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct được bật"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Chạm để cài đặt"</string>
<string name="select_character" msgid="3365550120617701745">"Chèn ký tự"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"Ứng dụng không xác định"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Đang gửi tin nhắn SMS"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6c40202..ca3c65c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"允许应用程序将任务移动到前台和后台。恶意应用程序可能会不受您的控制,强行让自己处于前台。"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"停止正在运行的应用程序"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"允许该应用程序删除任务并终止这些任务的应用程序。恶意应用程序可以籍此影响其他应用程序的行为。"</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"设置屏幕兼容性"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"允许应用程序控制其他应用程序的屏幕兼容模式。恶意应用程序可以籍此影响其他应用程序的行为。"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"启用应用程序调试"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"允许该应用程序对其他应用程序启用调试。恶意应用程序可以籍此终止其他的应用程序。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界面设置"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允许应用程序验证程序包是否可以安装。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"绑定到软件包验证程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许用户请求使用程序包验证程序。普通应用程序绝不需要此权限。"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"允许持有人使用 SerialManager API 访问串行端口。"</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string>
<string name="save_password_remember" msgid="6491879678996749466">"记住"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 Wi-Fi Direct。此操作将会关闭 Wi-Fi 客户端/热点。"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 Wi-Fi Direct。"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 Wi-Fi Direct"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string>
<string name="accept" msgid="1645267259272829559">"接受"</string>
<string name="decline" msgid="2112225451706137894">"拒绝"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀请已发送"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"收件人:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"键入所需的 PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 Wi-Fi Direct"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string>
<string name="select_character" msgid="3365550120617701745">"插入字符"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"未知应用程序"</string>
<string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 131c2f7..9b11c43 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"允許應用程式將工作移至前景或背景。請注意,惡意應用程式可能利用此功能自行移動至前景。"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"停止執行中的應用程式"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"允許應用程式移除工作並終止執行工作的應用程式。請注意,惡意應用程式可能利用此功能干擾其他應用程式的行為。"</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"設定螢幕相容性"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"允許應用程式控制其他應用程式的螢幕相容性模式。惡意應用程式可能藉此破壞其他應用程式的正常運作。"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"啟用應用程式偵錯"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"允許應用程式為其他程式開啟偵錯功能。提醒您,惡意應用程式可能會利用這個功能終止其他應用程式。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證是否可安裝特定套件。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"是否記住此密碼?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"現在不要"</string>
<string name="save_password_remember" msgid="6491879678996749466">"記住"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 WiFi Direct 作業,這會關閉 WiFi 用戶端/無線基地台作業。"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 WiFi Direct。"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"輕觸即可設定"</string>
<string name="accept" msgid="1645267259272829559">"接受"</string>
<string name="decline" msgid="2112225451706137894">"拒絕"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀請函已傳送"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"收件者:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"輕觸即可設定"</string>
<string name="select_character" msgid="3365550120617701745">"插入字元"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"不明的應用程式"</string>
<string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 56af9aa..8d02eff 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -215,6 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ivumela insiza ukuthi ihambise izenzo ziye ngaphambili kanye nasemumva. Izinsiza ezinobungozi zingaziphoqelela ukuth iziye phambili ngaphandle kokulawula kwakho."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ivumela uhlelo lokusebenza ukulawula imodi yokuhambelana kwesikrini kwezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezinonya zingase zephule ukuziphatha kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela insiza ilungise inkinga"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela insiza ukuthi ivule uhlelo lokulungisa lwenye insiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinsiza."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"shintsha izilungiselelo zakho ze-UI"</string>
@@ -760,6 +762,12 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string>
+ <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+ <skip />
+ <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Ingabe ufuna ukuba isiphequluli sikhumbule lephasiwedi?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Hha yi manje"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Khumbula"</string>
@@ -972,6 +980,8 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-WiFi Eqondile"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Qala ukusebenza kwe-WiFi Okuqondile. Lokhu kuzocima ikhasimende le-WiFi/Ukusebenza okwe-hotspot"</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Yehlulekile ukuqala i-Wi-Fi Ngqo"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ukuze uthole izilungiselelo"</string>
<string name="accept" msgid="1645267259272829559">"Yamukela"</string>
<string name="decline" msgid="2112225451706137894">"Nqaba"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Isimemo sithunyelwe"</string>
@@ -980,8 +990,6 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Ku:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Faka i-PIN edingekayo:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string>
- <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ukuze uthole izilungiselelo"</string>
<string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string>
<string name="sms_control_default_app_name" msgid="3058577482636640465">"insiza engaziwa"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0511b75..1eab01a 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -61,6 +61,25 @@
As of Honeycomb, blurring is not supported anymore. -->
<bool name="config_sf_slowBlur">true</bool>
+ <!-- Flag indicating that the media framework should allow changing
+ master volume stream and nothing else . -->
+ <bool name="config_useMasterVolume">false</bool>
+
+ <!-- Array of integer pairs controlling the rate at which the master volume changes
+ in response to volume up and down key events.
+ The first integer of each pair is compared against the current master volume
+ (in range 0 to 100).
+ The last pair with first integer <= the current volume is chosen,
+ and the second integer of the pair indicates the amount to increase the master volume
+ when volume up is pressed. -->
+ <integer-array name="config_masterVolumeRamp">
+ <item>0</item> <item>5</item> <!-- default: always increase volume by 5% -->
+ </integer-array>
+
+ <!-- Flag indicating whether the AUDIO_BECOMING_NOISY notification should
+ be sent during an change to the audio output device. -->
+ <bool name="config_sendAudioBecomingNoisy">true</bool>
+
<!-- The duration (in milliseconds) of a short animation. -->
<integer name="config_shortAnimTime">200</integer>
@@ -227,6 +246,13 @@
<item>4</item>
</integer-array>
+ <!-- If the DUN connection for this CDMA device supports more than just DUN -->
+ <!-- traffic you should list them here. -->
+ <!-- If this device is not CDMA this is ignored. If this list is empty on -->
+ <!-- a DUN-requiring CDMA device, the DUN APN will just support just DUN. -->
+ <string-array translatable="false" name="config_cdma_dun_supported_types">
+ </string-array>
+
<!-- String containing the apn value for tethering. May be overriden by secure settings
TETHER_DUN_APN. Value is a comma separated series of strings:
"name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
@@ -364,6 +390,12 @@
<string-array name="config_usbHostBlacklist" translatable="false">
</string-array>
+ <!-- List of paths to serial ports that are available to the serial manager.
+ for example, /dev/ttyUSB0
+ -->
+ <string-array translatable="false" name="config_serialPorts">
+ </string-array>
+
<!-- Vibrator pattern for feedback about a long screen/key press -->
<integer-array name="config_longPressVibePattern">
<item>0</item>
@@ -535,6 +567,9 @@
specified -->
<string name="default_wallpaper_component" translatable="false">@null</string>
+ <!-- True if WallpaperService is enabled -->
+ <bool name="config_enableWallpaperService">true</bool>
+
<!-- Component name of the service providing network location support. -->
<string name="config_networkLocationProvider" translatable="false">@null</string>
@@ -760,4 +795,10 @@
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+ <!-- Array of OEM specific USB mode override config.
+ OEM can override a certain USB mode depending on ro.bootmode.
+ Specify an array of below items to set override rule.
+ [bootmode]:[original USB mode]:[USB mode used]-->
+ <integer-array translatable="false" name="config_oemUsbModeOverride">
+ </integer-array>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1b91643..f347a4e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -234,6 +234,9 @@
<java-symbol type="bool" name="preferences_prefer_dual_pane" />
<java-symbol type="bool" name="skip_restoring_network_selection" />
<java-symbol type="bool" name="split_action_bar_is_narrow" />
+ <java-symbol type="bool" name="config_useMasterVolume" />
+ <java-symbol type="bool" name="config_enableWallpaperService" />
+ <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_longPressOnPowerBehavior" />
@@ -859,6 +862,8 @@
<java-symbol type="array" name="preloaded_drawables" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
+ <java-symbol type="array" name="config_masterVolumeRamp" />
+ <java-symbol type="array" name="config_cdma_dun_supported_types" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="ic_suggestions_add" />
@@ -1288,7 +1293,9 @@
<java-symbol type="array" name="config_tether_usb_regexs" />
<java-symbol type="array" name="config_tether_wifi_regexs" />
<java-symbol type="array" name="config_usbHostBlacklist" />
+ <java-symbol type="array" name="config_serialPorts" />
<java-symbol type="array" name="radioAttributes" />
+ <java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />
@@ -1432,6 +1439,7 @@
<java-symbol type="anim" name="push_down_out" />
<java-symbol type="anim" name="push_up_in" />
<java-symbol type="anim" name="push_up_out" />
+ <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
<java-symbol type="dimen" name="status_bar_icon_size" />
<java-symbol type="dimen" name="system_bar_icon_size" />
<java-symbol type="drawable" name="list_selector_pressed_holo_dark" />
@@ -1469,6 +1477,7 @@
<java-symbol type="string" name="usb_storage_stop_notification_title" />
<java-symbol type="string" name="usb_storage_stop_title" />
<java-symbol type="string" name="usb_storage_title" />
+ <java-symbol type="style" name="Animation.RecentApplications" />
<!-- ImfTest -->
<java-symbol type="layout" name="auto_complete_list" />
@@ -3488,4 +3497,12 @@
=============================================================== -->
<public type="attr" name="isolatedProcess" id="0x010103a7" />
+ <public type="attr" name="textDirection"/>
+
+ <public type="attr" name="paddingStart"/>
+ <public type="attr" name="paddingEnd"/>
+
+ <public type="attr" name="layout_marginStart"/>
+ <public type="attr" name="layout_marginEnd"/>
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dc45c408..3c1f50d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -532,6 +532,13 @@
tasks and kill their apps. Malicious apps may disrupt
the behavior of other apps.</string>
+ <!-- Title of an application permission, allowing control of app screen compatibility mode -->
+ <string name="permlab_setScreenCompatibility">set screen compatibility</string>
+ <!-- Description of an application permission, allowing control of app screen compatibility mode -->
+ <string name="permdesc_setScreenCompatibility">Allows the app to control the
+ screen compatibility mode of other applications. Malicious applications may
+ break the behavior of other applications.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_setDebugApp">enable app debugging</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2236,6 +2243,19 @@
<string name="permdesc_bindPackageVerifier">Allows the holder to make requests of
package verifiers. Should never be needed for normal apps.</string>
+ <!-- Title of an application permission which allows the application to access serial ports via the SerialManager. [CHAR LIMIT=40] -->
+ <string name="permlab_serialPort">access serial ports</string>
+ <!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_serialPort">Allows the holder to access serial ports using the SerialManager API.</string>
+
+ <!-- Title of an application permission which allows the holder to access content
+ providers from outside an ApplicationThread. [CHAR LIMIT=40] -->
+ <string name="permlab_accessContentProvidersExternally">access content providers externally</string>
+ <!-- Description of an application permission which allows the holder to access
+ content providers from outside an ApplicationThread. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_accessContentProvidersExternally">Allows the holder to access content
+ providers from the shell. Should never be needed for normal apps.</string>
+
<!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
<string name="save_password_message">Do you want the browser to remember this password?</string>
<!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
@@ -2696,10 +2716,11 @@
<!-- Do not translate. Default access point SSID used for tethering -->
<string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string>
- <!-- Wi-Fi p2p dialog title-->
<string name="wifi_p2p_dialog_title">Wi-Fi Direct</string>
<string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string>
<string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string>
+ <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string>
+ <string name="wifi_p2p_enabled_notification_message">Touch for settings</string>
<string name="accept">Accept</string>
<string name="decline">Decline</string>
@@ -2711,9 +2732,6 @@
<string name="wifi_p2p_enter_pin_message">Type the required PIN: </string>
<string name="wifi_p2p_show_pin_message">PIN: </string>
- <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string>
- <string name="wifi_p2p_enabled_notification_message">Touch for settings</string>
-
<!-- Name of the dialog that lets the user choose an accented character to insert -->
<string name="select_character">Insert character</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 571c4ad..610bad8 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -198,8 +198,10 @@
<!-- A special animation we can use for recent applications,
for devices that can support it (do alpha transformations). -->
<style name="Animation.RecentApplications">
- <item name="windowEnterAnimation">@anim/fade_in</item>
- <item name="windowExitAnimation">@anim/fade_out</item>
+ <item name="windowEnterAnimation">@anim/recents_fade_in</item>
+ <item name="windowShowAnimation">@anim/recents_fade_in</item>
+ <item name="windowExitAnimation">@anim/recents_fade_out</item>
+ <item name="windowHideAnimation">@anim/recents_fade_out</item>
</style>
<!-- A special animation value used internally for popup windows. -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 9819c54..9c1922f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -46,8 +46,7 @@
// create a new test suite
suite.setName("ConnectivityManagerWifiOnlyFunctionalTests");
String[] methodNames = {"testConnectToWifi", "testConnectToWifWithKnownAP",
- "testDisconnectWifi", "testDataConnectionOverAMWithWifi",
- "testDataConnectionWithWifiToAMToWifi", "testWifiStateChange"};
+ "testDisconnectWifi", "testWifiStateChange"};
Class<ConnectivityManagerMobileTest> testClass = ConnectivityManagerMobileTest.class;
for (String method: methodNames) {
suite.addTest(TestSuite.createTest(testClass, method));
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index a781472..76b702e 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -90,6 +90,7 @@
*/
@LargeTest
public void testWifiDownload() throws Exception {
+ mConnectionUtil.wifiTestInit();
assertTrue("Could not connect to wifi!", setDeviceWifiAndAirplaneMode(mSsid));
downloadFile();
}
@@ -143,6 +144,7 @@
*/
@LargeTest
public void testWifiUpload() throws Exception {
+ mConnectionUtil.wifiTestInit();
assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
uploadFile();
}
@@ -197,6 +199,7 @@
*/
@LargeTest
public void testWifiDownloadWithDownloadManager() throws Exception {
+ mConnectionUtil.wifiTestInit();
assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
downloadFileUsingDownloadManager();
}
@@ -286,6 +289,8 @@
* @return true if we successfully connect to mobile data.
*/
public boolean hasMobileData() {
+ assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
assertTrue("Not connected to mobile", mConnectionUtil.isConnectedToMobile());
assertFalse("Still connected to wifi.", mConnectionUtil.isConnectedToWifi());
return mConnectionUtil.hasData();
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index dfcbba9..7499f68 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -57,7 +57,7 @@
private static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; // 10 seconds
private static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
public static final int SHORT_TIMEOUT = 5 * 1000;
- public static final int LONG_TIMEOUT = 10 * 1000;
+ public static final int LONG_TIMEOUT = 120 * 1000; // 2 minutes
private ConnectivityReceiver mConnectivityReceiver = null;
private WifiReceiver mWifiReceiver = null;
private DownloadReceiver mDownloadReceiver = null;
@@ -118,8 +118,14 @@
initializeNetworkStates();
- mWifiManager.setWifiEnabled(true);
+ }
+
+ /**
+ * Additional initialization needed for wifi related tests.
+ */
+ public void wifiTestInit() {
+ mWifiManager.setWifiEnabled(true);
Log.v(LOG_TAG, "Clear Wifi before we start the test.");
sleep(SHORT_TIMEOUT);
removeConfiguredNetworksAndDisableWifi();
@@ -525,7 +531,7 @@
/**
* Connect to Wi-Fi with the given configuration.
* @param config
- * @return true if we ar connected to a given
+ * @return true if we are connected to a given AP.
*/
public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
// The SSID in the configuration is a pure string, need to convert it to a quoted string.
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index b81f774..88f3f34 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -22,7 +22,7 @@
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava littlemock
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java b/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java
index 4d65588..9015a6f 100644
--- a/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java
+++ b/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java
@@ -16,6 +16,8 @@
package android.net.http;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
import java.io.File;
import java.net.CacheRequest;
import java.net.CacheResponse;
@@ -30,6 +32,7 @@
public final class HttpResponseCacheTest extends TestCase {
private File cacheDir;
+ private MockWebServer server = new MockWebServer();
@Override public void setUp() throws Exception {
super.setUp();
@@ -39,6 +42,7 @@
@Override protected void tearDown() throws Exception {
ResponseCache.setDefault(null);
+ server.shutdown();
super.tearDown();
}
@@ -100,4 +104,32 @@
cache.delete();
assertNull(ResponseCache.getDefault());
}
+
+ /**
+ * Make sure that statistics tracking are wired all the way through the
+ * wrapper class. http://code.google.com/p/android/issues/detail?id=25418
+ */
+ public void testStatisticsTracking() throws Exception {
+ HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
+
+ server.enqueue(new MockResponse()
+ .addHeader("Cache-Control: max-age=60")
+ .setBody("A"));
+ server.play();
+
+ URLConnection c1 = server.getUrl("/").openConnection();
+ assertEquals('A', c1.getInputStream().read());
+ assertEquals(1, cache.getRequestCount());
+ assertEquals(1, cache.getNetworkCount());
+ assertEquals(0, cache.getHitCount());
+
+ URLConnection c2 = server.getUrl("/").openConnection();
+ assertEquals('A', c2.getInputStream().read());
+
+ URLConnection c3 = server.getUrl("/").openConnection();
+ assertEquals('A', c3.getInputStream().read());
+ assertEquals(3, cache.getRequestCount());
+ assertEquals(1, cache.getNetworkCount());
+ assertEquals(2, cache.getHitCount());
+ }
}
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index baf587e..f2eba23 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -16,6 +16,9 @@
package android.widget.focus;
+import static com.google.testing.littlemock.LittleMock.inOrder;
+import static com.google.testing.littlemock.LittleMock.mock;
+
import android.os.Handler;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
@@ -28,9 +31,7 @@
import android.widget.Button;
import com.android.frameworks.coretests.R;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.google.testing.littlemock.LittleMock.InOrder;
/**
* {@link RequestFocusTest} is set up to exercise cases where the views that
@@ -105,43 +106,47 @@
* This tests checks the case in which the first focusable View clears focus.
* In such a case the framework tries to give the focus to another View starting
* from the top. Hence, the framework will try to give focus to the view that
- * wants to clear its focus. From a client perspective, the view does not loose
- * focus after the call, therefore no callback for focus change should be invoked.
+ * wants to clear its focus.
*
* @throws Exception If an error occurs.
*/
@UiThreadTest
- public void testOnFocusChangeNotCalledIfFocusDoesNotMove() throws Exception {
+ public void testOnFocusChangeCallbackOrderWhenClearingFocusOfFirstFocusable()
+ throws Exception {
// Get the first focusable.
- Button button = mTopLeftButton;
+ Button clearingFocusButton = mTopLeftButton;
+ Button gainingFocusButton = mTopLeftButton;
- // Make sure that the button is the first focusable and focus it.
- button.getRootView().requestFocus(View.FOCUS_DOWN);
- assertTrue(button.hasFocus());
+ // Make sure that the clearing focus View is the first focusable.
+ View focusCandidate = clearingFocusButton.getRootView().getParent().focusSearch(null,
+ View.FOCUS_FORWARD);
+ assertSame("The clearing focus button is the first focusable.",
+ clearingFocusButton, focusCandidate);
+ assertSame("The gaining focus button is the first focusable.",
+ gainingFocusButton, focusCandidate);
- // Attach on focus change listener that should not be called.
- button.setOnFocusChangeListener(new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- throw new IllegalStateException("Unexpeced call to"
- + "OnFocusChangeListener#onFocusChange");
- }
- });
+ // Focus the clearing focus button.
+ clearingFocusButton.requestFocus();
+ assertTrue(clearingFocusButton.hasFocus());
- // Attach on global focus change listener that should not be called.
- button.getViewTreeObserver().addOnGlobalFocusChangeListener(
- new OnGlobalFocusChangeListener() {
- @Override
- public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- throw new IllegalStateException("Unexpeced call to"
- + "OnFocusChangeListener#onFocusChange");
- }
- });
+ // Register the invocation order checker.
+ CombinedListeners mock = mock(CombinedListeners.class);
+ clearingFocusButton.setOnFocusChangeListener(mock);
+ gainingFocusButton.setOnFocusChangeListener(mock);
+ clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(mock);
// Try to clear focus.
- button.clearFocus();
+ clearingFocusButton.clearFocus();
+
+ // Check that no callback was invoked since focus did not move.
+ InOrder inOrder = inOrder(mock);
+ inOrder.verify(mock).onFocusChange(clearingFocusButton, false);
+ inOrder.verify(mock).onGlobalFocusChanged(clearingFocusButton, gainingFocusButton);
+ inOrder.verify(mock).onFocusChange(gainingFocusButton, true);
}
+ public interface CombinedListeners extends OnFocusChangeListener, OnGlobalFocusChangeListener {}
+
/**
* This tests check whether the on focus change callbacks are invoked in
* the proper order when a View loses focus and the framework gives it to
@@ -150,12 +155,12 @@
* @throws Exception
*/
@UiThreadTest
- public void testOnFocusChangeCallbackOrder() throws Exception {
- // Get the first focusable.
+ public void testOnFocusChangeCallbackOrderWhenClearingFocusOfNotFirstFocusable()
+ throws Exception {
Button clearingFocusButton = mTopRightButton;
Button gainingFocusButton = mTopLeftButton;
- // Make sure that the clearing focus is not the first focusable.
+ // Make sure that the clearing focus View is not the first focusable.
View focusCandidate = clearingFocusButton.getRootView().getParent().focusSearch(null,
View.FOCUS_FORWARD);
assertNotSame("The clearing focus button is not the first focusable.",
@@ -168,77 +173,18 @@
assertTrue(clearingFocusButton.hasFocus());
// Register the invocation order checker.
- CallbackOrderChecker checker = new CallbackOrderChecker(clearingFocusButton,
- gainingFocusButton);
- clearingFocusButton.setOnFocusChangeListener(checker);
- gainingFocusButton.setOnFocusChangeListener(checker);
- clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(checker);
+ CombinedListeners mock = mock(CombinedListeners.class);
+ clearingFocusButton.setOnFocusChangeListener(mock);
+ gainingFocusButton.setOnFocusChangeListener(mock);
+ clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(mock);
// Try to clear focus.
clearingFocusButton.clearFocus();
// Check that no callback was invoked since focus did not move.
- checker.verify();
- }
-
- /**
- * This class check whether the focus change callback are invoked in order.
- */
- private class CallbackOrderChecker implements OnFocusChangeListener,
- OnGlobalFocusChangeListener {
-
- private class CallbackInvocation {
- final String mMethodName;
- final Object[] mArguments;
-
- CallbackInvocation(String methodName, Object[] arguments) {
- mMethodName = methodName;
- mArguments = arguments;
- }
- }
-
- private final View mClearingFocusView;
- private final View mGainingFocusView;
-
- private final List<CallbackInvocation> mInvocations = new ArrayList<CallbackInvocation>();
-
- public CallbackOrderChecker(View clearingFocusView, View gainingFocusView) {
- mClearingFocusView = clearingFocusView;
- mGainingFocusView = gainingFocusView;
- }
-
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- CallbackInvocation invocation = new CallbackInvocation(
- "OnFocusChangeListener#onFocusChange", new Object[] {view, hasFocus});
- mInvocations.add(invocation);
- }
-
- @Override
- public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- CallbackInvocation invocation = new CallbackInvocation(
- "OnFocusChangeListener#onFocusChange", new Object[] {oldFocus, newFocus});
- mInvocations.add(invocation);
- }
-
- public void verify() {
- assertSame("All focus change callback should be invoked.", 3, mInvocations.size());
- assertInvioked("Callback for View clearing focus explected.", 0,
- "OnFocusChangeListener#onFocusChange",
- new Object[] {mClearingFocusView, false});
- assertInvioked("Callback for View global focus change explected.", 1,
- "OnFocusChangeListener#onFocusChange", new Object[] {mClearingFocusView,
- mGainingFocusView});
- assertInvioked("Callback for View gaining focus explected.", 2,
- "OnFocusChangeListener#onFocusChange", new Object[] {mGainingFocusView, true});
- }
-
- private void assertInvioked(String message, int order, String methodName,
- Object[] arguments) {
- CallbackInvocation invocation = mInvocations.get(order);
- assertEquals(message, methodName, invocation.mMethodName);
- assertEquals(message, arguments[0], invocation.mArguments[0]);
- assertEquals(message, arguments[1], invocation.mArguments[1]);
- }
+ InOrder inOrder = inOrder(mock);
+ inOrder.verify(mock).onFocusChange(clearingFocusButton, false);
+ inOrder.verify(mock).onGlobalFocusChanged(clearingFocusButton, gainingFocusButton);
+ inOrder.verify(mock).onFocusChange(gainingFocusButton, true);
}
}
diff --git a/data/etc/android.hardware.bluetooth.xml b/data/etc/android.hardware.bluetooth.xml
new file mode 100644
index 0000000..4aa1744
--- /dev/null
+++ b/data/etc/android.hardware.bluetooth.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<!-- Adds the feature indicating support for the Bluetooth API -->
+<permissions>
+ <feature name="android.hardware.bluetooth" />
+</permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6cd07a3..8be1db2 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -158,6 +158,7 @@
<assign-permission name="android.permission.BACKUP" uid="shell" />
<assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" />
<assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" />
+ <assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 02d2f3d..ef38a60 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -51,6 +51,11 @@
$(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(font_symlink)
################################
+# On space-constrained devices, we include a subset of fonts:
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+droidsans_fallback_src := DroidSansFallback.ttf
+extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf
+else
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansEthiopic-Regular.ttf
LOCAL_SRC_FILES := $(LOCAL_MODULE)
@@ -59,15 +64,11 @@
LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
-################################
-ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallback.ttf
-extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf
-else
droidsans_fallback_src := DroidSansFallbackFull.ttf
extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf DroidSansEthiopic-Regular.ttf
endif # SMALLER_FONT_FOOTPRINT
+################################
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansFallback.ttf
LOCAL_SRC_FILES := $(droidsans_fallback_src)
@@ -81,3 +82,46 @@
font_symlink :=
droidsans_fallback_src :=
extra_droidsans_fonts :=
+
+################################
+# Build the rest font files as prebuilt.
+
+# $(1): The source file name in LOCAL_PATH.
+# It also serves as the module name and the dest file name.
+define build-one-font-module
+$(eval include $(CLEAR_VARS))\
+$(eval LOCAL_MODULE := $(1))\
+$(eval LOCAL_SRC_FILES := $(1))\
+$(eval LOCAL_MODULE_CLASS := ETC)\
+$(eval LOCAL_MODULE_TAGS := optional)\
+$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\
+$(eval include $(BUILD_PREBUILT))
+endef
+
+font_src_files := \
+ Roboto-Regular.ttf \
+ Roboto-Bold.ttf \
+ Roboto-Italic.ttf \
+ Roboto-BoldItalic.ttf \
+ DroidSansArabic.ttf \
+ DroidNaskh-Regular.ttf \
+ DroidSansHebrew-Regular.ttf \
+ DroidSansHebrew-Bold.ttf \
+ DroidSansThai.ttf \
+ DroidSerif-Regular.ttf \
+ DroidSerif-Bold.ttf \
+ DroidSerif-Italic.ttf \
+ DroidSerif-BoldItalic.ttf \
+ DroidSansMono.ttf \
+ DroidSansArmenian.ttf \
+ DroidSansGeorgian.ttf \
+ AndroidEmoji.ttf \
+ Clockopia.ttf \
+ AndroidClock.ttf \
+ AndroidClock_Highlight.ttf \
+ AndroidClock_Solid.ttf \
+
+$(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
+
+build-one-font-module :=
+font_src_files :=
diff --git a/data/fonts/DroidNaskh-Bold.ttf b/data/fonts/DroidNaskh-Bold.ttf
index 6b7d4f0..692b796 100644
--- a/data/fonts/DroidNaskh-Bold.ttf
+++ b/data/fonts/DroidNaskh-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidNaskh-Regular.ttf b/data/fonts/DroidNaskh-Regular.ttf
index d11e1ae..da9a45f 100644
--- a/data/fonts/DroidNaskh-Regular.ttf
+++ b/data/fonts/DroidNaskh-Regular.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index 2379b2d..cfbc66a 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf
index 41b015d..0cacabe 100644
--- a/data/fonts/DroidSansFallbackFull.ttf
+++ b/data/fonts/DroidSansFallbackFull.ttf
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 6a9ed53..458f85b 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -14,34 +14,30 @@
# Warning: this is actually a product definition, to be inherited from
-# On space-constrained devices, we include a subset of fonts:
-# First, core/required fonts
PRODUCT_COPY_FILES := \
- frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \
- frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \
- frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \
- frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \
- frameworks/base/data/fonts/DroidSansArabic.ttf:system/fonts/DroidSansArabic.ttf \
- frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \
- frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \
- frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \
- frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \
- frameworks/base/data/fonts/DroidSerif-Regular.ttf:system/fonts/DroidSerif-Regular.ttf \
- frameworks/base/data/fonts/DroidSerif-Bold.ttf:system/fonts/DroidSerif-Bold.ttf \
- frameworks/base/data/fonts/DroidSerif-Italic.ttf:system/fonts/DroidSerif-Italic.ttf \
- frameworks/base/data/fonts/DroidSerif-BoldItalic.ttf:system/fonts/DroidSerif-BoldItalic.ttf \
- frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
- frameworks/base/data/fonts/DroidSansArmenian.ttf:system/fonts/DroidSansArmenian.ttf \
- frameworks/base/data/fonts/DroidSansGeorgian.ttf:system/fonts/DroidSansGeorgian.ttf \
- frameworks/base/data/fonts/AndroidEmoji.ttf:system/fonts/AndroidEmoji.ttf \
- frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
- frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
- frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
- frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \
frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \
frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml
-# Next, include additional fonts, depending on how much space we have.
-# Details see module definitions in Android.mk.
PRODUCT_PACKAGES := \
- DroidSansFallback.ttf
+ DroidSansFallback.ttf \
+ Roboto-Regular.ttf \
+ Roboto-Bold.ttf \
+ Roboto-Italic.ttf \
+ Roboto-BoldItalic.ttf \
+ DroidSansArabic.ttf \
+ DroidNaskh-Regular.ttf \
+ DroidSansHebrew-Regular.ttf \
+ DroidSansHebrew-Bold.ttf \
+ DroidSansThai.ttf \
+ DroidSerif-Regular.ttf \
+ DroidSerif-Bold.ttf \
+ DroidSerif-Italic.ttf \
+ DroidSerif-BoldItalic.ttf \
+ DroidSansMono.ttf \
+ DroidSansArmenian.ttf \
+ DroidSansGeorgian.ttf \
+ AndroidEmoji.ttf \
+ Clockopia.ttf \
+ AndroidClock.ttf \
+ AndroidClock_Highlight.ttf \
+ AndroidClock_Solid.ttf \
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index d390ec1..d22dca1 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -51,19 +51,13 @@
<ol>
<li>Declare your application as "debuggable" in your Android Manifest.
- <p>In Eclipse, you can do this from the <b>Application</b> tab when viewing the Manifest
- (on the right side, set <b>Debuggable</b> to <em>true</em>). Otherwise, in the
-<code>AndroidManifest.xml</code>
- file, add <code>android:debuggable="true"</code> to the <code><application></code>
-element.</p>
- </li>
- <li>Set up your device to allow installation of non-Market applications. <p>On
-the device, go to <strong>Settings > Applications</strong> and enable
-
-<strong>Unknown sources</strong> (on an Android 4.0 device, the setting is
-located in <strong>Settings > Security</strong>).</p>
-
- </li>
+ <p>When using Eclipse, you can skip this step, because running your app directly from
+the Eclipse IDE automatically enables debugging.</p>
+ <p>In the <code>AndroidManifest.xml</code> file, add <code>android:debuggable="true"</code> to
+the <code><application></code> element.</p>
+ <p class="note"><strong>Note:</strong> If you manually enable debugging in the manifest
+ file, be sure to disable it before you build for release (your published application
+should usually <em>not</em> be debuggable).</p></li>
<li>Turn on "USB Debugging" on your device.
<p>On the device, go to <strong>Settings > Applications > Development</strong>
and enable <strong>USB debugging</strong>
@@ -72,13 +66,10 @@
</li>
<li>Set up your system to detect your device.
<ul>
- <li>If you're developing on Windows, you need to install a USB driver
- for adb. If you're using an Android Developer Phone (ADP), Nexus One, or Nexus S,
- see the <a href="{@docRoot}sdk/win-usb.html">Google Windows USB
- Driver</a>. Otherwise, you can find a link to the appropriate OEM driver in the
- <a href="{@docRoot}sdk/oem-usb.html">OEM USB Drivers</a> document.</li>
+ <li>If you're developing on Windows, you need to install a USB driver for adb. For an
+installation guide and links to OEM drivers, see the <a href="{@docRoot}sdk/oem-usb.html">OEM USB
+Drivers</a> document.</li>
<li>If you're developing on Mac OS X, it just works. Skip this step.</li>
-
<li>If you're developing on Ubuntu Linux, you need to add a
<code>udev</code> rules file that contains a USB configuration for each type of device
you want to use for development. In the rules file, each device manufacturer
@@ -114,7 +105,7 @@
</li>
</ol>
-<p>You can verify that your device is connected by executing <code>adb
+<p>When plugged in over USB, can verify that your device is connected by executing <code>adb
devices</code> from your SDK {@code platform-tools/} directory. If connected,
you'll see the device name listed as a "device."</p>
diff --git a/docs/html/index.jd b/docs/html/index.jd
index b9d6758..431a7d2 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -154,7 +154,7 @@
+ "href='https://plus.google.com/108967384991768947849'>+Android Developers</a>. "
+ "We'll use it to host Hangouts for developers, talk about the latest releases, "
+ "development and design tips, and much more.</p>"
-+ "<div style='margin:.7em 0 0 -1.2em'><g:plus href='https://plus.google.com/108967384991768947849' "
++ "<div style='margin:.7em 0 0 0'><g:plus href='https://plus.google.com/108967384991768947849' "
+ "size=\"smallbadge\" width=\"275\"></g:plus></div>"
},
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 44fe5e4..af25609 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -52,7 +52,7 @@
<script language="javascript">
var loc = window.location.href;
if (loc.indexOf('?v=') != -1) {
- var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+ var filename = loc.substring(loc.indexOf('=')+1,loc.length).replace(/</g,"<").replace(/>/g,">");
document.write("File: " + filename);
}
</script>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index afbad57..29f0749 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
ndk=true
-ndk.win_download=android-ndk-r7-windows.zip
-ndk.win_bytes=81270552
-ndk.win_checksum=55483482cf2b75e8dd1a5d9a7caeb6e5
+ndk.win_download=android-ndk-r7b-windows.zip
+ndk.win_bytes=80346206
+ndk.win_checksum=c42b0c9c14428397337421d5e4999380
-ndk.mac_download=android-ndk-r7-darwin-x86.tar.bz2
-ndk.mac_bytes=71262092
-ndk.mac_checksum=817ca5675a1dd44078098e43070f19b6
+ndk.mac_download=android-ndk-r7b-darwin-x86.tar.bz2
+ndk.mac_bytes=73817184
+ndk.mac_checksum=6daa82ca6b73bc0614c9997430079c7a
-ndk.linux_download=android-ndk-r7-linux-x86.tar.bz2
-ndk.linux_bytes=64884365
-ndk.linux_checksum=bf15e6b47bf50824c4b96849bf003ca3
+ndk.linux_download=android-ndk-r7b-linux-x86.tar.bz2
+ndk.linux_bytes=64349733
+ndk.linux_checksum=0eb8af18796cdaa082df8f7c54ad7f9a
page.title=Android NDK
@@ -62,6 +62,116 @@
<div class="toggleable open">
<a href="#" onclick="return toggleDiv(this)"><img src=
"{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
+ Android NDK, Revision 7b</a> <em>(February 2012)</em>
+
+ <div class="toggleme">
+ <p>This release of the NDK includes fixes for native Windows builds, Cygwin and many other
+ improvements:</p>
+
+ <dl>
+ <dt>Important bug fixes:</dt>
+
+ <dd>
+ <ul>
+ <li>Updated {@code sys/atomics.h} to avoid correctness issues
+ on some multi-core ARM-based devices. Rebuild your unmodified sources with this
+ version of the NDK and this problem should be completely eliminated.
+ For more details, read {@code docs/ANDROID-ATOMICS.html}.</li>
+ <li>Reverted to {@code binutils} 2.19 to fix debugging issues that
+ appeared in NDK r7 (which switched to {@code binutils} 2.20.1).</li>
+ <li>Fixed {@code ndk-build} on 32-bit Linux. A packaging error put a 64-bit version
+ of the {@code awk} executable under {@code prebuilt/linux-x86/bin} in NDK r7.</li>
+ <li>Fixed native Windows build ({@code ndk-build.cmd}). Other build modes were not
+ affected. The fixes include:
+ <ul>
+ <li>Removed an infinite loop / stack overflow bug that happened when trying
+ to call {@code ndk-build.cmd} from a directory that was <em>not</em> the top of
+ your project path (e.g., in any sub-directory of it).</li>
+ <li>Fixed a problem where the auto-generated dependency files were ignored. This
+ meant that updating a header didn't trigger recompilation of sources that included
+ it.</li>
+ <li>Fixed a problem where special characters in files or paths, other than spaces and
+ quotes, were not correctly handled.</li>
+ </ul>
+ </li>
+ <li>Fixed the standalone toolchain to generate proper binaries when using
+ {@code -lstdc++} (i.e., linking against the GNU {@code libstdc++} C++ runtime). You
+ should use {@code -lgnustl_shared} if you want to link against the shared library
+ version or {@code -lstdc++} for the static version.
+
+ <p>See {@code docs/STANDALONE-TOOLCHAIN.html} for more details about this fix.</p>
+ </li>
+ <li>Fixed {@code gnustl_shared} on Cygwin. The linker complained that it couldn't find
+ {@code libsupc++.a} even though the file was at the right location.</li>
+ <li>Fixed Cygwin C++ link when not using any specific C++ runtime through
+ {@code APP_STL}.</li>
+ </ul>
+ </dd>
+ </dl>
+
+ <dl>
+ <dt>Other changes:</dt>
+
+ <dd>
+ <ul>
+ <li>When your application uses the GNU {@code libstdc++} runtime, the compiler will
+ no longer forcibly enable exceptions and RTTI. This change results in smaller code.
+ <p>If you need these features, you must do one of the following:</p>
+ <ul>
+ <li>Enable exceptions and/or RTTI explicitly in your modules or
+ {@code Application.mk}. (recommended)</li>
+ <li>Define {@code APP_GNUSTL_FORCE_CPP_FEATURES} to {@code 'exceptions'},
+ {@code 'rtti'} or both in your {@code Application.mk}. See
+ {@code docs/APPLICATION-MK.html} for more details.</li>
+ </ul>
+ </li>
+ <li>{@code ndk-gdb} now works properly when your application has private services
+ running in independent processes. It debugs the main application process, instead of the
+ first process listed by {@code ps}, which is usually a service process.</li>
+ <li>Fixed a rare bug where NDK r7 would fail to honor the {@code LOCAL_ARM_MODE} value
+ and always compile certain source files (but not all) to 32-bit instructions.</li>
+ <li>{@code stlport}: Refresh the sources to match the Android platform version. This
+ update fixes a few minor bugs:
+ <ul>
+ <li>Fixed instantiation of an incomplete type</li>
+ <li>Fixed minor "==" versus "=" typo</li>
+ <li>Used {@code memmove} instead of {@code memcpy} in {@code string::assign}</li>
+ <li>Added better handling of {@code IsNANorINF}, {@code IsINF}, {@code IsNegNAN},
+ etc.</li>
+ </ul>
+ <p>For complete details, see the commit log.</p>
+ </li>
+ <li>{@code stlport}: Removed 5 unnecessary static initializers from the library.</li>
+ <li>The GNU libstdc++ libraries for armeabi-v7a were mistakenly compiled for
+ armeabi instead. This change had no impact on correctness, but using the right
+ ABI should provide slightly better performance.</li>
+ <li>The {@code cpu-features} helper library was updated to report three optional
+ x86 CPU features ({@code SSSE3}, {@code MOVBE} and {@code POPCNT}). See
+ {@code docs/CPU-FEATURES.html} for more details.</li>
+ <li>{@code docs/NDK-BUILD.html} was updated to mention {@code NDK_APPLICATION_MK} instead
+ of {@code NDK_APP_APPLICATION_MK} to select a custom {@code Application.mk} file.</li>
+ <li>Cygwin: {@code ndk-build} no longer creates an empty "NUL" file in the current
+ directory when invoked.</li>
+ <li>Cygwin: Added better automatic dependency detection. In the previous version, it
+ didn't work properly in the following cases:
+ <ul>
+ <li>When the Cygwin drive prefix was not {@code /cygdrive}.</li>
+ <li>When using drive-less mounts, for example, when Cygwin would translate
+ {@code /home} to {@code \\server\subdir} instead of {@code C:\Some\Dir}.</li>
+ </ul>
+ </li>
+ <li>Cygwin: {@code ndk-build} does not try to use the native Windows tools under
+ {@code $NDK/prebuilt/windows/bin} with certain versions of Cygwin and/or GNU Make.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)"><img src=
+ "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px">
Android NDK, Revision 7</a> <em>(November 2011)</em>
<div class="toggleme">
diff --git a/docs/html/sdk/oem-usb.jd b/docs/html/sdk/oem-usb.jd
index b81be71..f98257d 100644
--- a/docs/html/sdk/oem-usb.jd
+++ b/docs/html/sdk/oem-usb.jd
@@ -3,9 +3,21 @@
<div id="qv-wrapper">
<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#InstallingDriver">Installing a USB Driver</a>
+ <ol>
+ <li><a href="#Win7">Windows 7</a></li>
+ <li><a href="#WinXp">Windows XP</a></li>
+ <li><a href="#WinVista">Windows Vista</a></li>
+ </ol>
+ </li>
+ <li><a href="#Drivers">OEM Drivers</a></li>
+ </ol>
+
<h2>See also</h2>
<ol>
- <li><a href="{@docRoot}guide/developing/device.html">Developing on a Device</a></li>
+ <li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li>
<li><a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a></li>
</ol>
</div>
@@ -18,8 +30,8 @@
not exhaustive for all available Android-powered devices.</p>
<p>If you're developing on Mac OS X or Linux, then you probably don't need to install a USB driver.
-Refer to <a href="{@docRoot}guide/developing/device.html#setting-up">Setting up a Device</a> to
-start development with a device.</p>
+To start developing with your device, read <a
+href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a>.</p>
<p class="note"><strong>Note:</strong> If your device is one of the Android Developer Phones
(purchased from the Android Market publisher site), a Nexus One, or a Nexus S, then you need
@@ -28,10 +40,184 @@
href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a>
(listed as model SCH-I515).</p>
-<p>For instructions about how to install the driver on Windows, follow the guide for <a
- href="{@docRoot}sdk/win-usb.html#InstallingDriver">Installing the USB Driver</a>.</p>
-<p class="table-caption"><strong>Table 1.</strong> Links to OEM USB drivers</p>
+<h2 id="InstallingDriver">Installing a USB Driver</h2>
+
+<p>First, find the appropriate driver for your device from the <a href="#Drivers">OEM drivers</a>
+table below.</p>
+
+<p>Once you've downloaded your USB driver, follow the instructions below to install or upgrade the
+driver, based on your version of Windows and whether you're installing for the first time
+or upgrading an existing driver.</p>
+
+<p class="note"><strong>Tip:</strong> When you finish the USB driver installation,
+see <a
+href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a> for
+other important information about using an Android-powered device for
+development.</p>
+
+<ol class="nolist">
+ <li><a href="#Win7">Windows 7</a></li>
+ <li><a href="#WinXp">Windows XP</a></li>
+ <li><a href="#WinVista">Windows Vista</a></li>
+</ol>
+
+
+<p class="caution"><strong>Caution:</strong>
+You may make changes to <code>android_winusb.inf</code> file found inside
+<code>usb_driver\</code> (for example, to add support for other devices),
+however, this will lead to security warnings when you install or upgrade the
+driver. Making any other changes to the driver files may break the installation
+process.</p>
+
+
+<h3 id="Win7">Windows 7</h3>
+
+
+<p>To install the Android USB driver on Windows 7 for the first time:</p>
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port.</li>
+ <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer,
+ and select <strong>Manage</strong>.</li>
+ <li>Select <strong>Devices</strong> in the left pane.</li>
+ <li>Locate and expand <em>Other device</em> in the right pane.</li>
+ <li>Right-click the device name (such as <em>Nexus S</em>) and select <strong>Update
+ Driver Software</strong>.
+ This will launch the Hardware Update Wizard.</li>
+ <li>Select <strong>Browse my computer for driver software</strong> and click
+ <strong>Next</strong>.</li>
+ <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
+ <li>Click <strong>Next</strong> to install the driver.</li>
+</ol>
+
+<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows 7 with the new
+driver:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port.</li>
+ <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer,
+ and select <strong>Manage</strong>.</li>
+ <li>Select <strong>Device Manager</strong> in the left pane of the Computer Management
+ window.</li>
+ <li>Locate and expand <em>Android Phone</em> in the right pane.</li>
+ <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update
+ Driver</strong>.
+ This will launch the Hardware Update Wizard.</li>
+ <li>Select <strong>Install from a list or specific location</strong> and click
+ <strong>Next</strong>.</li>
+ <li>Select <strong>Search for the best driver in these locations</strong>; un-check
+<strong>Search removable media</strong>; and check <strong>Include this location in the
+search</strong>.</li>
+ <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
+ <li>Click <strong>Next</strong> to upgrade the driver.</li>
+</ol>
+
+
+
+
+
+<h3 id="WinXp">Windows XP</h3>
+
+<p>To install the Android USB driver on Windows XP for the first time:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port. Windows
+ will detect the device and launch the Hardware Update Wizard.</li>
+ <li>Select <strong>Install from a list or specific location</strong> and click
+ <strong>Next</strong>.</li>
+ <li>Select <strong>Search for the best driver in these locations</strong>; un-check
+<strong>Search
+ removable media</strong>; and check <strong>Include
+this location in the search</strong>.</li>
+ <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
+ <li>Click <strong>Next</strong> to install the driver.</li>
+</ol>
+
+<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows XP with the new
+driver:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port.</li>
+ <li>Right-click on <em>My Computer</em> from your desktop or Windows Explorer,
+ and select <strong>Manage</strong>.</li>
+ <li>Select <strong>Device Manager</strong> in the left pane.</li>
+ <li>Locate and expand <em>Android Phone</em> in the right pane.</li>
+ <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update
+ Driver</strong>.
+ This will launch the Hardware Update Wizard.</li>
+ <li>Select <strong>Install from a list or specific location</strong> and click
+ <strong>Next</strong>.</li>
+ <li>Select <strong>Search for the best driver in these locations</strong>; un-check <strong>Search
+ removable media</strong>; and check <strong>Include
+this location in the search</strong>.</li>
+ <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
+ <li>Click <strong>Next</strong> to upgrade the driver.</li>
+</ol>
+
+
+
+<h3 id="WinVista">Windows Vista</h3>
+
+<p>To install the Android USB driver on Windows Vista for the first time:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port. Windows
+ will detect the device and launch the Found New Hardware wizard.</li>
+ <li>Select <strong>Locate and install driver software</strong>.</li>
+ <li>Select <strong>Don't search online</strong>.</li>
+ <li>Select <strong>I don't have the disk. Show me other options</strong>.</li>
+ <li>Select <strong>Browse my computer for driver software</strong>.</li>
+ <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the
+exact location of the
+ installation package, you may leave <strong>Include subfolders</strong> checked or
+ unchecked—it doesn't matter.</li>
+ <li>Click <strong>Next</strong>. Vista may prompt you to confirm the privilege elevation
+ required for driver installation. Confirm it.</li>
+ <li>When Vista asks if you'd like to install the Google ADB Interface device,
+ click <strong>Install</strong> to install the driver.</li>
+</ol>
+
+<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows Vista with the new
+driver:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port.</li>
+ <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer,
+ and select <strong>Manage</strong>.</li>
+ <li>Select <strong>Device Manager</strong> in the left pane.</li>
+ <li>Locate and expand <em>ADB Interface</em> in the right pane.</li>
+ <li>Right-click on <em>HTC Dream Composite ADB Interface</em>, and select <strong>Update
+ Driver Software</strong>.</li>
+ <li>When Vista starts updating the driver, a prompt will ask how you want to
+ search for the driver
+ software. Select <strong>Browse my computer for driver software</strong>.</li>
+ <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the
+exact location of the
+ installation package, you may leave <strong>Include subfolders</strong> checked or
+ unchecked—it doesn't matter.</li>
+ <li>Click <strong>Next</strong>. Vista might prompt you to confirm the privilege elevation
+ required for driver installation. Confirm it.</li>
+ <li>When Vista asks if you'd like to install the Google ADB Interface device,
+ click <strong>Install</strong> to upgrade the driver.</li>
+</ol>
+
+
+<h2 id="Drivers">OEM Drivers</h2>
+
+<p class="note"><strong>Note:</strong> If your device is one of the Android Developer Phones
+(purchased from the Android Market publisher site), a Nexus One, or a Nexus S, then you need
+the <a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a>, instead of an OEM driver. The Galaxy
+Nexus driver, however, is distributed by <a
+href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a>
+(listed as model SCH-I515).</p>
+
+
<table><tr>
<th>OEM</th>
<th>Driver URL</th></tr>
@@ -92,7 +278,7 @@
</tr>
<tr><td>KT Tech</td> <td><a
-href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.asp</a> for EV-S100(Take)</td>
+href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.asp</a> for EV-S100 (Take)</td>
</tr>
<tr>
<td>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 0de477a..f7541f7 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -195,7 +195,7 @@
<span style="display:none" class="zh-TW"></span>
</span>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a>
+ <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7b</a>
<span class="new">new!</span>
</li>
<li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd
index 2d1435b..2bd031e 100644
--- a/docs/html/sdk/win-usb.jd
+++ b/docs/html/sdk/win-usb.jd
@@ -7,19 +7,12 @@
<ol>
<li><a href="#notes">Revisions</a></li>
<li><a href="#WinUsbDriver">Downloading the Google USB Driver</a></li>
- <li><a href="#InstallingDriver">Installing the USB Driver</a>
- <ol>
- <li><a href="#Win7">Windows 7</a></li>
- <li><a href="#WinXp">Windows XP</a></li>
- <li><a href="#WinVista">Windows Vista</a></li>
- </ol>
- </li>
</ol>
<h2>See also</h2>
<ol>
- <li><a href="{@docRoot}guide/developing/device.html">Developing on a Device</a></li>
+ <li><a href="{@docRoot}sdk/oem-usb.html#InstallingDriver">Installing a USB Driver</a></li>
+ <li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li>
<li><a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a></li>
- <li><a href="{@docRoot}sdk/oem-usb.html">OEM USB Drivers</a></li>
</ol>
</div>
</div>
@@ -43,9 +36,9 @@
(listed as model SCH-I515).</p>
<p class="note"><strong>Note:</strong>
-If you're developing on Mac OS X or Linux, then you do not need to install a USB driver. Refer to <a
-href="{@docRoot}guide/developing/device.html#setting-up">Setting up a Device</a> to start
-development with a device.</p>
+If you're developing on Mac OS X or Linux, then you do not need to install a USB driver. To start
+developing with your device, also read <a href="{@docRoot}guide/developing/device.html">Using
+Hardware Devices</a>.</p>
<p>The sections below provide instructions on how to download and install the Google USB Driver
for Windows. </p>
@@ -170,174 +163,10 @@
<ol>
<li>Launch the SDK and AVD Manager by double-clicking <code>SDK Manager.exe</code>,
at the root of your SDK directory.</li>
- <li>Expand the <em>Third party Add-ons</em> and <em>Google Inc. add-ons</em>.</li>
- <li>Check <strong>Google Usb Driver package</strong> and click <strong>Install selected</strong>.</li>
+ <li>Expand <em>Extras</em>.</li>
+ <li>Check <strong>Google USB Driver package</strong> and click <strong>Install</strong>.</li>
<li>Proceed to install the package. When done, the driver files are
downloaded into the <code><sdk>\extras\google\usb_driver\</code> directory.</li>
</ol>
-
-
-<h2 id="InstallingDriver">Installing the USB Driver</h2>
-
-<p>Once you've downloaded your USB driver, follow the instructions below to install or upgrade the
-driver, based on your version of Windows and whether you're installing for the first time
-or upgrading an existing driver.</p>
-
-<p class="note"><strong>Tip:</strong> When you finish the USB driver installation,
-see <a
-href="{@docRoot}guide/developing/device.html">Developing on a Device</a> for
-other important information about using an Android-powered device for
-development.</p>
-
-<ol class="nolist">
- <li><a href="#Win7">Windows 7</a></li>
- <li><a href="#WinXp">Windows XP</a></li>
- <li><a href="#WinVista">Windows Vista</a></li>
-</ol>
-
-
-<p class="caution"><strong>Caution:</strong>
-You may make changes to <code>android_winusb.inf</code> file found inside
-<code>usb_driver\</code> (for example, to add support for other devices),
-however, this will lead to security warnings when you install or upgrade the
-driver. Making any other changes to the driver files may break the installation
-process.</p>
-
-
-<h3 id="Win7">Windows 7</h3>
-
-
-<p>To install the Android USB driver on Windows 7 for the first time:</p>
-<ol>
- <li>Connect your Android-powered device to your computer's USB port.</li>
- <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer,
- and select <strong>Manage</strong>.</li>
- <li>Select <strong>Devices</strong> in the left pane.</li>
- <li>Locate and expand <em>Other device</em> in the right pane.</li>
- <li>Right-click the device name (such as <em>Nexus S</em>) and select <strong>Update
- Driver Software</strong>.
- This will launch the Hardware Update Wizard.</li>
- <li>Select <strong>Browse my computer for driver software</strong> and click
- <strong>Next</strong>.</li>
- <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
- <li>Click <strong>Next</strong> to install the driver.</li>
-</ol>
-
-<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows 7 with the new
-driver:</p>
-
-<ol>
- <li>Connect your Android-powered device to your computer's USB port.</li>
- <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer,
- and select <strong>Manage</strong>.</li>
- <li>Select <strong>Device Manager</strong> in the left pane of the Computer Management
- window.</li>
- <li>Locate and expand <em>Android Phone</em> in the right pane.</li>
- <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update
- Driver</strong>.
- This will launch the Hardware Update Wizard.</li>
- <li>Select <strong>Install from a list or specific location</strong> and click
- <strong>Next</strong>.</li>
- <li>Select <strong>Search for the best driver in these locations</strong>; un-check
-<strong>Search removable media</strong>; and check <strong>Include this location in the
-search</strong>.</li>
- <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
- <li>Click <strong>Next</strong> to upgrade the driver.</li>
-</ol>
-
-
-
-
-
-<h3 id="WinXp">Windows XP</h3>
-
-<p>To install the Android USB driver on Windows XP for the first time:</p>
-
-<ol>
- <li>Connect your Android-powered device to your computer's USB port. Windows
- will detect the device and launch the Hardware Update Wizard.</li>
- <li>Select <strong>Install from a list or specific location</strong> and click
- <strong>Next</strong>.</li>
- <li>Select <strong>Search for the best driver in these locations</strong>; un-check
-<strong>Search
- removable media</strong>; and check <strong>Include
-this location in the search</strong>.</li>
- <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
- <li>Click <strong>Next</strong> to install the driver.</li>
-</ol>
-
-<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows XP with the new
-driver:</p>
-
-<ol>
- <li>Connect your Android-powered device to your computer's USB port.</li>
- <li>Right-click on <em>My Computer</em> from your desktop or Windows Explorer,
- and select <strong>Manage</strong>.</li>
- <li>Select <strong>Device Manager</strong> in the left pane.</li>
- <li>Locate and expand <em>Android Phone</em> in the right pane.</li>
- <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update
- Driver</strong>.
- This will launch the Hardware Update Wizard.</li>
- <li>Select <strong>Install from a list or specific location</strong> and click
- <strong>Next</strong>.</li>
- <li>Select <strong>Search for the best driver in these locations</strong>; un-check <strong>Search
- removable media</strong>; and check <strong>Include
-this location in the search</strong>.</li>
- <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
- <li>Click <strong>Next</strong> to upgrade the driver.</li>
-</ol>
-
-
-
-<h3 id="WinVista">Windows Vista</h3>
-
-<p>To install the Android USB driver on Windows Vista for the first time:</p>
-
-<ol>
- <li>Connect your Android-powered device to your computer's USB port. Windows
- will detect the device and launch the Found New Hardware wizard.</li>
- <li>Select <strong>Locate and install driver software</strong>.</li>
- <li>Select <strong>Don't search online</strong>.</li>
- <li>Select <strong>I don't have the disk. Show me other options</strong>.</li>
- <li>Select <strong>Browse my computer for driver software</strong>.</li>
- <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the
-exact location of the
- installation package, you may leave <strong>Include subfolders</strong> checked or
- unchecked—it doesn't matter.</li>
- <li>Click <strong>Next</strong>. Vista may prompt you to confirm the privilege elevation
- required for driver installation. Confirm it.</li>
- <li>When Vista asks if you'd like to install the Google ADB Interface device,
- click <strong>Install</strong> to install the driver.</li>
-</ol>
-
-<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows Vista with the new
-driver:</p>
-
-<ol>
- <li>Connect your Android-powered device to your computer's USB port.</li>
- <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer,
- and select <strong>Manage</strong>.</li>
- <li>Select <strong>Device Manager</strong> in the left pane.</li>
- <li>Locate and expand <em>ADB Interface</em> in the right pane.</li>
- <li>Right-click on <em>HTC Dream Composite ADB Interface</em>, and select <strong>Update
- Driver Software</strong>.</li>
- <li>When Vista starts updating the driver, a prompt will ask how you want to
- search for the driver
- software. Select <strong>Browse my computer for driver software</strong>.</li>
- <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the
-exact location of the
- installation package, you may leave <strong>Include subfolders</strong> checked or
- unchecked—it doesn't matter.</li>
- <li>Click <strong>Next</strong>. Vista might prompt you to confirm the privilege elevation
- required for driver installation. Confirm it.</li>
- <li>When Vista asks if you'd like to install the Google ADB Interface device,
- click <strong>Install</strong> to upgrade the driver.</li>
-</ol>
-
+<p>For installation information, read <a href="{@docRoot}sdk/oem-usb.html#InstallingDriver">Installing a USB Driver</a>.</p>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 380b3d8..6f939be 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -408,16 +408,19 @@
}
/**
- * Creates a new bitmap, scaled from an existing bitmap.
+ * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
+ * specified width and height are the same as the current width and height of
+ * the source btimap, the source bitmap is returned and now new bitmap is
+ * created.
*
* @param src The source bitmap.
* @param dstWidth The new bitmap's desired width.
* @param dstHeight The new bitmap's desired height.
* @param filter true if the source should be filtered.
- * @return the new scaled bitmap.
+ * @return The new scaled bitmap or the source bitmap if no scaling is required.
*/
- public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
- int dstHeight, boolean filter) {
+ public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
+ boolean filter) {
Matrix m;
synchronized (Bitmap.class) {
// small pool of just 1 matrix
@@ -458,14 +461,15 @@
/**
* Returns an immutable bitmap from the specified subset of the source
* bitmap. The new bitmap may be the same object as source, or a copy may
- * have been made. It is
- * initialized with the same density as the original bitmap.
+ * have been made. It is initialized with the same density as the original
+ * bitmap.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
* @param y The y coordinate of the first pixel in source
* @param width The number of pixels in each row
* @param height The number of rows
+ * @return A copy of a subset of the source bitmap or the source bitmap itself.
*/
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
return createBitmap(source, x, y, width, height, null, false);
@@ -473,8 +477,13 @@
/**
* Returns an immutable bitmap from subset of the source bitmap,
- * transformed by the optional matrix. It is
+ * transformed by the optional matrix. The new bitmap may be the
+ * same object as source, or a copy may have been made. It is
* initialized with the same density as the original bitmap.
+ *
+ * If the source bitmap is immutable and the requested subset is the
+ * same as the source bitmap itself, then the source bitmap is
+ * returned and no new bitmap is created.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 11c2427..37a270e 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2012 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.
@@ -22,6 +22,7 @@
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
import android.util.Log;
import android.util.TypedValue;
@@ -78,6 +79,8 @@
boolean mConstrainedFace;
boolean mConstrainedY;
boolean mConstrainedZ;
+ boolean mReadAllowed = true;
+ boolean mWriteAllowed = true;
int mSelectedY;
int mSelectedZ;
int mSelectedLOD;
@@ -99,7 +102,7 @@
public static final int USAGE_SCRIPT = 0x0001;
/**
- * GRAPHICS_TEXTURE The allcation will be used as a texture
+ * GRAPHICS_TEXTURE The allocation will be used as a texture
* source by one or more graphics programs.
*
*/
@@ -121,12 +124,38 @@
public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
/**
- * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a
+ * USAGE_GRAPHICS_RENDER_TARGET The allocation will be used as a
* target for offscreen rendering
*
*/
public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
+ /**
+ * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE The allocation
+ * will be used as a SurfaceTexture graphics consumer. This
+ * usage may only be used with USAGE_GRAPHICS_TEXTURE.
+ *
+ * @hide
+ */
+ public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
+
+ /**
+ * USAGE_IO_INPUT The allocation will be used as SurfaceTexture
+ * consumer. This usage will cause the allocation to be created
+ * read only.
+ *
+ * @hide
+ */
+ public static final int USAGE_IO_INPUT = 0x0040;
+
+ /**
+ * USAGE_IO_OUTPUT The allocation will be used as a
+ * SurfaceTexture producer. The dimensions and format of the
+ * SurfaceTexture will be forced to those of the allocation.
+ *
+ * @hide
+ */
+ public static final int USAGE_IO_OUTPUT = 0x0080;
/**
* Controls mipmap behavior when using the bitmap creation and
@@ -187,10 +216,26 @@
USAGE_GRAPHICS_TEXTURE |
USAGE_GRAPHICS_VERTEX |
USAGE_GRAPHICS_CONSTANTS |
- USAGE_GRAPHICS_RENDER_TARGET)) != 0) {
+ USAGE_GRAPHICS_RENDER_TARGET |
+ USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+ USAGE_IO_INPUT |
+ USAGE_IO_OUTPUT)) != 0) {
throw new RSIllegalArgumentException("Unknown usage specified.");
}
+
+ if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) {
+ mWriteAllowed = false;
+
+ if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+ USAGE_IO_INPUT |
+ USAGE_GRAPHICS_TEXTURE |
+ USAGE_SCRIPT)) != 0) {
+ throw new RSIllegalArgumentException("Invalid usage combination.");
+ }
+ }
+
mType = t;
+ mUsage = usage;
if (t != null) {
updateCacheInfo(t);
@@ -278,6 +323,37 @@
mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
}
+ /**
+ * Send a buffer to the output stream. The contents of the
+ * Allocation will be undefined after this operation.
+ *
+ * @hide
+ *
+ */
+ public void ioSendOutput() {
+ if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+ throw new RSIllegalArgumentException(
+ "Can only send buffer if IO_OUTPUT usage specified.");
+ }
+ mRS.validate();
+ mRS.nAllocationIoSend(getID());
+ }
+
+ /**
+ * Receive the latest input into the Allocation.
+ *
+ * @hide
+ *
+ */
+ public void ioGetInput() {
+ if ((mUsage & USAGE_IO_INPUT) == 0) {
+ throw new RSIllegalArgumentException(
+ "Can only send buffer if IO_OUTPUT usage specified.");
+ }
+ mRS.validate();
+ mRS.nAllocationIoReceive(getID());
+ }
+
public void copyFrom(BaseObj[] d) {
mRS.validate();
validateIsObject();
@@ -842,17 +918,37 @@
updateCacheInfo(mType);
}
- /*
+ /**
+ * Resize a 2D allocation. The contents of the allocation are
+ * preserved. If new elements are allocated objects are created
+ * with null contents and the new region is otherwise undefined.
+ *
+ * If the new region is smaller the references of any objects
+ * outside the new region will be released.
+ *
+ * A new type will be created with the new dimension.
+ *
+ * @hide
+ * @param dimX The new size of the allocation.
+ * @param dimY The new size of the allocation.
+ */
public void resize(int dimX, int dimY) {
- if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
- throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
+ if ((mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
+ throw new RSInvalidStateException(
+ "Resize only support for 2D allocations at this time.");
}
if (mType.getY() == 0) {
- throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
+ throw new RSInvalidStateException(
+ "Resize only support for 2D allocations at this time.");
}
mRS.nAllocationResize2D(getID(), dimX, dimY);
+ mRS.finish(); // Necessary because resize is fifoed and update is async.
+
+ int typeID = mRS.nAllocationGetType(getID());
+ mType = new Type(typeID, mRS);
+ mType.updateFromNative();
+ updateCacheInfo(mType);
}
- */
@@ -876,7 +972,31 @@
if (type.getID() == 0) {
throw new RSInvalidStateException("Bad Type");
}
- int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
+ int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, 0);
+ if (id == 0) {
+ throw new RSRuntimeException("Allocation creation failed.");
+ }
+ return new Allocation(id, rs, type, usage);
+ }
+
+ /**
+ * @hide
+ * This API is hidden and only intended to be used for
+ * transitional purposes.
+ *
+ * @param type renderscript type describing data layout
+ * @param mips specifies desired mipmap behaviour for the
+ * allocation
+ * @param usage bit field specifying how the allocation is
+ * utilized
+ */
+ static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips,
+ int usage, int pointer) {
+ rs.validate();
+ if (type.getID() == 0) {
+ throw new RSInvalidStateException("Bad Type");
+ }
+ int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, pointer);
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
@@ -931,7 +1051,7 @@
b.setX(count);
Type t = b.create();
- int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
+ int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage, 0);
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
@@ -1006,6 +1126,35 @@
}
/**
+ *
+ *
+ * @hide
+ *
+ */
+ public SurfaceTexture getSurfaceTexture() {
+ if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
+ throw new RSInvalidStateException("Allocation is not a surface texture.");
+ }
+
+ int id = mRS.nAllocationGetSurfaceTextureID(getID());
+ return new SurfaceTexture(id);
+
+ }
+
+ /**
+ * @hide
+ */
+ public void setSurfaceTexture(SurfaceTexture sur) {
+ if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+ throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
+ }
+
+ mRS.validate();
+ mRS.nAllocationSetSurfaceTexture(getID(), sur);
+ }
+
+
+ /**
* Creates a non-mipmapped renderscript allocation to use as a
* graphics texture
*
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 22ef7bb..3d4951f 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2012 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.
@@ -54,26 +54,59 @@
int[] mArraySizes;
int[] mOffsetInBytes;
+ int[] mVisibleElementMap;
+
DataType mType;
DataKind mKind;
boolean mNormalized;
int mVectorSize;
+ private void updateVisibleSubElements() {
+ if (mElements == null) {
+ return;
+ }
+
+ int noPaddingFieldCount = 0;
+ int fieldCount = mElementNames.length;
+ // Find out how many elements are not padding
+ for (int ct = 0; ct < fieldCount; ct ++) {
+ if (mElementNames[ct].charAt(0) != '#') {
+ noPaddingFieldCount ++;
+ }
+ }
+ mVisibleElementMap = new int[noPaddingFieldCount];
+
+ // Make a map that points us at non-padding elements
+ for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
+ if (mElementNames[ct].charAt(0) != '#') {
+ mVisibleElementMap[ctNoPadding ++] = ct;
+ }
+ }
+ }
+
/**
* @hide
* @return element size in bytes
*/
public int getSizeBytes() {return mSize;}
+ /**
+ * @hide
+ * @return element vector size
+ */
+ public int getVectorSize() {return mVectorSize;}
+
/**
* DataType represents the basic type information for a basic element. The
- * naming convention follows. For numeric types its FLOAT, SIGNED, UNSIGNED
- * followed by the _BITS where BITS is the size of the data. BOOLEAN is a
- * true / false (1,0) represented in an 8 bit container. The UNSIGNED
- * variants with multiple bit definitions are for packed graphical data
- * formats and represents vectors with per vector member sizes which are
- * treated as a single unit for packing and alignment purposes.
+ * naming convention follows. For numeric types it is FLOAT,
+ * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ * size of the data. BOOLEAN is a true / false (1,0)
+ * represented in an 8 bit container. The UNSIGNED variants
+ * with multiple bit definitions are for packed graphical data
+ * formats and represent vectors with per vector member sizes
+ * which are treated as a single unit for packing and alignment
+ * purposes.
*
* MATRIX the three matrix types contain FLOAT_32 elements and are treated
* as 32 bits for alignment purposes.
@@ -81,6 +114,11 @@
* RS_* objects. 32 bit opaque handles.
*/
public enum DataType {
+ /**
+ * @hide
+ * new enum
+ */
+ NONE (0, 0),
//FLOAT_16 (1, 2),
FLOAT_32 (2, 4),
FLOAT_64 (3, 8),
@@ -167,10 +205,10 @@
* @return number of sub-elements in this element
*/
public int getSubElementCount() {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
return 0;
}
- return mElements.length;
+ return mVisibleElementMap.length;
}
/**
@@ -179,13 +217,13 @@
* @return sub-element in this element at given index
*/
public Element getSubElement(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mElements[index];
+ return mElements[mVisibleElementMap[index]];
}
/**
@@ -194,13 +232,13 @@
* @return sub-element in this element at given index
*/
public String getSubElementName(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mElementNames[index];
+ return mElementNames[mVisibleElementMap[index]];
}
/**
@@ -209,13 +247,13 @@
* @return array size of sub-element in this element at given index
*/
public int getSubElementArraySize(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mArraySizes[index];
+ return mArraySizes[mVisibleElementMap[index]];
}
/**
@@ -224,13 +262,29 @@
* @return offset in bytes of sub-element in this element at given index
*/
public int getSubElementOffsetBytes(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mOffsetInBytes[index];
+ return mOffsetInBytes[mVisibleElementMap[index]];
+ }
+
+ /**
+ * @hide
+ * @return element data type
+ */
+ public DataType getDataType() {
+ return mType;
+ }
+
+ /**
+ * @hide
+ * @return element data kind
+ */
+ public DataKind getDataKind() {
+ return mKind;
}
/**
@@ -681,14 +735,18 @@
Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
super(id, rs);
mSize = 0;
+ mVectorSize = 1;
mElements = e;
mElementNames = n;
mArraySizes = as;
+ mType = DataType.NONE;
+ mKind = DataKind.USER;
mOffsetInBytes = new int[mElements.length];
for (int ct = 0; ct < mElements.length; ct++ ) {
mOffsetInBytes[ct] = mSize;
mSize += mElements[ct].mSize * mArraySizes[ct];
}
+ updateVisibleSubElements();
}
Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -753,7 +811,7 @@
mSize += mElements[i].mSize * mArraySizes[i];
}
}
-
+ updateVisibleSubElements();
}
/**
@@ -774,10 +832,12 @@
/**
* Create a custom vector element of the specified DataType and vector size.
- * DataKind will be set to USER.
+ * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64,
+ * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16,
+ * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported.
*
* @param rs The context associated with the new Element.
- * @param dt The DataType for the new element.
+ * @param dt The DataType for the new Element.
* @param size Vector size for the new Element. Range 2-4 inclusive
* supported.
*
@@ -787,10 +847,31 @@
if (size < 2 || size > 4) {
throw new RSIllegalArgumentException("Vector size out of range 2-4.");
}
- DataKind dk = DataKind.USER;
- boolean norm = false;
- int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
- return new Element(id, rs, dt, dk, norm, size);
+
+ switch (dt) {
+ // Support only primitive integer/float/boolean types as vectors.
+ case FLOAT_32:
+ case FLOAT_64:
+ case SIGNED_8:
+ case SIGNED_16:
+ case SIGNED_32:
+ case SIGNED_64:
+ case UNSIGNED_8:
+ case UNSIGNED_16:
+ case UNSIGNED_32:
+ case UNSIGNED_64:
+ case BOOLEAN: {
+ DataKind dk = DataKind.USER;
+ boolean norm = false;
+ int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
+ return new Element(id, rs, dt, dk, norm, size);
+ }
+
+ default: {
+ throw new RSIllegalArgumentException("Cannot create vector of " +
+ "non-primitive type.");
+ }
+ }
}
/**
@@ -875,10 +956,10 @@
// Ignore mKind because it is allowed to be different (user vs. pixel).
// We also ignore mNormalized because it can be different. The mType
- // field must be non-null since we require name equivalence for
- // user-created Elements.
+ // field must not be NONE since we require name equivalence for
+ // all user-created Elements.
return ((mSize == e.mSize) &&
- (mType != null) &&
+ (mType != DataType.NONE) &&
(mType == e.mType) &&
(mVectorSize == e.mVectorSize));
}
diff --git a/graphics/java/android/renderscript/Path.java b/graphics/java/android/renderscript/Path.java
new file mode 100644
index 0000000..83ae150
--- /dev/null
+++ b/graphics/java/android/renderscript/Path.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.util.Vector;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ */
+public class Path extends BaseObj {
+
+ public enum Primitive {
+ QUADRATIC_BEZIER(0),
+ CUBIC_BEZIER(1);
+
+ int mID;
+ Primitive(int id) {
+ mID = id;
+ }
+ }
+
+ Allocation mVertexBuffer;
+ Allocation mLoopBuffer;
+ Primitive mPrimitive;
+ float mQuality;
+ boolean mCoverageToAlpha;
+
+ Path(int id, RenderScript rs, Primitive p, Allocation vtx, Allocation loop, float q) {
+ super(id, rs);
+ mVertexBuffer = vtx;
+ mLoopBuffer = loop;
+ mPrimitive = p;
+ mQuality = q;
+ }
+
+ public Allocation getVertexAllocation() {
+ return mVertexBuffer;
+ }
+
+ public Allocation getLoopAllocation() {
+ return mLoopBuffer;
+ }
+
+ public Primitive getPrimitive() {
+ return mPrimitive;
+ }
+
+ @Override
+ void updateFromNative() {
+ }
+
+
+ public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+ int id = rs.nPathCreate(p.mID, false, vtx.getID(), 0, quality);
+ Path newPath = new Path(id, rs, p, null, null, quality);
+ return newPath;
+ }
+
+ public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+ return null;
+ }
+
+ public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+ return null;
+ }
+
+ public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+ return null;
+ }
+
+
+}
+
+
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index a1b1ba3..4d60ac8 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -69,6 +69,7 @@
Element mOutputs[];
Type mConstants[];
TextureType mTextures[];
+ String mTextureNames[];
int mTextureCount;
String mShader;
@@ -77,6 +78,50 @@
}
/**
+ * @hide
+ */
+ public int getConstantCount() {
+ return mConstants != null ? mConstants.length : 0;
+ }
+
+ /**
+ * @hide
+ */
+ public Type getConstant(int slot) {
+ if (slot < 0 || slot >= mConstants.length) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mConstants[slot];
+ }
+
+ /**
+ * @hide
+ */
+ public int getTextureCount() {
+ return mTextureCount;
+ }
+
+ /**
+ * @hide
+ */
+ public TextureType getTextureType(int slot) {
+ if ((slot < 0) || (slot >= mTextureCount)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mTextures[slot];
+ }
+
+ /**
+ * @hide
+ */
+ public String getTextureName(int slot) {
+ if ((slot < 0) || (slot >= mTextureCount)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mTextureNames[slot];
+ }
+
+ /**
* Binds a constant buffer to be used as uniform inputs to the
* program
*
@@ -146,6 +191,7 @@
Type mConstants[];
Type mTextures[];
TextureType mTextureTypes[];
+ String mTextureNames[];
int mInputCount;
int mOutputCount;
int mConstantCount;
@@ -163,6 +209,7 @@
mConstantCount = 0;
mTextureCount = 0;
mTextureTypes = new TextureType[MAX_TEXTURE];
+ mTextureNames = new String[MAX_TEXTURE];
}
/**
@@ -266,10 +313,28 @@
* @return self
*/
public BaseProgramBuilder addTexture(TextureType texType) throws IllegalArgumentException {
+ addTexture(texType, "Tex" + mTextureCount);
+ return this;
+ }
+
+ /**
+ * @hide
+ * Adds a texture input to the Program
+ *
+ * @param texType describes that the texture to append it (2D,
+ * Cubemap, etc.)
+ * @param texName what the texture should be called in the
+ * shader
+ * @return self
+ */
+ public BaseProgramBuilder addTexture(TextureType texType, String texName)
+ throws IllegalArgumentException {
if(mTextureCount >= MAX_TEXTURE) {
throw new IllegalArgumentException("Max texture count exceeded.");
}
- mTextureTypes[mTextureCount ++] = texType;
+ mTextureTypes[mTextureCount] = texType;
+ mTextureNames[mTextureCount] = texName;
+ mTextureCount ++;
return this;
}
@@ -283,6 +348,8 @@
p.mTextureCount = mTextureCount;
p.mTextures = new TextureType[mTextureCount];
System.arraycopy(mTextureTypes, 0, p.mTextures, 0, mTextureCount);
+ p.mTextureNames = new String[mTextureCount];
+ System.arraycopy(mTextureNames, 0, p.mTextureNames, 0, mTextureCount);
}
}
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 21bace8..ebc15e5 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -59,6 +59,7 @@
public ProgramFragment create() {
mRS.validate();
int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+ String[] texNames = new String[mTextureCount];
int idx = 0;
for (int i=0; i < mInputCount; i++) {
@@ -76,9 +77,10 @@
for (int i=0; i < mTextureCount; i++) {
tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
tmp[idx++] = mTextureTypes[i].mID;
+ texNames[i] = mTextureNames[i];
}
- int id = mRS.nProgramFragmentCreate(mShader, tmp);
+ int id = mRS.nProgramFragmentCreate(mShader, texNames, tmp);
ProgramFragment pf = new ProgramFragment(id, mRS);
initProgram(pf);
return pf;
diff --git a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
index 0ab73c1..cd31db3 100644
--- a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -47,6 +47,7 @@
public ProgramFragmentFixedFunction create() {
mRS.validate();
int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+ String[] texNames = new String[mTextureCount];
int idx = 0;
for (int i=0; i < mInputCount; i++) {
@@ -64,9 +65,10 @@
for (int i=0; i < mTextureCount; i++) {
tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
tmp[idx++] = mTextureTypes[i].mID;
+ texNames[i] = mTextureNames[i];
}
- int id = mRS.nProgramFragmentCreate(mShader, tmp);
+ int id = mRS.nProgramFragmentCreate(mShader, texNames, tmp);
ProgramFragmentFixedFunction pf = new ProgramFragmentFixedFunction(id, mRS);
initProgram(pf);
return pf;
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 56bb836..a6cd15b 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -55,6 +55,23 @@
}
/**
+ * @hide
+ */
+ public int getInputCount() {
+ return mInputs != null ? mInputs.length : 0;
+ }
+
+ /**
+ * @hide
+ */
+ public Element getInput(int slot) {
+ if (slot < 0 || slot >= mInputs.length) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mInputs[slot];
+ }
+
+ /**
* Builder class for creating ProgramVertex objects.
* The builder starts empty and the user must minimally provide
* the GLSL shader code, and the varying inputs. Constant, or
@@ -99,6 +116,7 @@
public ProgramVertex create() {
mRS.validate();
int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+ String[] texNames = new String[mTextureCount];
int idx = 0;
for (int i=0; i < mInputCount; i++) {
@@ -116,9 +134,10 @@
for (int i=0; i < mTextureCount; i++) {
tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
tmp[idx++] = mTextureTypes[i].mID;
+ texNames[i] = mTextureNames[i];
}
- int id = mRS.nProgramVertexCreate(mShader, tmp);
+ int id = mRS.nProgramVertexCreate(mShader, texNames, tmp);
ProgramVertex pv = new ProgramVertex(id, mRS);
initProgram(pv);
return pv;
diff --git a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
index 740d6a5..9a43943 100644
--- a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -70,6 +70,7 @@
public ProgramVertexFixedFunction create() {
mRS.validate();
int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+ String[] texNames = new String[mTextureCount];
int idx = 0;
for (int i=0; i < mInputCount; i++) {
@@ -87,9 +88,10 @@
for (int i=0; i < mTextureCount; i++) {
tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
tmp[idx++] = mTextureTypes[i].mID;
+ texNames[i] = mTextureNames[i];
}
- int id = mRS.nProgramVertexCreate(mShader, tmp);
+ int id = mRS.nProgramVertexCreate(mShader, texNames, tmp);
ProgramVertexFixedFunction pv = new ProgramVertexFixedFunction(id, mRS);
initProgram(pv);
return pv;
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index bfe412c..9517513 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -231,10 +231,10 @@
rsnTypeGetNativeData(mContext, id, typeData);
}
- native int rsnAllocationCreateTyped(int con, int type, int mip, int usage);
- synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+ native int rsnAllocationCreateTyped(int con, int type, int mip, int usage, int pointer);
+ synchronized int nAllocationCreateTyped(int type, int mip, int usage, int pointer) {
validate();
- return rsnAllocationCreateTyped(mContext, type, mip, usage);
+ return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
}
native int rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
@@ -269,6 +269,28 @@
validate();
rsnAllocationSyncAll(mContext, alloc, src);
}
+ native int rsnAllocationGetSurfaceTextureID(int con, int alloc);
+ synchronized int nAllocationGetSurfaceTextureID(int alloc) {
+ validate();
+ return rsnAllocationGetSurfaceTextureID(mContext, alloc);
+ }
+ native void rsnAllocationSetSurfaceTexture(int con, int alloc, SurfaceTexture sur);
+ synchronized void nAllocationSetSurfaceTexture(int alloc, SurfaceTexture sur) {
+ validate();
+ rsnAllocationSetSurfaceTexture(mContext, alloc, sur);
+ }
+ native void rsnAllocationIoSend(int con, int alloc);
+ synchronized void nAllocationIoSend(int alloc) {
+ validate();
+ rsnAllocationIoSend(mContext, alloc);
+ }
+ native void rsnAllocationIoReceive(int con, int alloc);
+ synchronized void nAllocationIoReceive(int alloc) {
+ validate();
+ rsnAllocationIoReceive(mContext, alloc);
+ }
+
+
native void rsnAllocationGenerateMipmaps(int con, int alloc);
synchronized void nAllocationGenerateMipmaps(int alloc) {
validate();
@@ -547,15 +569,15 @@
validate();
rsnProgramBindSampler(mContext, vpf, slot, s);
}
- native int rsnProgramFragmentCreate(int con, String shader, int[] params);
- synchronized int nProgramFragmentCreate(String shader, int[] params) {
+ native int rsnProgramFragmentCreate(int con, String shader, String[] texNames, int[] params);
+ synchronized int nProgramFragmentCreate(String shader, String[] texNames, int[] params) {
validate();
- return rsnProgramFragmentCreate(mContext, shader, params);
+ return rsnProgramFragmentCreate(mContext, shader, texNames, params);
}
- native int rsnProgramVertexCreate(int con, String shader, int[] params);
- synchronized int nProgramVertexCreate(String shader, int[] params) {
+ native int rsnProgramVertexCreate(int con, String shader, String[] texNames, int[] params);
+ synchronized int nProgramVertexCreate(String shader, String[] texNames, int[] params) {
validate();
- return rsnProgramVertexCreate(mContext, shader, params);
+ return rsnProgramVertexCreate(mContext, shader, texNames, params);
}
native int rsnMeshCreate(int con, int[] vtx, int[] idx, int[] prim);
@@ -584,6 +606,11 @@
rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
}
+ native int rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+ synchronized int nPathCreate(int prim, boolean isStatic, int vtx, int loop, float q) {
+ validate();
+ return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
+ }
int mDev;
int mContext;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 9622bd2..27ea8f6 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -31,9 +31,9 @@
#include <core/SkTemplates.h>
#include <images/SkImageDecoder.h>
-#include <utils/Asset.h>
-#include <utils/AssetManager.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
#include "jni.h"
#include "JNIHelp.h"
@@ -41,8 +41,8 @@
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/android_util_AssetManager.h"
-#include <RenderScript.h>
-#include <RenderScriptEnv.h>
+#include <rs.h>
+#include <rsEnv.h>
#include <gui/SurfaceTexture.h>
#include <gui/SurfaceTextureClient.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -54,13 +54,11 @@
class AutoJavaStringToUTF8 {
public:
- AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str)
- {
+ AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
fCStr = env->GetStringUTFChars(str, NULL);
fLength = env->GetStringUTFLength(str);
}
- ~AutoJavaStringToUTF8()
- {
+ ~AutoJavaStringToUTF8() {
fEnv->ReleaseStringUTFChars(fJStr, fCStr);
}
const char* c_str() const { return fCStr; }
@@ -73,6 +71,42 @@
jsize fLength;
};
+class AutoJavaStringArrayToUTF8 {
+public:
+ AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength)
+ : mEnv(env), mStrings(strings), mStringsLength(stringsLength) {
+ mCStrings = NULL;
+ mSizeArray = NULL;
+ if (stringsLength > 0) {
+ mCStrings = (const char **)calloc(stringsLength, sizeof(char *));
+ mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t));
+ for (jsize ct = 0; ct < stringsLength; ct ++) {
+ jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
+ mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL);
+ mSizeArray[ct] = mEnv->GetStringUTFLength(s);
+ }
+ }
+ }
+ ~AutoJavaStringArrayToUTF8() {
+ for (jsize ct=0; ct < mStringsLength; ct++) {
+ jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
+ mEnv->ReleaseStringUTFChars(s, mCStrings[ct]);
+ }
+ free(mCStrings);
+ free(mSizeArray);
+ }
+ const char **c_str() const { return mCStrings; }
+ size_t *c_str_len() const { return mSizeArray; }
+ jsize length() const { return mStringsLength; }
+
+private:
+ JNIEnv *mEnv;
+ jobjectArray mStrings;
+ const char **mCStrings;
+ size_t *mSizeArray;
+ jsize mStringsLength;
+};
+
// ---------------------------------------------------------------------------
static jfieldID gContextId = 0;
@@ -322,33 +356,27 @@
}
static jint
-nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes)
+nElementCreate2(JNIEnv *_env, jobject _this, RsContext con,
+ jintArray _ids, jobjectArray _names, jintArray _arraySizes)
{
int fieldCount = _env->GetArrayLength(_ids);
LOG_API("nElementCreate2, con(%p)", con);
jint *ids = _env->GetIntArrayElements(_ids, NULL);
jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
- const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
- size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t));
- for (int ct=0; ct < fieldCount; ct++) {
- jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
- nameArray[ct] = _env->GetStringUTFChars(s, NULL);
- sizeArray[ct] = _env->GetStringUTFLength(s);
- }
+ AutoJavaStringArrayToUTF8 names(_env, _names, fieldCount);
+
+ const char **nameArray = names.c_str();
+ size_t *sizeArray = names.c_str_len();
+
jint id = (jint)rsElementCreate2(con,
(RsElement *)ids, fieldCount,
nameArray, fieldCount * sizeof(size_t), sizeArray,
(const uint32_t *)arraySizes, fieldCount);
- for (int ct=0; ct < fieldCount; ct++) {
- jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
- _env->ReleaseStringUTFChars(s, nameArray[ct]);
- }
+
_env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
_env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
- free(nameArray);
- free(sizeArray);
return (jint)id;
}
@@ -430,10 +458,10 @@
// -----------------------------------
static jint
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage)
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage, jint pointer)
{
- LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage);
- return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage);
+ LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", con, (RsElement)type, mips, usage, (void *)pointer);
+ return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
}
static void
@@ -443,6 +471,44 @@
rsAllocationSyncAll(con, (RsAllocation)a, (RsAllocationUsageType)bits);
}
+static jint
+nAllocationGetSurfaceTextureID(JNIEnv *_env, jobject _this, RsContext con, jint a)
+{
+ LOG_API("nAllocationGetSurfaceTextureID, con(%p), a(%p)", con, (RsAllocation)a);
+ return rsAllocationGetSurfaceTextureID(con, (RsAllocation)a);
+}
+
+static void
+nAllocationSetSurfaceTexture(JNIEnv *_env, jobject _this, RsContext con,
+ RsAllocation alloc, jobject sur)
+{
+ LOG_API("nAllocationSetSurfaceTexture, con(%p), alloc(%p), surface(%p)",
+ con, alloc, (Surface *)sur);
+
+ sp<ANativeWindow> window;
+ if (sur != 0) {
+ sp<SurfaceTexture> st = SurfaceTexture_getSurfaceTexture(_env, sur);
+ window = new SurfaceTextureClient(st);
+ }
+
+ rsAllocationSetSurface(con, alloc, window.get());
+}
+
+static void
+nAllocationIoSend(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc)
+{
+ LOG_API("nAllocationIoSend, con(%p), alloc(%p)", con, alloc);
+ rsAllocationIoSend(con, alloc);
+}
+
+static void
+nAllocationIoReceive(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc)
+{
+ LOG_API("nAllocationIoReceive, con(%p), alloc(%p)", con, alloc);
+ rsAllocationIoReceive(con, alloc);
+}
+
+
static void
nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
{
@@ -1026,15 +1092,24 @@
// ---------------------------------------------------------------------------
static jint
-nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params)
+nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader,
+ jobjectArray texNames, jintArray params)
{
AutoJavaStringToUTF8 shaderUTF(_env, shader);
jint *paramPtr = _env->GetIntArrayElements(params, NULL);
jint paramLen = _env->GetArrayLength(params);
+ int texCount = _env->GetArrayLength(texNames);
+ AutoJavaStringArrayToUTF8 names(_env, texNames, texCount);
+ const char ** nameArray = names.c_str();
+ size_t* sizeArray = names.c_str_len();
+
LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen);
- jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
+ jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(),
+ nameArray, texCount, sizeArray,
+ (uint32_t *)paramPtr, paramLen);
+
_env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
return ret;
}
@@ -1043,7 +1118,8 @@
// ---------------------------------------------------------------------------
static jint
-nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params)
+nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader,
+ jobjectArray texNames, jintArray params)
{
AutoJavaStringToUTF8 shaderUTF(_env, shader);
jint *paramPtr = _env->GetIntArrayElements(params, NULL);
@@ -1051,7 +1127,15 @@
LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen);
- jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
+ int texCount = _env->GetArrayLength(texNames);
+ AutoJavaStringArrayToUTF8 names(_env, texNames, texCount);
+ const char ** nameArray = names.c_str();
+ size_t* sizeArray = names.c_str_len();
+
+ jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(),
+ nameArray, texCount, sizeArray,
+ (uint32_t *)paramPtr, paramLen);
+
_env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
return ret;
}
@@ -1122,6 +1206,17 @@
// ---------------------------------------------------------------------------
+//native int rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+static jint
+nPathCreate(JNIEnv *_env, jobject _this, RsContext con, jint prim, jboolean isStatic, jint _vtx, jint _loop, jfloat q) {
+ LOG_API("nPathCreate, con(%p)", con);
+
+ int id = (int)rsPathCreate(con, (RsPathPrimitive)prim, isStatic,
+ (RsAllocation)_vtx,
+ (RsAllocation)_loop, q);
+ return id;
+}
+
static jint
nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jintArray _vtx, jintArray _idx, jintArray _prim)
{
@@ -1250,7 +1345,7 @@
{"rsnTypeCreate", "(IIIIIZZ)I", (void*)nTypeCreate },
{"rsnTypeGetNativeData", "(II[I)V", (void*)nTypeGetNativeData },
-{"rsnAllocationCreateTyped", "(IIII)I", (void*)nAllocationCreateTyped },
+{"rsnAllocationCreateTyped", "(IIIII)I", (void*)nAllocationCreateTyped },
{"rsnAllocationCreateFromBitmap", "(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCreateFromBitmap },
{"rsnAllocationCubeCreateFromBitmap","(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCubeCreateFromBitmap },
@@ -1258,6 +1353,10 @@
{"rsnAllocationCopyToBitmap", "(IILandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap },
{"rsnAllocationSyncAll", "(III)V", (void*)nAllocationSyncAll },
+{"rsnAllocationGetSurfaceTextureID", "(II)I", (void*)nAllocationGetSurfaceTextureID },
+{"rsnAllocationSetSurfaceTexture", "(IILandroid/graphics/SurfaceTexture;)V", (void*)nAllocationSetSurfaceTexture },
+{"rsnAllocationIoSend", "(II)V", (void*)nAllocationIoSend },
+{"rsnAllocationIoReceive", "(II)V", (void*)nAllocationIoReceive },
{"rsnAllocationData1D", "(IIIII[II)V", (void*)nAllocationData1D_i },
{"rsnAllocationData1D", "(IIIII[SI)V", (void*)nAllocationData1D_s },
{"rsnAllocationData1D", "(IIIII[BI)V", (void*)nAllocationData1D_b },
@@ -1298,9 +1397,9 @@
{"rsnProgramBindTexture", "(IIII)V", (void*)nProgramBindTexture },
{"rsnProgramBindSampler", "(IIII)V", (void*)nProgramBindSampler },
-{"rsnProgramFragmentCreate", "(ILjava/lang/String;[I)I", (void*)nProgramFragmentCreate },
+{"rsnProgramFragmentCreate", "(ILjava/lang/String;[Ljava/lang/String;[I)I", (void*)nProgramFragmentCreate },
{"rsnProgramRasterCreate", "(IZI)I", (void*)nProgramRasterCreate },
-{"rsnProgramVertexCreate", "(ILjava/lang/String;[I)I", (void*)nProgramVertexCreate },
+{"rsnProgramVertexCreate", "(ILjava/lang/String;[Ljava/lang/String;[I)I", (void*)nProgramVertexCreate },
{"rsnContextBindRootScript", "(II)V", (void*)nContextBindRootScript },
{"rsnContextBindProgramStore", "(II)V", (void*)nContextBindProgramStore },
@@ -1310,6 +1409,7 @@
{"rsnSamplerCreate", "(IIIIIIF)I", (void*)nSamplerCreate },
+{"rsnPathCreate", "(IIZIIF)I", (void*)nPathCreate },
{"rsnMeshCreate", "(I[I[I[I)I", (void*)nMeshCreate },
{"rsnMeshGetVertexBufferCount", "(II)I", (void*)nMeshGetVertexBufferCount },
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index 990143b..a59677a 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -17,7 +17,7 @@
#ifndef _ANDROID_APP_NATIVEACTIVITY_H
#define _ANDROID_APP_NATIVEACTIVITY_H
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include <utils/Looper.h>
#include <android/native_activity.h>
@@ -114,8 +114,8 @@
struct in_flight_event {
android::InputEvent* event;
- int seq;
- bool doFinish;
+ int seq; // internal sequence number for synthetic pre-dispatch events
+ uint32_t finishSeq; // sequence number for sendFinishedSignal, or 0 if finish not required
};
struct finish_pre_dispatch {
diff --git a/include/android_runtime/android_content_res_Configuration.h b/include/android_runtime/android_content_res_Configuration.h
index 2f5a982..34c4439 100644
--- a/include/android_runtime/android_content_res_Configuration.h
+++ b/include/android_runtime/android_content_res_Configuration.h
@@ -17,7 +17,7 @@
#ifndef _ANDROID_CONTENT_RES_CONFIGURATION_H
#define _ANDROID_CONTENT_RES_CONFIGURATION_H
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <android/configuration.h>
#include "jni.h"
diff --git a/include/android_runtime/android_util_AssetManager.h b/include/android_runtime/android_util_AssetManager.h
index b6dd9c9..8dd9337 100644
--- a/include/android_runtime/android_util_AssetManager.h
+++ b/include/android_runtime/android_util_AssetManager.h
@@ -17,7 +17,7 @@
#ifndef android_util_AssetManager_H
#define android_util_AssetManager_H
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
#include "jni.h"
diff --git a/include/utils/Asset.h b/include/androidfw/Asset.h
similarity index 100%
rename from include/utils/Asset.h
rename to include/androidfw/Asset.h
diff --git a/include/utils/AssetDir.h b/include/androidfw/AssetDir.h
similarity index 100%
rename from include/utils/AssetDir.h
rename to include/androidfw/AssetDir.h
diff --git a/include/utils/AssetManager.h b/include/androidfw/AssetManager.h
similarity index 98%
rename from include/utils/AssetManager.h
rename to include/androidfw/AssetManager.h
index a8c7ddb..d95b45e 100644
--- a/include/utils/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -20,14 +20,15 @@
#ifndef __LIBS_ASSETMANAGER_H
#define __LIBS_ASSETMANAGER_H
-#include <utils/Asset.h>
-#include <utils/AssetDir.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetDir.h>
+#include <androidfw/ZipFileRO.h>
#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
+#include <utils/SortedVector.h>
#include <utils/String16.h>
-#include <utils/ZipFileRO.h>
+#include <utils/String8.h>
#include <utils/threads.h>
+#include <utils/Vector.h>
/*
* Native-app access is via the opaque typedef struct AAssetManager in the C namespace.
diff --git a/include/utils/BackupHelpers.h b/include/androidfw/BackupHelpers.h
similarity index 100%
rename from include/utils/BackupHelpers.h
rename to include/androidfw/BackupHelpers.h
diff --git a/include/ui/Input.h b/include/androidfw/Input.h
similarity index 99%
rename from include/ui/Input.h
rename to include/androidfw/Input.h
index c2cbe1d..f5db6e24 100644
--- a/include/ui/Input.h
+++ b/include/androidfw/Input.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_H
-#define _UI_INPUT_H
+#ifndef _ANDROIDFW_INPUT_H
+#define _ANDROIDFW_INPUT_H
/**
* Native input event structures.
@@ -894,4 +894,4 @@
} // namespace android
-#endif // _UI_INPUT_H
+#endif // _ANDROIDFW_INPUT_H
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
new file mode 100644
index 0000000..a846e65
--- /dev/null
+++ b/include/androidfw/InputTransport.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROIDFW_INPUT_TRANSPORT_H
+#define _ANDROIDFW_INPUT_TRANSPORT_H
+
+/**
+ * Native input transport.
+ *
+ * The InputChannel provides a mechanism for exchanging InputMessage structures across processes.
+ *
+ * The InputPublisher and InputConsumer each handle one end-point of an input channel.
+ * The InputPublisher is used by the input dispatcher to send events to the application.
+ * The InputConsumer is used by the application to receive events from the input dispatcher.
+ */
+
+#include <androidfw/Input.h>
+#include <utils/Errors.h>
+#include <utils/Timers.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+/*
+ * Intermediate representation used to send input events and related signals.
+ */
+struct InputMessage {
+ enum {
+ TYPE_KEY = 1,
+ TYPE_MOTION = 2,
+ TYPE_FINISHED = 3,
+ };
+
+ struct Header {
+ uint32_t type;
+ uint32_t padding; // 8 byte alignment for the body that follows
+ } header;
+
+ union Body {
+ struct Key {
+ uint32_t seq;
+ nsecs_t eventTime;
+ int32_t deviceId;
+ int32_t source;
+ int32_t action;
+ int32_t flags;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ int32_t repeatCount;
+ nsecs_t downTime;
+
+ inline size_t size() const {
+ return sizeof(Key);
+ }
+ } key;
+
+ struct Motion {
+ uint32_t seq;
+ nsecs_t eventTime;
+ int32_t deviceId;
+ int32_t source;
+ int32_t action;
+ int32_t flags;
+ int32_t metaState;
+ int32_t buttonState;
+ int32_t edgeFlags;
+ nsecs_t downTime;
+ float xOffset;
+ float yOffset;
+ float xPrecision;
+ float yPrecision;
+ size_t pointerCount;
+ struct Pointer {
+ PointerProperties properties;
+ PointerCoords coords;
+ } pointers[MAX_POINTERS];
+
+ inline size_t size() const {
+ return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
+ + sizeof(Pointer) * pointerCount;
+ }
+ } motion;
+
+ struct Finished {
+ uint32_t seq;
+ bool handled;
+
+ inline size_t size() const {
+ return sizeof(Finished);
+ }
+ } finished;
+ } body;
+
+ bool isValid(size_t actualSize) const;
+ size_t size() const;
+};
+
+/*
+ * An input channel consists of a local unix domain socket used to send and receive
+ * input messages across processes. Each channel has a descriptive name for debugging purposes.
+ *
+ * Each endpoint has its own InputChannel object that specifies its file descriptor.
+ *
+ * The input channel is closed when all references to it are released.
+ */
+class InputChannel : public RefBase {
+protected:
+ virtual ~InputChannel();
+
+public:
+ InputChannel(const String8& name, int fd);
+
+ /* Creates a pair of input channels.
+ *
+ * Returns OK on success.
+ */
+ static status_t openInputChannelPair(const String8& name,
+ sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
+
+ inline String8 getName() const { return mName; }
+ inline int getFd() const { return mFd; }
+
+ /* Sends a message to the other endpoint.
+ *
+ * If the channel is full then the message is guaranteed not to have been sent at all.
+ * Try again after the consumer has sent a finished signal indicating that it has
+ * consumed some of the pending messages from the channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t sendMessage(const InputMessage* msg);
+
+ /* Receives a message sent by the other endpoint.
+ *
+ * If there is no message present, try again after poll() indicates that the fd
+ * is readable.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if there is no message present.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t receiveMessage(InputMessage* msg);
+
+private:
+ String8 mName;
+ int mFd;
+};
+
+/*
+ * Publishes input events to an input channel.
+ */
+class InputPublisher {
+public:
+ /* Creates a publisher associated with an input channel. */
+ explicit InputPublisher(const sp<InputChannel>& channel);
+
+ /* Destroys the publisher and releases its input channel. */
+ ~InputPublisher();
+
+ /* Gets the underlying input channel. */
+ inline sp<InputChannel> getChannel() { return mChannel; }
+
+ /* Publishes a key event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Returns BAD_VALUE if seq is 0.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishKeyEvent(
+ uint32_t seq,
+ int32_t deviceId,
+ int32_t source,
+ int32_t action,
+ int32_t flags,
+ int32_t keyCode,
+ int32_t scanCode,
+ int32_t metaState,
+ int32_t repeatCount,
+ nsecs_t downTime,
+ nsecs_t eventTime);
+
+ /* Publishes a motion event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishMotionEvent(
+ uint32_t seq,
+ int32_t deviceId,
+ int32_t source,
+ int32_t action,
+ int32_t flags,
+ int32_t edgeFlags,
+ int32_t metaState,
+ int32_t buttonState,
+ float xOffset,
+ float yOffset,
+ float xPrecision,
+ float yPrecision,
+ nsecs_t downTime,
+ nsecs_t eventTime,
+ size_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords);
+
+ /* Receives the finished signal from the consumer in reply to the original dispatch signal.
+ * If a signal was received, returns the message sequence number,
+ * and whether the consumer handled the message.
+ *
+ * The returned sequence number is never 0 unless the operation failed.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if there is no signal present.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
+
+private:
+ sp<InputChannel> mChannel;
+};
+
+/*
+ * Consumes input events from an input channel.
+ */
+class InputConsumer {
+public:
+ /* Creates a consumer associated with an input channel. */
+ explicit InputConsumer(const sp<InputChannel>& channel);
+
+ /* Destroys the consumer and releases its input channel. */
+ ~InputConsumer();
+
+ /* Gets the underlying input channel. */
+ inline sp<InputChannel> getChannel() { return mChannel; }
+
+ /* Consumes an input event from the input channel and copies its contents into
+ * an InputEvent object created using the specified factory.
+ *
+ * Tries to combine a series of move events into larger batches whenever possible.
+ *
+ * If consumeBatches is false, then defers consuming pending batched events if it
+ * is possible for additional samples to be added to them later. Call hasPendingBatch()
+ * to determine whether a pending batch is available to be consumed.
+ *
+ * If consumeBatches is true, then events are still batched but they are consumed
+ * immediately as soon as the input channel is exhausted.
+ *
+ * The returned sequence number is never 0 unless the operation failed.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if there is no event present.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Returns NO_MEMORY if the event could not be created.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
+ uint32_t* outSeq, InputEvent** outEvent);
+
+ /* Sends a finished signal to the publisher to inform it that the message
+ * with the specified sequence number has finished being process and whether
+ * the message was handled by the consumer.
+ *
+ * Returns OK on success.
+ * Returns BAD_VALUE if seq is 0.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t sendFinishedSignal(uint32_t seq, bool handled);
+
+ /* Returns true if there is a pending batch. */
+ bool hasPendingBatch() const;
+
+private:
+ sp<InputChannel> mChannel;
+
+ // The current input message.
+ InputMessage mMsg;
+
+ // True if mMsg contains a valid input message that was deferred from the previous
+ // call to consume and that still needs to be handled.
+ bool mMsgDeferred;
+
+ // Batched motion events per device and source.
+ struct Batch {
+ uint32_t seq; // sequence number of last input message batched in the event
+ MotionEvent event;
+ };
+ Vector<Batch> mBatches;
+
+ // Chain of batched sequence numbers. When multiple input messages are combined into
+ // a batch, we append a record here that associates the last sequence number in the
+ // batch with the previous one. When the finished signal is sent, we traverse the
+ // chain to individually finish all input messages that were part of the batch.
+ struct SeqChain {
+ uint32_t seq; // sequence number of batched input message
+ uint32_t chain; // sequence number of previous batched input message
+ };
+ Vector<SeqChain> mSeqChains;
+
+ ssize_t findBatch(int32_t deviceId, int32_t source) const;
+ status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
+
+ static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
+ static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
+ static bool canAppendSamples(const MotionEvent* event, const InputMessage* msg);
+ static void appendSamples(MotionEvent* event, const InputMessage* msg);
+};
+
+} // namespace android
+
+#endif // _ANDROIDFW_INPUT_TRANSPORT_H
diff --git a/include/ui/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
similarity index 97%
rename from include/ui/KeyCharacterMap.h
rename to include/androidfw/KeyCharacterMap.h
index be14432..679dd2c 100644
--- a/include/ui/KeyCharacterMap.h
+++ b/include/androidfw/KeyCharacterMap.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef _UI_KEY_CHARACTER_MAP_H
-#define _UI_KEY_CHARACTER_MAP_H
+#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H
+#define _ANDROIDFW_KEY_CHARACTER_MAP_H
#include <stdint.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
@@ -196,4 +196,4 @@
} // namespace android
-#endif // _UI_KEY_CHARACTER_MAP_H
+#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/ui/KeyLayoutMap.h b/include/androidfw/KeyLayoutMap.h
similarity index 95%
rename from include/ui/KeyLayoutMap.h
rename to include/androidfw/KeyLayoutMap.h
index d82d0c8..5a6f550 100644
--- a/include/ui/KeyLayoutMap.h
+++ b/include/androidfw/KeyLayoutMap.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _UI_KEY_LAYOUT_MAP_H
-#define _UI_KEY_LAYOUT_MAP_H
+#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H
+#define _ANDROIDFW_KEY_LAYOUT_MAP_H
#include <stdint.h>
#include <utils/Errors.h>
@@ -96,4 +96,4 @@
} // namespace android
-#endif // _UI_KEY_LAYOUT_MAP_H
+#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H
diff --git a/include/ui/Keyboard.h b/include/androidfw/Keyboard.h
similarity index 96%
rename from include/ui/Keyboard.h
rename to include/androidfw/Keyboard.h
index 274f526..ae65198 100644
--- a/include/ui/Keyboard.h
+++ b/include/androidfw/Keyboard.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef _UI_KEYBOARD_H
-#define _UI_KEYBOARD_H
+#ifndef _ANDROIDFW_KEYBOARD_H
+#define _ANDROIDFW_KEYBOARD_H
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/PropertyMap.h>
@@ -116,4 +116,4 @@
} // namespace android
-#endif // _UI_KEYBOARD_H
+#endif // _ANDROIDFW_KEYBOARD_H
diff --git a/include/ui/KeycodeLabels.h b/include/androidfw/KeycodeLabels.h
similarity index 98%
rename from include/ui/KeycodeLabels.h
rename to include/androidfw/KeycodeLabels.h
index c5bd0c5..9e4dfcb 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/androidfw/KeycodeLabels.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _UI_KEYCODE_LABELS_H
-#define _UI_KEYCODE_LABELS_H
+#ifndef _ANDROIDFW_KEYCODE_LABELS_H
+#define _ANDROIDFW_KEYCODE_LABELS_H
#include <android/keycodes.h>
@@ -307,4 +307,4 @@
{ NULL, -1 }
};
-#endif // _UI_KEYCODE_LABELS_H
+#endif // _ANDROIDFW_KEYCODE_LABELS_H
diff --git a/include/utils/ObbFile.h b/include/androidfw/ObbFile.h
similarity index 100%
rename from include/utils/ObbFile.h
rename to include/androidfw/ObbFile.h
diff --git a/include/ui/PowerManager.h b/include/androidfw/PowerManager.h
similarity index 88%
rename from include/ui/PowerManager.h
rename to include/androidfw/PowerManager.h
index dd80318..59e993a 100644
--- a/include/ui/PowerManager.h
+++ b/include/androidfw/PowerManager.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _UI_POWER_MANAGER_H
-#define _UI_POWER_MANAGER_H
+#ifndef _ANDROIDFW_POWER_MANAGER_H
+#define _ANDROIDFW_POWER_MANAGER_H
namespace android {
@@ -30,4 +30,4 @@
} // namespace android
-#endif // _UI_POWER_MANAGER_H
+#endif // _ANDROIDFW_POWER_MANAGER_H
diff --git a/include/utils/ResourceTypes.h b/include/androidfw/ResourceTypes.h
similarity index 99%
rename from include/utils/ResourceTypes.h
rename to include/androidfw/ResourceTypes.h
index c496da6..23bca3e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -20,7 +20,7 @@
#ifndef _LIBS_UTILS_RESOURCE_TYPES_H
#define _LIBS_UTILS_RESOURCE_TYPES_H
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
#include <utils/ByteOrder.h>
#include <utils/Errors.h>
#include <utils/String16.h>
diff --git a/include/utils/StreamingZipInflater.h b/include/androidfw/StreamingZipInflater.h
similarity index 100%
rename from include/utils/StreamingZipInflater.h
rename to include/androidfw/StreamingZipInflater.h
diff --git a/include/ui/VirtualKeyMap.h b/include/androidfw/VirtualKeyMap.h
similarity index 92%
rename from include/ui/VirtualKeyMap.h
rename to include/androidfw/VirtualKeyMap.h
index 7813d9d..66340e3 100644
--- a/include/ui/VirtualKeyMap.h
+++ b/include/androidfw/VirtualKeyMap.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef _UI_VIRTUAL_KEY_MAP_H
-#define _UI_VIRTUAL_KEY_MAP_H
+#ifndef _ANDROIDFW_VIRTUAL_KEY_MAP_H
+#define _ANDROIDFW_VIRTUAL_KEY_MAP_H
#include <stdint.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
@@ -76,4 +76,4 @@
} // namespace android
-#endif // _UI_KEY_CHARACTER_MAP_H
+#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/utils/ZipFileCRO.h b/include/androidfw/ZipFileCRO.h
similarity index 100%
rename from include/utils/ZipFileCRO.h
rename to include/androidfw/ZipFileCRO.h
diff --git a/include/utils/ZipFileRO.h b/include/androidfw/ZipFileRO.h
similarity index 100%
rename from include/utils/ZipFileRO.h
rename to include/androidfw/ZipFileRO.h
diff --git a/include/utils/ZipUtils.h b/include/androidfw/ZipUtils.h
similarity index 100%
rename from include/utils/ZipUtils.h
rename to include/androidfw/ZipUtils.h
diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h
index 2316fef..ca594d3 100644
--- a/include/binder/BinderService.h
+++ b/include/binder/BinderService.h
@@ -34,15 +34,15 @@
class BinderService
{
public:
- static status_t publish() {
+ static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
- return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+ return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
}
- static void publishAndJoinThreadPool() {
+ static void publishAndJoinThreadPool(bool allowIsolated = false) {
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
- sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+ sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
index 24e9e99..2c297d6 100644
--- a/include/binder/IServiceManager.h
+++ b/include/binder/IServiceManager.h
@@ -47,7 +47,8 @@
* Register a service.
*/
virtual status_t addService( const String16& name,
- const sp<IBinder>& service) = 0;
+ const sp<IBinder>& service,
+ bool allowIsolated = false) = 0;
/**
* Return list of all existing services.
diff --git a/include/common_time/ICommonClock.h b/include/common_time/ICommonClock.h
new file mode 100644
index 0000000..d7073f1
--- /dev/null
+++ b/include/common_time/ICommonClock.h
@@ -0,0 +1,108 @@
+/*
+ * 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 ANDROID_ICOMMONCLOCK_H
+#define ANDROID_ICOMMONCLOCK_H
+
+#include <stdint.h>
+#include <linux/socket.h>
+
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class ICommonClockListener : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(CommonClockListener);
+
+ virtual void onTimelineChanged(uint64_t timelineID) = 0;
+};
+
+class BnCommonClockListener : public BnInterface<ICommonClockListener> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+class ICommonClock : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(CommonClock);
+
+ // Name of the ICommonClock service registered with the service manager.
+ static const String16 kServiceName;
+
+ // a reserved invalid timeline ID
+ static const uint64_t kInvalidTimelineID;
+
+ // a reserved invalid error estimate
+ static const int32_t kErrorEstimateUnknown;
+
+ enum State {
+ // the device just came up and is trying to discover the master
+ STATE_INITIAL,
+
+ // the device is a client of a master
+ STATE_CLIENT,
+
+ // the device is acting as master
+ STATE_MASTER,
+
+ // the device has lost contact with its master and needs to participate
+ // in the election of a new master
+ STATE_RONIN,
+
+ // the device is waiting for announcement of the newly elected master
+ STATE_WAIT_FOR_ELECTION,
+ };
+
+ virtual status_t isCommonTimeValid(bool* valid, uint32_t* timelineID) = 0;
+ virtual status_t commonTimeToLocalTime(int64_t commonTime,
+ int64_t* localTime) = 0;
+ virtual status_t localTimeToCommonTime(int64_t localTime,
+ int64_t* commonTime) = 0;
+ virtual status_t getCommonTime(int64_t* commonTime) = 0;
+ virtual status_t getCommonFreq(uint64_t* freq) = 0;
+ virtual status_t getLocalTime(int64_t* localTime) = 0;
+ virtual status_t getLocalFreq(uint64_t* freq) = 0;
+ virtual status_t getEstimatedError(int32_t* estimate) = 0;
+ virtual status_t getTimelineID(uint64_t* id) = 0;
+ virtual status_t getState(State* state) = 0;
+ virtual status_t getMasterAddr(struct sockaddr_storage* addr) = 0;
+
+ virtual status_t registerListener(
+ const sp<ICommonClockListener>& listener) = 0;
+ virtual status_t unregisterListener(
+ const sp<ICommonClockListener>& listener) = 0;
+
+ // Simple helper to make it easier to connect to the CommonClock service.
+ static inline sp<ICommonClock> getInstance() {
+ sp<IBinder> binder = defaultServiceManager()->checkService(
+ ICommonClock::kServiceName);
+ sp<ICommonClock> clk = interface_cast<ICommonClock>(binder);
+ return clk;
+ }
+};
+
+class BnCommonClock : public BnInterface<ICommonClock> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_ICOMMONCLOCK_H
diff --git a/include/common_time/ICommonTimeConfig.h b/include/common_time/ICommonTimeConfig.h
new file mode 100644
index 0000000..497b666
--- /dev/null
+++ b/include/common_time/ICommonTimeConfig.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_ICOMMONTIMECONFIG_H
+#define ANDROID_ICOMMONTIMECONFIG_H
+
+#include <stdint.h>
+#include <linux/socket.h>
+
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class String16;
+
+class ICommonTimeConfig : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(CommonTimeConfig);
+
+ // Name of the ICommonTimeConfig service registered with the service
+ // manager.
+ static const String16 kServiceName;
+
+ virtual status_t getMasterElectionPriority(uint8_t *priority) = 0;
+ virtual status_t setMasterElectionPriority(uint8_t priority) = 0;
+ virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr) = 0;
+ virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr) = 0;
+ virtual status_t getMasterElectionGroupId(uint64_t *id) = 0;
+ virtual status_t setMasterElectionGroupId(uint64_t id) = 0;
+ virtual status_t getInterfaceBinding(String16& ifaceName) = 0;
+ virtual status_t setInterfaceBinding(const String16& ifaceName) = 0;
+ virtual status_t getMasterAnnounceInterval(int *interval) = 0;
+ virtual status_t setMasterAnnounceInterval(int interval) = 0;
+ virtual status_t getClientSyncInterval(int *interval) = 0;
+ virtual status_t setClientSyncInterval(int interval) = 0;
+ virtual status_t getPanicThreshold(int *threshold) = 0;
+ virtual status_t setPanicThreshold(int threshold) = 0;
+ virtual status_t getAutoDisable(bool *autoDisable) = 0;
+ virtual status_t setAutoDisable(bool autoDisable) = 0;
+ virtual status_t forceNetworklessMasterMode() = 0;
+
+ // Simple helper to make it easier to connect to the CommonTimeConfig service.
+ static inline sp<ICommonTimeConfig> getInstance() {
+ sp<IBinder> binder = defaultServiceManager()->checkService(
+ ICommonTimeConfig::kServiceName);
+ sp<ICommonTimeConfig> clk = interface_cast<ICommonTimeConfig>(binder);
+ return clk;
+ }
+};
+
+class BnCommonTimeConfig : public BnInterface<ICommonTimeConfig> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_ICOMMONTIMECONFIG_H
diff --git a/include/common_time/cc_helper.h b/include/common_time/cc_helper.h
new file mode 100644
index 0000000..8c4d5c0
--- /dev/null
+++ b/include/common_time/cc_helper.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __CC_HELPER_H__
+#define __CC_HELPER_H__
+
+#include <stdint.h>
+#include <common_time/ICommonClock.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// CCHelper is a simple wrapper class to help with centralizing access to the
+// Common Clock service and implementing lifetime managment, as well as to
+// implement a simple policy of making a basic attempt to reconnect to the
+// common clock service when things go wrong.
+//
+// On platforms which run the native common_time service in auto-disable mode,
+// the service will go into networkless mode whenever it has no active clients.
+// It tracks active clients using registered CommonClockListeners (the callback
+// interface for onTimelineChanged) since this provides a convienent death
+// handler notification for when the service's clients die unexpectedly. This
+// means that users of the common time service should really always have a
+// CommonClockListener, unless they know that the time service is not running in
+// auto disabled mode, or that there is at least one other registered listener
+// active in the system. The CCHelper makes this a little easier by sharing a
+// ref counted ICommonClock interface across all clients and automatically
+// registering and unregistering a listener whenever there are CCHelper
+// instances active in the process.
+class CCHelper {
+ public:
+ CCHelper();
+ ~CCHelper();
+
+ status_t isCommonTimeValid(bool* valid, uint32_t* timelineID);
+ status_t commonTimeToLocalTime(int64_t commonTime, int64_t* localTime);
+ status_t localTimeToCommonTime(int64_t localTime, int64_t* commonTime);
+ status_t getCommonTime(int64_t* commonTime);
+ status_t getCommonFreq(uint64_t* freq);
+ status_t getLocalTime(int64_t* localTime);
+ status_t getLocalFreq(uint64_t* freq);
+
+ private:
+ class CommonClockListener : public BnCommonClockListener {
+ public:
+ void onTimelineChanged(uint64_t timelineID);
+ };
+
+ static bool verifyClock_l();
+
+ static Mutex lock_;
+ static sp<ICommonClock> common_clock_;
+ static sp<ICommonClockListener> common_clock_listener_;
+ static uint32_t ref_count_;
+};
+
+
+} // namespace android
+#endif // __CC_HELPER_H__
diff --git a/include/common_time/local_clock.h b/include/common_time/local_clock.h
new file mode 100644
index 0000000..845d1c21
--- /dev/null
+++ b/include/common_time/local_clock.h
@@ -0,0 +1,47 @@
+/*
+ * 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 __LOCAL_CLOCK_H__
+#define __LOCAL_CLOCK_H__
+
+#include <stdint.h>
+
+#include <hardware/local_time_hal.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class LocalClock {
+ public:
+ LocalClock();
+
+ bool initCheck();
+
+ int64_t getLocalTime();
+ uint64_t getLocalFreq();
+ status_t setLocalSlew(int16_t rate);
+ int32_t getDebugLog(struct local_time_debug_event* records,
+ int max_records);
+
+ private:
+ static Mutex dev_lock_;
+ static local_time_hw_device_t* dev_;
+};
+
+} // namespace android
+#endif // __LOCAL_CLOCK_H__
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 991a181..ae99160 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -60,6 +60,8 @@
BufferQueue(bool allowSynchronousMode = true);
virtual ~BufferQueue();
+ virtual int query(int what, int* value);
+
// setBufferCount updates the number of available buffer slots. After
// calling this all buffer slots are both unallocated and owned by the
// BufferQueue object (i.e. they are not owned by the client).
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 4318f0f..dcab049 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -55,7 +55,7 @@
virtual ~SurfaceTexture();
- virtual int query(int what, int* value);
+
// updateTexImage sets the image contents of the target texture to that of
// the most recently queued buffer.
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index ca57f9e..437a89c 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -341,7 +341,7 @@
private:
friend class AudioRecord;
virtual bool threadLoop();
- virtual status_t readyToRun() { return NO_ERROR; }
+ virtual status_t readyToRun();
virtual void onFirstRef() {}
AudioRecord& mReceiver;
};
@@ -359,7 +359,9 @@
sp<IAudioRecord> mAudioRecord;
sp<IMemory> mCblkMemory;
sp<ClientRecordThread> mClientRecordThread;
+ status_t mReadyToRun;
Mutex mLock;
+ Condition mCondition;
uint32_t mFrameCount;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index da99620..1916ac5 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -131,7 +131,7 @@
NUM_CONFIG_EVENTS
};
- // audio output descritor used to cache output configurations in client process to avoid frequent calls
+ // audio output descriptor used to cache output configurations in client process to avoid frequent calls
// through IAudioFlinger
class OutputDescriptor {
public:
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 11db81b..9f2bd3a 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -58,8 +58,8 @@
EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer.
};
- /* Create Buffer on the stack and pass it to obtainBuffer()
- * and releaseBuffer().
+ /* Client should declare Buffer on the stack and pass address to obtainBuffer()
+ * and releaseBuffer(). See also callback_t for EVENT_MORE_DATA.
*/
class Buffer
@@ -68,12 +68,16 @@
enum {
MUTE = 0x00000001
};
- uint32_t flags;
+ uint32_t flags; // 0 or MUTE
audio_format_t format; // but AUDIO_FORMAT_PCM_8_BIT -> AUDIO_FORMAT_PCM_16_BIT
// accessed directly by WebKit ANP callback
int channelCount; // will be removed in the future, do not use
- size_t frameCount;
- size_t size;
+
+ size_t frameCount; // number of sample frames corresponding to size;
+ // on input it is the number of frames desired,
+ // on output is the number of frames actually filled
+
+ size_t size; // input/output in byte units
union {
void* raw;
short* i16; // signed 16-bit
@@ -84,15 +88,15 @@
/* As a convenience, if a callback is supplied, a handler thread
* is automatically created with the appropriate priority. This thread
- * invokes the callback when a new buffer becomes available or an underrun condition occurs.
+ * invokes the callback when a new buffer becomes available or various conditions occur.
* Parameters:
*
* event: type of event notified (see enum AudioTrack::event_type).
* user: Pointer to context for use by the callback receiver.
* info: Pointer to optional parameter according to event type:
* - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write
- * more bytes than indicated by 'size' field and update 'size' if less bytes are
- * written.
+ * more bytes than indicated by 'size' field and update 'size' if fewer bytes are
+ * written.
* - EVENT_UNDERRUN: unused.
* - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
* - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames.
@@ -225,7 +229,7 @@
*/
uint32_t latency() const;
- /* getters, see constructor */
+ /* getters, see constructors and set() */
audio_stream_type_t streamType() const;
audio_format_t format() const;
@@ -299,7 +303,6 @@
* (loopEnd-loopStart) <= framecount()
*/
status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
- status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const;
/* Sets marker position. When playback reaches the number of frames specified, a callback with
* event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
@@ -401,13 +404,19 @@
status_t attachAuxEffect(int effectId);
/* Obtains a buffer of "frameCount" frames. The buffer must be
- * filled entirely. If the track is stopped, obtainBuffer() returns
+ * filled entirely, and then released with releaseBuffer().
+ * If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers available,
* at which point NO_MORE_BUFFERS is returned.
* Buffers will be returned until the pool (buffercount())
* is exhausted, at which point obtainBuffer() will either block
* or return WOULD_BLOCK depending on the value of the "blocking"
* parameter.
+ *
+ * Interpretation of waitCount:
+ * +n limits wait time to n * WAIT_PERIOD_MS,
+ * -1 causes an (almost) infinite wait time,
+ * 0 non-blocking.
*/
enum {
@@ -416,12 +425,19 @@
};
status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+
+ /* Release a filled buffer of "frameCount" frames for AudioFlinger to process. */
void releaseBuffer(Buffer* audioBuffer);
/* As a convenience we provide a write() interface to the audio buffer.
- * This is implemented on top of lockBuffer/unlockBuffer. For best
- * performance use callbacks. Return actual number of bytes written.
- *
+ * This is implemented on top of obtainBuffer/releaseBuffer. For best
+ * performance use callbacks. Returns actual number of bytes written >= 0,
+ * or one of the following negative status codes:
+ * INVALID_OPERATION AudioTrack is configured for shared buffer mode
+ * BAD_VALUE size is invalid
+ * STOPPED AudioTrack was stopped during the write
+ * NO_MORE_BUFFERS when obtainBuffer() returns same
+ * or any other error code returned by IAudioTrack::start() or restoreTrack_l().
*/
ssize_t write(const void* buffer, size_t size);
@@ -430,7 +446,7 @@
*/
status_t dump(int fd, const Vector<String16>& args) const;
-private:
+protected:
/* copying audio tracks is not allowed */
AudioTrack(const AudioTrack& other);
AudioTrack& operator = (const AudioTrack& other);
@@ -448,6 +464,7 @@
AudioTrack& mReceiver;
};
+ // body of AudioTrackThread::threadLoop()
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
status_t createTrack_l(audio_stream_type_t streamType,
uint32_t sampleRate,
@@ -484,7 +501,7 @@
bool mActive; // protected by mLock
- callback_t mCbf;
+ callback_t mCbf; // callback handler for events, or NULL
void* mUserData;
uint32_t mNotificationFramesReq; // requested number of frames between each notification callback
uint32_t mNotificationFramesAct; // actual number of frames between each notification callback
@@ -501,10 +518,33 @@
int mAuxEffectId;
mutable Mutex mLock;
status_t mRestoreStatus;
+ bool mIsTimed;
int mPreviousPriority; // before start()
int mPreviousSchedulingGroup;
};
+class TimedAudioTrack : public AudioTrack
+{
+public:
+ TimedAudioTrack();
+
+ /* allocate a shared memory buffer that can be passed to queueTimedBuffer */
+ status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer);
+
+ /* queue a buffer obtained via allocateTimedBuffer for playback at the
+ given timestamp. PTS units a microseconds on the media time timeline.
+ The media time transform (set with setMediaTimeTransform) set by the
+ audio producer will handle converting from media time to local time
+ (perhaps going through the common time timeline in the case of
+ synchronized multiroom audio case) */
+ status_t queueTimedBuffer(const sp<IMemory>& buffer, int64_t pts);
+
+ /* define a transform between media time and either common time or
+ local time */
+ enum TargetTimeline {LOCAL_TIME, COMMON_TIME};
+ status_t setMediaTimeTransform(const LinearTransform& xform,
+ TargetTimeline target);
+};
}; // namespace android
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
index df83995..65c26f47 100644
--- a/include/media/EffectsFactoryApi.h
+++ b/include/media/EffectsFactoryApi.h
@@ -87,7 +87,7 @@
// Description: Creates an effect engine of the specified type and returns an
// effect control interface on this engine. The function will allocate the
// resources for an instance of the requested effect engine and return
-// a handler on the effect control interface.
+// a handle on the effect control interface.
//
// Input:
// pEffectUuid: pointer to the effect uuid.
@@ -115,17 +115,17 @@
//
// Function: EffectRelease
//
-// Description: Releases the effect engine whose handler is given as argument.
+// Description: Releases the effect engine whose handle is given as argument.
// All resources allocated to this particular instance of the effect are
// released.
//
// Input:
-// handle: handler on the effect interface to be released.
+// handle: handle on the effect interface to be released.
//
// Output:
// returned value: 0 successful operation.
// -ENODEV factory failed to initialize
-// -EINVAL invalid interface handler
+// -EINVAL invalid interface handle
//
////////////////////////////////////////////////////////////////////////////////
int EffectRelease(effect_handle_t handle);
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 433ce7c..7a2ada0 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -55,6 +55,7 @@
uint32_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ bool isTimed,
int *sessionId,
status_t *status) = 0;
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index 46735de..7869020 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -37,8 +37,9 @@
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
+ * tid identifies the client callback thread, or 0 if not needed.
*/
- virtual status_t start() = 0;
+ virtual status_t start(pid_t tid) = 0;
/* Stop a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index b83e552..77f3e21 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -24,7 +24,7 @@
#include <utils/Errors.h>
#include <binder/IInterface.h>
#include <binder/IMemory.h>
-
+#include <utils/LinearTransform.h>
namespace android {
@@ -40,17 +40,18 @@
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
+ * tid identifies the client callback thread, or 0 if not needed.
*/
- virtual status_t start() = 0;
+ virtual status_t start(pid_t tid) = 0;
/* Stop a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
- * will be processed, unless flush() is called.
+ * will continue to be processed, unless/until flush() is called.
*/
virtual void stop() = 0;
- /* Flush a stopped track. All pending buffers are discarded.
- * This function has no effect if the track is not stopped.
+ /* Flush a stopped or paused track. All pending/released buffers are discarded.
+ * This function has no effect if the track is not stopped or paused.
*/
virtual void flush() = 0;
@@ -61,7 +62,7 @@
/* Pause a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
- * will be processed, unless flush() is called.
+ * will continue to be processed, unless/until flush() is called.
*/
virtual void pause() = 0;
@@ -70,6 +71,23 @@
*/
virtual status_t attachAuxEffect(int effectId) = 0;
+
+ /* Allocate a shared memory buffer suitable for holding timed audio
+ samples */
+ virtual status_t allocateTimedBuffer(size_t size,
+ sp<IMemory>* buffer) = 0;
+
+ /* Queue a buffer obtained via allocateTimedBuffer for playback at the given
+ timestamp */
+ virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
+ int64_t pts) = 0;
+
+ /* Define the linear transform that will be applied to the timestamps
+ given to queueTimedBuffer (which are expressed in media time).
+ Target specifies whether this transform converts media time to local time
+ or Tungsten time. The values for target are defined in AudioTrack.h */
+ virtual status_t setMediaTimeTransform(const LinearTransform& xform,
+ int target) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 7beb176..23a3e49 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -46,6 +46,9 @@
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
+
+ AAH_RX_PLAYER = 100,
+ AAH_TX_PLAYER = 101,
};
@@ -96,6 +99,8 @@
virtual void flush() = 0;
virtual void pause() = 0;
virtual void close() = 0;
+
+ virtual status_t setPlaybackRatePermille(int32_t rate) { return INVALID_OPERATION; }
};
MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
index 290b748..ac0f6b2 100644
--- a/include/media/MemoryLeakTrackUtil.h
+++ b/include/media/MemoryLeakTrackUtil.h
@@ -19,7 +19,7 @@
namespace android {
/*
- * Dump the memory adddress of the calling process to the given fd.
+ * Dump the memory address of the calling process to the given fd.
*/
extern void dumpMemoryAddresses(int fd);
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 00b7dd5..d0b87c8 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -145,6 +145,9 @@
// audio track, or zero for error (e.g. no audio track) or unknown.
KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
+ // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
+ // values used for rewinding or reverse playback.
+ KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
};
// ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 0b79324..70c47ae 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -64,6 +64,8 @@
bool isSeeking();
bool reachedEOS(status_t *finalStatus);
+ status_t setPlaybackRatePermille(int32_t ratePermille);
+
private:
friend class VideoEditorAudioPlayer;
sp<MediaSource> mSource;
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
deleted file mode 100644
index 2ca9667..0000000
--- a/include/media/stagefright/MediaDebug.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_DEBUG_H_
-
-#define MEDIA_DEBUG_H_
-
-#include <cutils/log.h>
-
-#define LITERAL_TO_STRING_INTERNAL(x) #x
-#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
-
-#define CHECK_EQ(x,y) \
- LOG_ALWAYS_FATAL_IF( \
- (x) != (y), \
- __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
-
-#define CHECK(x) \
- LOG_ALWAYS_FATAL_IF( \
- !(x), \
- __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
-
-#endif // MEDIA_DEBUG_H_
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 23226c0..af2db93 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -62,16 +62,23 @@
// are in the same line of data cache.
Mutex lock; // sizeof(int)
Condition cv; // sizeof(int)
+
+ // next 4 are offsets within "buffers"
volatile uint32_t user;
volatile uint32_t server;
uint32_t userBase;
uint32_t serverBase;
+
+ // if there is a shared buffer, "buffers" is the value of pointer() for the shared
+ // buffer, otherwise "buffers" points immediately after the control block
void* buffers;
uint32_t frameCount;
+
// Cache line boundary
+
uint32_t loopStart;
- uint32_t loopEnd;
- int loopCount;
+ uint32_t loopEnd; // read-only for server, read/write for client
+ int loopCount; // read/write for client
// Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
// Left channel is in [0:15], right channel is in [16:31].
@@ -82,29 +89,39 @@
public:
uint32_t sampleRate;
+
// NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
// 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of
// 16 bit because data is converted to 16 bit before being stored in buffer
+ // read-only for client, server writes once at initialization and is then read-only
uint8_t frameSize; // would normally be size_t, but 8 bits is plenty
+
+ // never used
uint8_t pad1;
+
+ // used by client only
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
- uint16_t waitTimeMs; // Cumulated wait time
+ uint16_t waitTimeMs; // Cumulated wait time, used by client only
private:
+ // client write-only, server read-only
uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0
public:
volatile int32_t flags;
// Cache line boundary (32 bytes)
+ // Since the control block is always located in shared memory, this constructor
+ // is only used for placement new(). It is never used for regular new() or stack.
audio_track_cblk_t();
- uint32_t stepUser(uint32_t frameCount);
- bool stepServer(uint32_t frameCount);
+ uint32_t stepUser(uint32_t frameCount); // called by client only, where
+ // client includes regular AudioTrack and AudioFlinger::PlaybackThread::OutputTrack
+ bool stepServer(uint32_t frameCount); // called by server only
void* buffer(uint32_t offset) const;
uint32_t framesAvailable();
uint32_t framesAvailable_l();
- uint32_t framesReady();
+ uint32_t framesReady(); // called by server only
bool tryLock();
// No barriers on the following operations, so the ordering of loads/stores
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
deleted file mode 100644
index 95e4447..0000000
--- a/include/ui/InputTransport.h
+++ /dev/null
@@ -1,338 +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.
- */
-
-#ifndef _UI_INPUT_TRANSPORT_H
-#define _UI_INPUT_TRANSPORT_H
-
-/**
- * Native input transport.
- *
- * Uses anonymous shared memory as a whiteboard for sending input events from an
- * InputPublisher to an InputConsumer and ensuring appropriate synchronization.
- * One interesting feature is that published events can be updated in place as long as they
- * have not yet been consumed.
- *
- * The InputPublisher and InputConsumer only take care of transferring event data
- * over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue
- * build on these abstractions to add multiplexing and queueing.
- */
-
-#include <semaphore.h>
-#include <ui/Input.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-namespace android {
-
-/*
- * An input channel consists of a shared memory buffer and a pair of pipes
- * used to send input messages from an InputPublisher to an InputConsumer
- * across processes. Each channel has a descriptive name for debugging purposes.
- *
- * Each endpoint has its own InputChannel object that specifies its own file descriptors.
- *
- * The input channel is closed when all references to it are released.
- */
-class InputChannel : public RefBase {
-protected:
- virtual ~InputChannel();
-
-public:
- InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
- int32_t sendPipeFd);
-
- /* Creates a pair of input channels and their underlying shared memory buffers
- * and pipes.
- *
- * Returns OK on success.
- */
- static status_t openInputChannelPair(const String8& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
-
- inline String8 getName() const { return mName; }
- inline int32_t getAshmemFd() const { return mAshmemFd; }
- inline int32_t getReceivePipeFd() const { return mReceivePipeFd; }
- inline int32_t getSendPipeFd() const { return mSendPipeFd; }
-
- /* Sends a signal to the other endpoint.
- *
- * Returns OK on success.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Other errors probably indicate that the channel is broken.
- */
- status_t sendSignal(char signal);
-
- /* Receives a signal send by the other endpoint.
- * (Should only call this after poll() indicates that the receivePipeFd has available input.)
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Other errors probably indicate that the channel is broken.
- */
- status_t receiveSignal(char* outSignal);
-
-private:
- String8 mName;
- int32_t mAshmemFd;
- int32_t mReceivePipeFd;
- int32_t mSendPipeFd;
-};
-
-/*
- * Private intermediate representation of input events as messages written into an
- * ashmem buffer.
- */
-struct InputMessage {
- /* Semaphore count is set to 1 when the message is published.
- * It becomes 0 transiently while the publisher updates the message.
- * It becomes 0 permanently when the consumer consumes the message.
- */
- sem_t semaphore;
-
- /* Initialized to false by the publisher.
- * Set to true by the consumer when it consumes the message.
- */
- bool consumed;
-
- int32_t type;
-
- struct SampleData {
- nsecs_t eventTime;
- PointerCoords coords[0]; // variable length
- };
-
- int32_t deviceId;
- int32_t source;
-
- union {
- struct {
- int32_t action;
- int32_t flags;
- int32_t keyCode;
- int32_t scanCode;
- int32_t metaState;
- int32_t repeatCount;
- nsecs_t downTime;
- nsecs_t eventTime;
- } key;
-
- struct {
- int32_t action;
- int32_t flags;
- int32_t metaState;
- int32_t buttonState;
- int32_t edgeFlags;
- nsecs_t downTime;
- float xOffset;
- float yOffset;
- float xPrecision;
- float yPrecision;
- size_t pointerCount;
- PointerProperties pointerProperties[MAX_POINTERS];
- size_t sampleCount;
- SampleData sampleData[0]; // variable length
- } motion;
- };
-
- /* Gets the number of bytes to add to step to the next SampleData object in a motion
- * event message for a given number of pointers.
- */
- static inline size_t sampleDataStride(size_t pointerCount) {
- return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
- }
-
- /* Adds the SampleData stride to the given pointer. */
- static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) {
- return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride);
- }
-};
-
-/*
- * Publishes input events to an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent consumer.
- */
-class InputPublisher {
-public:
- /* Creates a publisher associated with an input channel. */
- explicit InputPublisher(const sp<InputChannel>& channel);
-
- /* Destroys the publisher and releases its input channel. */
- ~InputPublisher();
-
- /* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
-
- /* Prepares the publisher for use. Must be called before it is used.
- * Returns OK on success.
- *
- * This method implicitly calls reset(). */
- status_t initialize();
-
- /* Resets the publisher to its initial state and unpins its ashmem buffer.
- * Returns OK on success.
- *
- * Should be called after an event has been consumed to release resources used by the
- * publisher until the next event is ready to be published.
- */
- status_t reset();
-
- /* Publishes a key event to the ashmem buffer.
- *
- * Returns OK on success.
- * Returns INVALID_OPERATION if the publisher has not been reset.
- */
- status_t publishKeyEvent(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime);
-
- /* Publishes a motion event to the ashmem buffer.
- *
- * Returns OK on success.
- * Returns INVALID_OPERATION if the publisher has not been reset.
- * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS.
- */
- status_t publishMotionEvent(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords);
-
- /* Appends a motion sample to a motion event unless already consumed.
- *
- * Returns OK on success.
- * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event.
- * Returns FAILED_TRANSACTION if the current event has already been consumed.
- * Returns NO_MEMORY if the buffer is full and no additional samples can be added.
- */
- status_t appendMotionSample(
- nsecs_t eventTime,
- const PointerCoords* pointerCoords);
-
- /* Sends a dispatch signal to the consumer to inform it that a new message is available.
- *
- * Returns OK on success.
- * Errors probably indicate that the channel is broken.
- */
- status_t sendDispatchSignal();
-
- /* Receives the finished signal from the consumer in reply to the original dispatch signal.
- * Returns whether the consumer handled the message.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
- * Other errors probably indicate that the channel is broken.
- */
- status_t receiveFinishedSignal(bool* outHandled);
-
-private:
- sp<InputChannel> mChannel;
-
- size_t mAshmemSize;
- InputMessage* mSharedMessage;
- bool mPinned;
- bool mSemaphoreInitialized;
- bool mWasDispatched;
-
- size_t mMotionEventPointerCount;
- InputMessage::SampleData* mMotionEventSampleDataTail;
- size_t mMotionEventSampleDataStride;
-
- status_t publishInputEvent(
- int32_t type,
- int32_t deviceId,
- int32_t source);
-};
-
-/*
- * Consumes input events from an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent publisher.
- */
-class InputConsumer {
-public:
- /* Creates a consumer associated with an input channel. */
- explicit InputConsumer(const sp<InputChannel>& channel);
-
- /* Destroys the consumer and releases its input channel. */
- ~InputConsumer();
-
- /* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
-
- /* Prepares the consumer for use. Must be called before it is used. */
- status_t initialize();
-
- /* Consumes the input event in the buffer and copies its contents into
- * an InputEvent object created using the specified factory.
- * This operation will block if the publisher is updating the event.
- *
- * Returns OK on success.
- * Returns INVALID_OPERATION if there is no currently published event.
- * Returns NO_MEMORY if the event could not be created.
- */
- status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
-
- /* Sends a finished signal to the publisher to inform it that the current message is
- * finished processing and specifies whether the message was handled by the consumer.
- *
- * Returns OK on success.
- * Errors probably indicate that the channel is broken.
- */
- status_t sendFinishedSignal(bool handled);
-
- /* Receives the dispatched signal from the publisher.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
- * Other errors probably indicate that the channel is broken.
- */
- status_t receiveDispatchSignal();
-
-private:
- sp<InputChannel> mChannel;
-
- size_t mAshmemSize;
- InputMessage* mSharedMessage;
-
- void populateKeyEvent(KeyEvent* keyEvent) const;
- void populateMotionEvent(MotionEvent* motionEvent) const;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_TRANSPORT_H
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index 6bcdea4..fcc3bcf 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -66,7 +66,7 @@
ssize_t indexOfKey(const KEY& key) const;
/*!
- * modifing the array
+ * modifying the array
*/
VALUE& editValueFor(const KEY& key);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index db6388a..0fe7bd8 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -124,7 +124,7 @@
public static final String EXTRA_SENDER = "sender";
/**
- * Action to bring up the CertInstaller
+ * Action to bring up the CertInstaller.
*/
private static final String ACTION_INSTALL = "android.credentials.INSTALL";
@@ -167,6 +167,22 @@
// Compatible with old android.security.Credentials.PKCS12
public static final String EXTRA_PKCS12 = "PKCS12";
+
+ /**
+ * @hide TODO This is temporary and will be removed
+ * Broadcast Action: Indicates the trusted storage has changed. Sent when
+ * one of this happens:
+ *
+ * <ul>
+ * <li>a new CA is added,
+ * <li>an existing CA is removed or disabled,
+ * <li>a disabled CA is enabled,
+ * <li>trusted storage is reset (all user certs are cleared),
+ * <li>when permission to access a private key is changed.
+ * </ul>
+ */
+ public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
+
/**
* Returns an {@code Intent} that can be used for credential
* installation. The intent may be used without any extras, in
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 33b305d..1750640 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -151,12 +151,14 @@
return reply.readStrongBinder();
}
- virtual status_t addService(const String16& name, const sp<IBinder>& service)
+ virtual status_t addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
+ data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk
new file mode 100644
index 0000000..526f17b
--- /dev/null
+++ b/libs/common_time/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+#
+# libcommon_time_client
+# (binder marshalers for ICommonClock as well as common clock and local clock
+# helper code)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcommon_time_client
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := cc_helper.cpp \
+ local_clock.cpp \
+ ICommonClock.cpp \
+ ICommonTimeConfig.cpp \
+ utils.cpp
+LOCAL_SHARED_LIBRARIES := libbinder \
+ libhardware \
+ libutils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/common_time/ICommonClock.cpp b/libs/common_time/ICommonClock.cpp
new file mode 100644
index 0000000..28b43ac
--- /dev/null
+++ b/libs/common_time/ICommonClock.cpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <linux/socket.h>
+
+#include <common_time/ICommonClock.h>
+#include <binder/Parcel.h>
+
+#include "utils.h"
+
+namespace android {
+
+/***** ICommonClock *****/
+
+enum {
+ IS_COMMON_TIME_VALID = IBinder::FIRST_CALL_TRANSACTION,
+ COMMON_TIME_TO_LOCAL_TIME,
+ LOCAL_TIME_TO_COMMON_TIME,
+ GET_COMMON_TIME,
+ GET_COMMON_FREQ,
+ GET_LOCAL_TIME,
+ GET_LOCAL_FREQ,
+ GET_ESTIMATED_ERROR,
+ GET_TIMELINE_ID,
+ GET_STATE,
+ GET_MASTER_ADDRESS,
+ REGISTER_LISTENER,
+ UNREGISTER_LISTENER,
+};
+
+const String16 ICommonClock::kServiceName("common_time.clock");
+const uint64_t ICommonClock::kInvalidTimelineID = 0;
+const int32_t ICommonClock::kErrorEstimateUnknown = 0x7FFFFFFF;
+
+class BpCommonClock : public BpInterface<ICommonClock>
+{
+ public:
+ BpCommonClock(const sp<IBinder>& impl)
+ : BpInterface<ICommonClock>(impl) {}
+
+ virtual status_t isCommonTimeValid(bool* valid, uint32_t* timelineID) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(IS_COMMON_TIME_VALID,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *valid = reply.readInt32();
+ *timelineID = reply.readInt32();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t commonTimeToLocalTime(int64_t commonTime,
+ int64_t* localTime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ data.writeInt64(commonTime);
+ status_t status = remote()->transact(COMMON_TIME_TO_LOCAL_TIME,
+ data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *localTime = reply.readInt64();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t localTimeToCommonTime(int64_t localTime,
+ int64_t* commonTime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ data.writeInt64(localTime);
+ status_t status = remote()->transact(LOCAL_TIME_TO_COMMON_TIME,
+ data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *commonTime = reply.readInt64();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getCommonTime(int64_t* commonTime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_COMMON_TIME, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *commonTime = reply.readInt64();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getCommonFreq(uint64_t* freq) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_COMMON_FREQ, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *freq = reply.readInt64();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getLocalTime(int64_t* localTime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_LOCAL_TIME, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *localTime = reply.readInt64();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getLocalFreq(uint64_t* freq) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_LOCAL_FREQ, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *freq = reply.readInt64();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getEstimatedError(int32_t* estimate) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_ESTIMATED_ERROR, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *estimate = reply.readInt32();
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getTimelineID(uint64_t* id) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_TIMELINE_ID, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *id = static_cast<uint64_t>(reply.readInt64());
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getState(State* state) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_STATE, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *state = static_cast<State>(reply.readInt32());
+ }
+ }
+ return status;
+ }
+
+ virtual status_t getMasterAddr(struct sockaddr_storage* addr) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_MASTER_ADDRESS, data, &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK)
+ deserializeSockaddr(&reply, addr);
+ }
+ return status;
+ }
+
+ virtual status_t registerListener(
+ const sp<ICommonClockListener>& listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ data.writeStrongBinder(listener->asBinder());
+
+ status_t status = remote()->transact(REGISTER_LISTENER, data, &reply);
+
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t unregisterListener(
+ const sp<ICommonClockListener>& listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+ data.writeStrongBinder(listener->asBinder());
+ status_t status = remote()->transact(UNREGISTER_LISTENER, data, &reply);
+
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CommonClock, "android.os.ICommonClock");
+
+status_t BnCommonClock::onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags) {
+ switch(code) {
+ case IS_COMMON_TIME_VALID: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ bool valid;
+ uint32_t timelineID;
+ status_t status = isCommonTimeValid(&valid, &timelineID);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(valid);
+ reply->writeInt32(timelineID);
+ }
+ return OK;
+ } break;
+
+ case COMMON_TIME_TO_LOCAL_TIME: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ int64_t commonTime = data.readInt64();
+ int64_t localTime;
+ status_t status = commonTimeToLocalTime(commonTime, &localTime);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(localTime);
+ }
+ return OK;
+ } break;
+
+ case LOCAL_TIME_TO_COMMON_TIME: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ int64_t localTime = data.readInt64();
+ int64_t commonTime;
+ status_t status = localTimeToCommonTime(localTime, &commonTime);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(commonTime);
+ }
+ return OK;
+ } break;
+
+ case GET_COMMON_TIME: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ int64_t commonTime;
+ status_t status = getCommonTime(&commonTime);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(commonTime);
+ }
+ return OK;
+ } break;
+
+ case GET_COMMON_FREQ: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ uint64_t freq;
+ status_t status = getCommonFreq(&freq);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(freq);
+ }
+ return OK;
+ } break;
+
+ case GET_LOCAL_TIME: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ int64_t localTime;
+ status_t status = getLocalTime(&localTime);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(localTime);
+ }
+ return OK;
+ } break;
+
+ case GET_LOCAL_FREQ: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ uint64_t freq;
+ status_t status = getLocalFreq(&freq);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(freq);
+ }
+ return OK;
+ } break;
+
+ case GET_ESTIMATED_ERROR: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ int32_t error;
+ status_t status = getEstimatedError(&error);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(error);
+ }
+ return OK;
+ } break;
+
+ case GET_TIMELINE_ID: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ uint64_t id;
+ status_t status = getTimelineID(&id);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(static_cast<int64_t>(id));
+ }
+ return OK;
+ } break;
+
+ case GET_STATE: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ State state;
+ status_t status = getState(&state);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(static_cast<int32_t>(state));
+ }
+ return OK;
+ } break;
+
+ case GET_MASTER_ADDRESS: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ struct sockaddr_storage addr;
+ status_t status = getMasterAddr(&addr);
+
+ if ((status == OK) && !canSerializeSockaddr(&addr)) {
+ status = UNKNOWN_ERROR;
+ }
+
+ reply->writeInt32(status);
+
+ if (status == OK) {
+ serializeSockaddr(reply, &addr);
+ }
+
+ return OK;
+ } break;
+
+ case REGISTER_LISTENER: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ sp<ICommonClockListener> listener =
+ interface_cast<ICommonClockListener>(data.readStrongBinder());
+ status_t status = registerListener(listener);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case UNREGISTER_LISTENER: {
+ CHECK_INTERFACE(ICommonClock, data, reply);
+ sp<ICommonClockListener> listener =
+ interface_cast<ICommonClockListener>(data.readStrongBinder());
+ status_t status = unregisterListener(listener);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+}
+
+/***** ICommonClockListener *****/
+
+enum {
+ ON_TIMELINE_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpCommonClockListener : public BpInterface<ICommonClockListener>
+{
+ public:
+ BpCommonClockListener(const sp<IBinder>& impl)
+ : BpInterface<ICommonClockListener>(impl) {}
+
+ virtual void onTimelineChanged(uint64_t timelineID) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ ICommonClockListener::getInterfaceDescriptor());
+ data.writeInt64(timelineID);
+ remote()->transact(ON_TIMELINE_CHANGED, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CommonClockListener,
+ "android.os.ICommonClockListener");
+
+status_t BnCommonClockListener::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ switch(code) {
+ case ON_TIMELINE_CHANGED: {
+ CHECK_INTERFACE(ICommonClockListener, data, reply);
+ uint32_t timelineID = data.readInt64();
+ onTimelineChanged(timelineID);
+ return NO_ERROR;
+ } break;
+ }
+
+ return BBinder::onTransact(code, data, reply, flags);
+}
+
+}; // namespace android
diff --git a/libs/common_time/ICommonTimeConfig.cpp b/libs/common_time/ICommonTimeConfig.cpp
new file mode 100644
index 0000000..8eb37cb
--- /dev/null
+++ b/libs/common_time/ICommonTimeConfig.cpp
@@ -0,0 +1,508 @@
+/*
+ * 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.
+ */
+#include <linux/socket.h>
+
+#include <common_time/ICommonTimeConfig.h>
+#include <binder/Parcel.h>
+
+#include "utils.h"
+
+namespace android {
+
+/***** ICommonTimeConfig *****/
+
+enum {
+ GET_MASTER_ELECTION_PRIORITY = IBinder::FIRST_CALL_TRANSACTION,
+ SET_MASTER_ELECTION_PRIORITY,
+ GET_MASTER_ELECTION_ENDPOINT,
+ SET_MASTER_ELECTION_ENDPOINT,
+ GET_MASTER_ELECTION_GROUP_ID,
+ SET_MASTER_ELECTION_GROUP_ID,
+ GET_INTERFACE_BINDING,
+ SET_INTERFACE_BINDING,
+ GET_MASTER_ANNOUNCE_INTERVAL,
+ SET_MASTER_ANNOUNCE_INTERVAL,
+ GET_CLIENT_SYNC_INTERVAL,
+ SET_CLIENT_SYNC_INTERVAL,
+ GET_PANIC_THRESHOLD,
+ SET_PANIC_THRESHOLD,
+ GET_AUTO_DISABLE,
+ SET_AUTO_DISABLE,
+ FORCE_NETWORKLESS_MASTER_MODE,
+};
+
+const String16 ICommonTimeConfig::kServiceName("common_time.config");
+
+class BpCommonTimeConfig : public BpInterface<ICommonTimeConfig>
+{
+ public:
+ BpCommonTimeConfig(const sp<IBinder>& impl)
+ : BpInterface<ICommonTimeConfig>(impl) {}
+
+ virtual status_t getMasterElectionPriority(uint8_t *priority) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_MASTER_ELECTION_PRIORITY,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *priority = static_cast<uint8_t>(reply.readInt32());
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setMasterElectionPriority(uint8_t priority) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(priority));
+ status_t status = remote()->transact(SET_MASTER_ELECTION_PRIORITY,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_MASTER_ELECTION_ENDPOINT,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ deserializeSockaddr(&reply, addr);
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setMasterElectionEndpoint(
+ const struct sockaddr_storage *addr) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ if (!canSerializeSockaddr(addr))
+ return BAD_VALUE;
+ if (NULL == addr) {
+ data.writeInt32(0);
+ } else {
+ data.writeInt32(1);
+ serializeSockaddr(&data, addr);
+ }
+ status_t status = remote()->transact(SET_MASTER_ELECTION_ENDPOINT,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getMasterElectionGroupId(uint64_t *id) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_MASTER_ELECTION_GROUP_ID,
+ data,
+ &reply);
+
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *id = static_cast<uint64_t>(reply.readInt64());
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setMasterElectionGroupId(uint64_t id) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeInt64(id);
+ status_t status = remote()->transact(SET_MASTER_ELECTION_GROUP_ID,
+ data,
+ &reply);
+
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getInterfaceBinding(String16& ifaceName) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_INTERFACE_BINDING,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ ifaceName = reply.readString16();
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setInterfaceBinding(const String16& ifaceName) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeString16(ifaceName);
+ status_t status = remote()->transact(SET_INTERFACE_BINDING,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getMasterAnnounceInterval(int *interval) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_MASTER_ANNOUNCE_INTERVAL,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *interval = reply.readInt32();
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setMasterAnnounceInterval(int interval) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeInt32(interval);
+ status_t status = remote()->transact(SET_MASTER_ANNOUNCE_INTERVAL,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getClientSyncInterval(int *interval) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_CLIENT_SYNC_INTERVAL,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *interval = reply.readInt32();
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setClientSyncInterval(int interval) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeInt32(interval);
+ status_t status = remote()->transact(SET_CLIENT_SYNC_INTERVAL,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getPanicThreshold(int *threshold) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_PANIC_THRESHOLD,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *threshold = reply.readInt32();
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setPanicThreshold(int threshold) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeInt32(threshold);
+ status_t status = remote()->transact(SET_PANIC_THRESHOLD,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t getAutoDisable(bool *autoDisable) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_AUTO_DISABLE,
+ data,
+ &reply);
+ if (status == OK) {
+ status = reply.readInt32();
+ if (status == OK) {
+ *autoDisable = (0 != reply.readInt32());
+ }
+ }
+
+ return status;
+ }
+
+ virtual status_t setAutoDisable(bool autoDisable) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ data.writeInt32(autoDisable ? 1 : 0);
+ status_t status = remote()->transact(SET_AUTO_DISABLE,
+ data,
+ &reply);
+
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+
+ virtual status_t forceNetworklessMasterMode() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+ status_t status = remote()->transact(FORCE_NETWORKLESS_MASTER_MODE,
+ data,
+ &reply);
+
+ if (status == OK) {
+ status = reply.readInt32();
+ }
+
+ return status;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CommonTimeConfig, "android.os.ICommonTimeConfig");
+
+status_t BnCommonTimeConfig::onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags) {
+ switch(code) {
+ case GET_MASTER_ELECTION_PRIORITY: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ uint8_t priority;
+ status_t status = getMasterElectionPriority(&priority);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(static_cast<int32_t>(priority));
+ }
+ return OK;
+ } break;
+
+ case SET_MASTER_ELECTION_PRIORITY: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ uint8_t priority = static_cast<uint8_t>(data.readInt32());
+ status_t status = setMasterElectionPriority(priority);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_MASTER_ELECTION_ENDPOINT: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ struct sockaddr_storage addr;
+ status_t status = getMasterElectionEndpoint(&addr);
+
+ if ((status == OK) && !canSerializeSockaddr(&addr)) {
+ status = UNKNOWN_ERROR;
+ }
+
+ reply->writeInt32(status);
+
+ if (status == OK) {
+ serializeSockaddr(reply, &addr);
+ }
+
+ return OK;
+ } break;
+
+ case SET_MASTER_ELECTION_ENDPOINT: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ struct sockaddr_storage addr;
+ int hasAddr = data.readInt32();
+
+ status_t status;
+ if (hasAddr) {
+ deserializeSockaddr(&data, &addr);
+ status = setMasterElectionEndpoint(&addr);
+ } else {
+ status = setMasterElectionEndpoint(&addr);
+ }
+
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_MASTER_ELECTION_GROUP_ID: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ uint64_t id;
+ status_t status = getMasterElectionGroupId(&id);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt64(id);
+ }
+ return OK;
+ } break;
+
+ case SET_MASTER_ELECTION_GROUP_ID: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ uint64_t id = static_cast<uint64_t>(data.readInt64());
+ status_t status = setMasterElectionGroupId(id);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_INTERFACE_BINDING: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ String16 ret;
+ status_t status = getInterfaceBinding(ret);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeString16(ret);
+ }
+ return OK;
+ } break;
+
+ case SET_INTERFACE_BINDING: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ String16 ifaceName;
+ ifaceName = data.readString16();
+ status_t status = setInterfaceBinding(ifaceName);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_MASTER_ANNOUNCE_INTERVAL: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ int interval;
+ status_t status = getMasterAnnounceInterval(&interval);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(interval);
+ }
+ return OK;
+ } break;
+
+ case SET_MASTER_ANNOUNCE_INTERVAL: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ int interval = data.readInt32();
+ status_t status = setMasterAnnounceInterval(interval);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_CLIENT_SYNC_INTERVAL: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ int interval;
+ status_t status = getClientSyncInterval(&interval);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(interval);
+ }
+ return OK;
+ } break;
+
+ case SET_CLIENT_SYNC_INTERVAL: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ int interval = data.readInt32();
+ status_t status = setClientSyncInterval(interval);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_PANIC_THRESHOLD: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ int threshold;
+ status_t status = getPanicThreshold(&threshold);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(threshold);
+ }
+ return OK;
+ } break;
+
+ case SET_PANIC_THRESHOLD: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ int threshold = data.readInt32();
+ status_t status = setPanicThreshold(threshold);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case GET_AUTO_DISABLE: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ bool autoDisable;
+ status_t status = getAutoDisable(&autoDisable);
+ reply->writeInt32(status);
+ if (status == OK) {
+ reply->writeInt32(autoDisable ? 1 : 0);
+ }
+ return OK;
+ } break;
+
+ case SET_AUTO_DISABLE: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ bool autoDisable = (0 != data.readInt32());
+ status_t status = setAutoDisable(autoDisable);
+ reply->writeInt32(status);
+ return OK;
+ } break;
+
+ case FORCE_NETWORKLESS_MASTER_MODE: {
+ CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+ status_t status = forceNetworklessMasterMode();
+ reply->writeInt32(status);
+ return OK;
+ } break;
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+}
+
+}; // namespace android
+
diff --git a/libs/common_time/cc_helper.cpp b/libs/common_time/cc_helper.cpp
new file mode 100644
index 0000000..8d8556c
--- /dev/null
+++ b/libs/common_time/cc_helper.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+
+#include <common_time/cc_helper.h>
+#include <common_time/ICommonClock.h>
+#include <utils/threads.h>
+
+namespace android {
+
+Mutex CCHelper::lock_;
+sp<ICommonClock> CCHelper::common_clock_;
+sp<ICommonClockListener> CCHelper::common_clock_listener_;
+uint32_t CCHelper::ref_count_ = 0;
+
+bool CCHelper::verifyClock_l() {
+ bool ret = false;
+
+ if (common_clock_ == NULL) {
+ common_clock_ = ICommonClock::getInstance();
+ if (common_clock_ == NULL)
+ goto bailout;
+ }
+
+ if (ref_count_ > 0) {
+ if (common_clock_listener_ == NULL) {
+ common_clock_listener_ = new CommonClockListener();
+ if (common_clock_listener_ == NULL)
+ goto bailout;
+
+ if (OK != common_clock_->registerListener(common_clock_listener_))
+ goto bailout;
+ }
+ }
+
+ ret = true;
+
+bailout:
+ if (!ret) {
+ common_clock_listener_ = NULL;
+ common_clock_ = NULL;
+ }
+ return ret;
+}
+
+CCHelper::CCHelper() {
+ Mutex::Autolock lock(&lock_);
+ ref_count_++;
+ verifyClock_l();
+}
+
+CCHelper::~CCHelper() {
+ Mutex::Autolock lock(&lock_);
+
+ assert(ref_count_ > 0);
+ ref_count_--;
+
+ // If we were the last CCHelper instance in the system, and we had
+ // previously register a listener, unregister it now so that the common time
+ // service has the chance to go into auto-disabled mode.
+ if (!ref_count_ &&
+ (common_clock_ != NULL) &&
+ (common_clock_listener_ != NULL)) {
+ common_clock_->unregisterListener(common_clock_listener_);
+ common_clock_listener_ = NULL;
+ }
+}
+
+void CCHelper::CommonClockListener::onTimelineChanged(uint64_t timelineID) {
+ // do nothing; listener is only really used as a token so the server can
+ // find out when clients die.
+}
+
+// Helper methods which attempts to make calls to the common time binder
+// service. If the first attempt fails with DEAD_OBJECT, the helpers will
+// attempt to make a connection to the service again (assuming that the process
+// hosting the service had crashed and the client proxy we are holding is dead)
+// If the second attempt fails, or no connection can be made, the we let the
+// error propagate up the stack and let the caller deal with the situation as
+// best they can.
+#define CCHELPER_METHOD(decl, call) \
+ status_t CCHelper::decl { \
+ Mutex::Autolock lock(&lock_); \
+ \
+ if (!verifyClock_l()) \
+ return DEAD_OBJECT; \
+ \
+ status_t status = common_clock_->call; \
+ if (DEAD_OBJECT == status) { \
+ if (!verifyClock_l()) \
+ return DEAD_OBJECT; \
+ status = common_clock_->call; \
+ } \
+ \
+ return status; \
+ }
+
+#define VERIFY_CLOCK()
+
+CCHELPER_METHOD(isCommonTimeValid(bool* valid, uint32_t* timelineID),
+ isCommonTimeValid(valid, timelineID))
+CCHELPER_METHOD(commonTimeToLocalTime(int64_t commonTime, int64_t* localTime),
+ commonTimeToLocalTime(commonTime, localTime))
+CCHELPER_METHOD(localTimeToCommonTime(int64_t localTime, int64_t* commonTime),
+ localTimeToCommonTime(localTime, commonTime))
+CCHELPER_METHOD(getCommonTime(int64_t* commonTime),
+ getCommonTime(commonTime))
+CCHELPER_METHOD(getCommonFreq(uint64_t* freq),
+ getCommonFreq(freq))
+CCHELPER_METHOD(getLocalTime(int64_t* localTime),
+ getLocalTime(localTime))
+CCHELPER_METHOD(getLocalFreq(uint64_t* freq),
+ getLocalFreq(freq))
+
+} // namespace android
diff --git a/libs/common_time/local_clock.cpp b/libs/common_time/local_clock.cpp
new file mode 100644
index 0000000..a7c61fc
--- /dev/null
+++ b/libs/common_time/local_clock.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common_time/local_clock.h>
+#include <hardware/hardware.h>
+#include <hardware/local_time_hal.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+Mutex LocalClock::dev_lock_;
+local_time_hw_device_t* LocalClock::dev_ = NULL;
+
+LocalClock::LocalClock() {
+ int res;
+ const hw_module_t* mod;
+
+ AutoMutex lock(&dev_lock_);
+
+ if (dev_ != NULL)
+ return;
+
+ res = hw_get_module_by_class(LOCAL_TIME_HARDWARE_MODULE_ID, NULL, &mod);
+ if (res) {
+ ALOGE("Failed to open local time HAL module (res = %d)", res);
+ } else {
+ res = local_time_hw_device_open(mod, &dev_);
+ if (res) {
+ ALOGE("Failed to open local time HAL device (res = %d)", res);
+ dev_ = NULL;
+ }
+ }
+}
+
+bool LocalClock::initCheck() {
+ return (NULL != dev_);
+}
+
+int64_t LocalClock::getLocalTime() {
+ assert(NULL != dev_);
+ assert(NULL != dev_->get_local_time);
+
+ return dev_->get_local_time(dev_);
+}
+
+uint64_t LocalClock::getLocalFreq() {
+ assert(NULL != dev_);
+ assert(NULL != dev_->get_local_freq);
+
+ return dev_->get_local_freq(dev_);
+}
+
+status_t LocalClock::setLocalSlew(int16_t rate) {
+ assert(NULL != dev_);
+
+ if (!dev_->set_local_slew)
+ return INVALID_OPERATION;
+
+ return static_cast<status_t>(dev_->set_local_slew(dev_, rate));
+}
+
+int32_t LocalClock::getDebugLog(struct local_time_debug_event* records,
+ int max_records) {
+ assert(NULL != dev_);
+
+ if (!dev_->get_debug_log)
+ return INVALID_OPERATION;
+
+ return dev_->get_debug_log(dev_, records, max_records);
+}
+
+} // namespace android
diff --git a/libs/common_time/utils.cpp b/libs/common_time/utils.cpp
new file mode 100644
index 0000000..6539171
--- /dev/null
+++ b/libs/common_time/utils.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <linux/socket.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+bool canSerializeSockaddr(const struct sockaddr_storage* addr) {
+ switch (addr->ss_family) {
+ case AF_INET:
+ case AF_INET6:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr) {
+ switch (addr->ss_family) {
+ case AF_INET: {
+ const struct sockaddr_in* s =
+ reinterpret_cast<const struct sockaddr_in*>(addr);
+ p->writeInt32(AF_INET);
+ p->writeInt32(ntohl(s->sin_addr.s_addr));
+ p->writeInt32(static_cast<int32_t>(ntohs(s->sin_port)));
+ } break;
+
+ case AF_INET6: {
+ const struct sockaddr_in6* s =
+ reinterpret_cast<const struct sockaddr_in6*>(addr);
+ const int32_t* a =
+ reinterpret_cast<const int32_t*>(s->sin6_addr.s6_addr);
+ p->writeInt32(AF_INET6);
+ p->writeInt32(ntohl(a[0]));
+ p->writeInt32(ntohl(a[1]));
+ p->writeInt32(ntohl(a[2]));
+ p->writeInt32(ntohl(a[3]));
+ p->writeInt32(static_cast<int32_t>(ntohs(s->sin6_port)));
+ p->writeInt32(ntohl(s->sin6_flowinfo));
+ p->writeInt32(ntohl(s->sin6_scope_id));
+ } break;
+ }
+}
+
+void deserializeSockaddr(const Parcel* p, struct sockaddr_storage* addr) {
+ memset(addr, 0, sizeof(addr));
+
+ addr->ss_family = p->readInt32();
+ switch(addr->ss_family) {
+ case AF_INET: {
+ struct sockaddr_in* s =
+ reinterpret_cast<struct sockaddr_in*>(addr);
+ s->sin_addr.s_addr = htonl(p->readInt32());
+ s->sin_port = htons(static_cast<uint16_t>(p->readInt32()));
+ } break;
+
+ case AF_INET6: {
+ struct sockaddr_in6* s =
+ reinterpret_cast<struct sockaddr_in6*>(addr);
+ int32_t* a = reinterpret_cast<int32_t*>(s->sin6_addr.s6_addr);
+
+ a[0] = htonl(p->readInt32());
+ a[1] = htonl(p->readInt32());
+ a[2] = htonl(p->readInt32());
+ a[3] = htonl(p->readInt32());
+ s->sin6_port = htons(static_cast<uint16_t>(p->readInt32()));
+ s->sin6_flowinfo = htonl(p->readInt32());
+ s->sin6_scope_id = htonl(p->readInt32());
+ } break;
+ }
+}
+
+} // namespace android
diff --git a/libs/common_time/utils.h b/libs/common_time/utils.h
new file mode 100644
index 0000000..ce79d0d
--- /dev/null
+++ b/libs/common_time/utils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_LIBCOMMONCLOCK_UTILS_H
+#define ANDROID_LIBCOMMONCLOCK_UTILS_H
+
+#include <linux/socket.h>
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+extern bool canSerializeSockaddr(const struct sockaddr_storage* addr);
+extern void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr);
+extern status_t deserializeSockaddr(const Parcel* p,
+ struct sockaddr_storage* addr);
+
+}; // namespace android
+
+#endif // ANDROID_LIBCOMMONCLOCK_UTILS_H
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index c7e2c0f..0791de2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -166,6 +166,37 @@
return OK;
}
+int BufferQueue::query(int what, int* outValue)
+{
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("query: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
+ int value;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ value = mDefaultWidth;
+ break;
+ case NATIVE_WINDOW_HEIGHT:
+ value = mDefaultHeight;
+ break;
+ case NATIVE_WINDOW_FORMAT:
+ value = mPixelFormat;
+ break;
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ value = mSynchronousMode ?
+ (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ outValue[0] = value;
+ return NO_ERROR;
+}
+
status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGV("requestBuffer: slot=%d", slot);
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index be1bcd1..a7bfc61 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -416,36 +416,7 @@
return mSynchronousMode;
}
-int SurfaceTexture::query(int what, int* outValue)
-{
- Mutex::Autolock lock(mMutex);
- if (mAbandoned) {
- ST_LOGE("query: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
- int value;
- switch (what) {
- case NATIVE_WINDOW_WIDTH:
- value = mDefaultWidth;
- break;
- case NATIVE_WINDOW_HEIGHT:
- value = mDefaultHeight;
- break;
- case NATIVE_WINDOW_FORMAT:
- value = mPixelFormat;
- break;
- case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = mSynchronousMode ?
- (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
- break;
- default:
- return BAD_VALUE;
- }
- outValue[0] = value;
- return NO_ERROR;
-}
void SurfaceTexture::abandon() {
Mutex::Autolock lock(mMutex);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 1a11fbc..f9088ac 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -226,6 +226,11 @@
while (!mReader.eof()) {
int op = mReader.readInt();
+ if (op & OP_MAY_BE_SKIPPED_MASK) {
+ int skip = mReader.readInt();
+ ALOGD("%sSkip %d", (char*) indent, skip);
+ op &= ~OP_MAY_BE_SKIPPED_MASK;
+ }
switch (op) {
case DrawGLFunction: {
@@ -316,8 +321,9 @@
DisplayList* displayList = getDisplayList();
uint32_t width = getUInt();
uint32_t height = getUInt();
- ALOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
- displayList, width, height, level + 1);
+ int32_t flags = getInt();
+ ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
+ displayList, width, height, flags, level + 1);
renderer.outputDisplayList(displayList, level + 1);
}
break;
@@ -551,7 +557,7 @@
* in the output() function, since that function processes the same list of opcodes for the
* purposes of logging display list info for a given view.
*/
-bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
bool needsInvalidate = false;
TextContainer text;
mReader.rewind();
@@ -572,6 +578,18 @@
int saveCount = renderer.getSaveCount() - 1;
while (!mReader.eof()) {
int op = mReader.readInt();
+ if (op & OP_MAY_BE_SKIPPED_MASK) {
+ int32_t skip = mReader.readInt() * 4;
+ if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) {
+ mReader.skip(skip);
+ DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent,
+ OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip);
+ continue;
+ } else {
+ op &= ~OP_MAY_BE_SKIPPED_MASK;
+ ALOGD("%s", OP_NAMES[op]);
+ }
+ }
logBuffer.writeCommand(level, op);
switch (op) {
@@ -584,7 +602,7 @@
}
break;
case Save: {
- int rendererNum = getInt();
+ int32_t rendererNum = getInt();
DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
renderer.save(rendererNum);
}
@@ -595,7 +613,7 @@
}
break;
case RestoreToCount: {
- int restoreCount = saveCount + getInt();
+ int32_t restoreCount = saveCount + getInt();
DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
renderer.restoreToCount(restoreCount);
}
@@ -606,7 +624,7 @@
float f3 = getFloat();
float f4 = getFloat();
SkPaint* paint = getPaint(renderer);
- int flags = getInt();
+ int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, paint, flags);
renderer.saveLayer(f1, f2, f3, f4, paint, flags);
@@ -617,8 +635,8 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- int alpha = getInt();
- int flags = getInt();
+ int32_t alpha = getInt();
+ int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
@@ -668,7 +686,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- int regionOp = getInt();
+ int32_t regionOp = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
f1, f2, f3, f4, regionOp);
renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
@@ -678,10 +696,11 @@
DisplayList* displayList = getDisplayList();
uint32_t width = getUInt();
uint32_t height = getUInt();
- DISPLAY_LIST_LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
- displayList, width, height, level + 1);
+ int32_t flags = getInt();
+ DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
+ displayList, width, height, flags, level + 1);
needsInvalidate |= renderer.drawDisplayList(displayList, width, height,
- dirty, level + 1);
+ dirty, flags, level + 1);
}
break;
case DrawLayer: {
@@ -730,7 +749,7 @@
}
break;
case DrawBitmapMesh: {
- int verticesCount = 0;
+ int32_t verticesCount = 0;
uint32_t colorsCount = 0;
SkBitmap* bitmap = getBitmap();
@@ -738,7 +757,7 @@
uint32_t meshHeight = getInt();
float* vertices = getFloats(verticesCount);
bool hasColors = getInt();
- int* colors = hasColors ? getInts(colorsCount) : NULL;
+ int32_t* colors = hasColors ? getInts(colorsCount) : NULL;
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -771,8 +790,8 @@
}
break;
case DrawColor: {
- int color = getInt();
- int xferMode = getInt();
+ int32_t color = getInt();
+ int32_t xferMode = getInt();
DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
renderer.drawColor(color, (SkXfermode::Mode) xferMode);
}
@@ -829,7 +848,7 @@
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
- int i1 = getInt();
+ int32_t i1 = getInt();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
@@ -844,7 +863,7 @@
}
break;
case DrawLines: {
- int count = 0;
+ int32_t count = 0;
float* points = getFloats(count);
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -852,7 +871,7 @@
}
break;
case DrawPoints: {
- int count = 0;
+ int32_t count = 0;
float* points = getFloats(count);
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -861,7 +880,7 @@
break;
case DrawText: {
getText(&text);
- int count = getInt();
+ int32_t count = getInt();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint(renderer);
@@ -873,8 +892,8 @@
break;
case DrawPosText: {
getText(&text);
- int count = getInt();
- int positionsCount = 0;
+ int32_t count = getInt();
+ int32_t positionsCount = 0;
float* positions = getFloats(positionsCount);
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent,
@@ -913,7 +932,7 @@
float radius = getFloat();
float dx = getFloat();
float dy = getFloat();
- int color = getInt();
+ int32_t color = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
radius, dx, dy, color);
renderer.setupShadow(radius, dx, dy, color);
@@ -925,8 +944,8 @@
}
break;
case SetupPaintFilter: {
- int clearBits = getInt();
- int setBits = getInt();
+ int32_t clearBits = getInt();
+ int32_t setBits = getInt();
DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op],
clearBits, setBits);
renderer.setupPaintFilter(clearBits, setBits);
@@ -949,7 +968,8 @@
// Base structure
///////////////////////////////////////////////////////////////////////////////
-DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE), mHasDrawOps(false) {
+DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE),
+ mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
}
DisplayListRenderer::~DisplayListRenderer() {
@@ -1019,6 +1039,7 @@
void DisplayListRenderer::finish() {
insertRestoreToCount();
+ insertTranlate();
OpenGLRenderer::finish();
}
@@ -1043,15 +1064,18 @@
void DisplayListRenderer::restore() {
if (mRestoreSaveCount < 0) {
- addOp(DisplayList::Restore);
- } else {
- mRestoreSaveCount--;
+ restoreToCount(getSaveCount() - 1);
+ return;
}
+
+ mRestoreSaveCount--;
+ insertTranlate();
OpenGLRenderer::restore();
}
void DisplayListRenderer::restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
+ insertTranlate();
OpenGLRenderer::restoreToCount(saveCount);
}
@@ -1074,8 +1098,10 @@
}
void DisplayListRenderer::translate(float dx, float dy) {
- addOp(DisplayList::Translate);
- addPoint(dx, dy);
+ mHasTranslate = true;
+ mTranslateX += dx;
+ mTranslateY += dy;
+ insertRestoreToCount();
OpenGLRenderer::translate(dx, dy);
}
@@ -1118,12 +1144,15 @@
}
bool DisplayListRenderer::drawDisplayList(DisplayList* displayList,
- uint32_t width, uint32_t height, Rect& dirty, uint32_t level) {
+ uint32_t width, uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
- addOp(DisplayList::DrawDisplayList);
+ const bool reject = quickReject(0.0f, 0.0f, width, height);
+ uint32_t* location = addOp(DisplayList::DrawDisplayList, reject);
addDisplayList(displayList);
addSize(width, height);
+ addInt(flags);
+ addSkip(location);
return false;
}
@@ -1134,30 +1163,38 @@
addPaint(paint);
}
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
- SkPaint* paint) {
- addOp(DisplayList::DrawBitmap);
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+ const bool reject = quickReject(left, top, left + bitmap->width(), top + bitmap->height());
+ uint32_t* location = addOp(DisplayList::DrawBitmap, reject);
addBitmap(bitmap);
addPoint(left, top);
addPaint(paint);
+ addSkip(location);
}
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
- SkPaint* paint) {
- addOp(DisplayList::DrawBitmapMatrix);
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
+ Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
+ const mat4 transform(*matrix);
+ transform.mapRect(r);
+
+ const bool reject = quickReject(r.left, r.top, r.right, r.bottom);
+ uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject);
addBitmap(bitmap);
addMatrix(matrix);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, SkPaint* paint) {
- addOp(DisplayList::DrawBitmapRect);
+ const bool reject = quickReject(dstLeft, dstTop, dstRight, dstBottom);
+ uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject);
addBitmap(bitmap);
addBounds(srcLeft, srcTop, srcRight, srcBottom);
addBounds(dstLeft, dstTop, dstRight, dstBottom);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
@@ -1179,13 +1216,15 @@
void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
float left, float top, float right, float bottom, SkPaint* paint) {
- addOp(DisplayList::DrawPatch);
+ const bool reject = quickReject(left, top, right, bottom);
+ uint32_t* location = addOp(DisplayList::DrawPatch, reject);
addBitmap(bitmap);
addInts(xDivs, width);
addInts(yDivs, height);
addUInts(colors, numColors);
addBounds(left, top, right, bottom);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -1196,17 +1235,23 @@
void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
SkPaint* paint) {
- addOp(DisplayList::DrawRect);
+ const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
+ quickReject(left, top, right, bottom);
+ uint32_t* location = addOp(DisplayList::DrawRect, reject);
addBounds(left, top, right, bottom);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, SkPaint* paint) {
- addOp(DisplayList::DrawRoundRect);
+ const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
+ quickReject(left, top, right, bottom);
+ uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
addBounds(left, top, right, bottom);
addPoint(rx, ry);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
@@ -1233,9 +1278,15 @@
}
void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
- addOp(DisplayList::DrawPath);
+ float left, top, offset;
+ uint32_t width, height;
+ computePathBounds(path, paint, left, top, offset, width, height);
+
+ const bool reject = quickReject(left - offset, top - offset, width, height);
+ uint32_t* location = addOp(DisplayList::DrawPath, reject);
addPath(path);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
@@ -1252,11 +1303,8 @@
void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
float x, float y, SkPaint* paint, float length) {
- if (count <= 0) return;
- addOp(DisplayList::DrawText);
- addText(text, bytesCount);
- addInt(count);
- addPoint(x, y);
+ if (!text || count <= 0) return;
+
// TODO: We should probably make a copy of the paint instead of modifying
// it; modifying the paint will change its generationID the first
// time, which might impact caches. More investigation needed to
@@ -1265,13 +1313,27 @@
// its own copy as it does right now.
// Beware: this needs Glyph encoding (already done on the Paint constructor)
paint->setAntiAlias(true);
+ if (length < 0.0f) length = paint->measureText(text, bytesCount);
+
+ bool reject = false;
+ if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
+ SkPaint::FontMetrics metrics;
+ paint->getFontMetrics(&metrics, 0.0f);
+ reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom);
+ }
+
+ uint32_t* location = addOp(DisplayList::DrawText, reject);
+ addText(text, bytesCount);
+ addInt(count);
+ addPoint(x, y);
addPaint(paint);
- addFloat(length < 0.0f ? paint->measureText(text, bytesCount) : length);
+ addFloat(length);
+ addSkip(location);
}
void DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
const float* positions, SkPaint* paint) {
- if (count <= 0) return;
+ if (!text || count <= 0) return;
addOp(DisplayList::DrawPosText);
addText(text, bytesCount);
addInt(count);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 46506e4..6dd47be 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -42,6 +42,7 @@
///////////////////////////////////////////////////////////////////////////////
#define MIN_WRITER_SIZE 4096
+#define OP_MAY_BE_SKIPPED_MASK 0xff000000
// Debug
#if DEBUG_DISPLAY_LIST
@@ -110,13 +111,18 @@
DrawGLFunction,
};
+ // See flags defined in DisplayList.java
+ enum ReplayFlag {
+ kReplayFlag_ClipChildren = 0x1
+ };
+
static const char* OP_NAMES[];
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
ANDROID_API size_t getSize();
- bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
+ bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
void output(OpenGLRenderer& renderer, uint32_t level = 0);
@@ -167,11 +173,11 @@
return (SkiaColorFilter*) getInt();
}
- inline int getIndex() {
+ inline int32_t getIndex() {
return mReader.readInt();
}
- inline int getInt() {
+ inline int32_t getInt() {
return mReader.readInt();
}
@@ -209,7 +215,7 @@
return (uint32_t*) mReader.skip(count * sizeof(uint32_t));
}
- float* getFloats(int& count) {
+ float* getFloats(int32_t& count) {
count = getInt();
return (float*) mReader.skip(count * sizeof(float));
}
@@ -279,7 +285,7 @@
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
- Rect& dirty, uint32_t level = 0);
+ Rect& dirty, int32_t flags, uint32_t level = 0);
virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -358,13 +364,45 @@
}
}
- inline void addOp(DisplayList::Op drawOp) {
+ void insertTranlate() {
+ if (mHasTranslate) {
+ if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
+ mWriter.writeInt(DisplayList::Translate);
+ addPoint(mTranslateX, mTranslateY);
+ mTranslateX = mTranslateY = 0.0f;
+ }
+ mHasTranslate = false;
+ }
+ }
+
+ inline void addOp(const DisplayList::Op drawOp) {
insertRestoreToCount();
+ insertTranlate();
mWriter.writeInt(drawOp);
mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
}
- inline void addInt(int value) {
+ uint32_t* addOp(const DisplayList::Op drawOp, const bool reject) {
+ insertRestoreToCount();
+ insertTranlate();
+ mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
+ if (reject) {
+ mWriter.writeInt(OP_MAY_BE_SKIPPED_MASK | drawOp);
+ mWriter.writeInt(0);
+ uint32_t* location = reject ? mWriter.peek32(mWriter.size() - 4) : NULL;
+ return location;
+ }
+ mWriter.writeInt(drawOp);
+ return NULL;
+ }
+
+ inline void addSkip(uint32_t* location) {
+ if (location) {
+ *location = (int32_t) (mWriter.peek32(mWriter.size() - 4) - location);
+ }
+ }
+
+ inline void addInt(int32_t value) {
mWriter.writeInt(value);
}
@@ -391,9 +429,9 @@
mWriter.writeScalar(value);
}
- void addFloats(const float* values, int count) {
+ void addFloats(const float* values, int32_t count) {
mWriter.writeInt(count);
- for (int i = 0; i < count; i++) {
+ for (int32_t i = 0; i < count; i++) {
mWriter.writeScalar(values[i]);
}
}
@@ -513,6 +551,11 @@
SkWriter32 mWriter;
int mRestoreSaveCount;
+
+ float mTranslateX;
+ float mTranslateY;
+ bool mHasTranslate;
+
bool mHasDrawOps;
friend class DisplayList;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index afae70f..55e2ca5 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1321,7 +1321,7 @@
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
- Rect& dirty, uint32_t level) {
+ Rect& dirty, int32_t flags, uint32_t level) {
if (quickReject(0.0f, 0.0f, width, height)) {
return false;
}
@@ -1329,7 +1329,7 @@
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
- return displayList->replay(*this, dirty, level);
+ return displayList->replay(*this, dirty, flags, level);
}
return false;
@@ -2189,8 +2189,7 @@
SkPaint::FontMetrics metrics;
paint->getFontMetrics(&metrics, 0.0f);
// If no length was specified, just perform the hit test on the Y axis
- if (quickReject(x, y + metrics.fTop,
- x + (length >= 0.0f ? length : INT_MAX / 2), y + metrics.fBottom)) {
+ if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
return;
}
@@ -2298,6 +2297,7 @@
mCaches.activeTexture(0);
+ // TODO: Perform early clip test before we rasterize the path
const PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
const AutoTexture autoCleanup(texture);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3c2d09e..3f63c3fe 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,7 +98,7 @@
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
- Rect& dirty, uint32_t level = 0);
+ Rect& dirty, int32_t flags, uint32_t level = 0);
virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index e893f7a9..e09c243 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -24,6 +24,23 @@
namespace android {
namespace uirenderer {
+// Defined in ShapeCache.h
+void computePathBounds(const SkPath *path, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
+ const SkRect& bounds = path->getBounds();
+
+ const float pathWidth = fmax(bounds.width(), 1.0f);
+ const float pathHeight = fmax(bounds.height(), 1.0f);
+
+ left = bounds.fLeft;
+ top = bounds.fTop;
+
+ offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
+
+ width = uint32_t(pathWidth + offset * 2.0 + 0.5);
+ height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Path cache
///////////////////////////////////////////////////////////////////////////////
@@ -69,6 +86,9 @@
PathCacheEntry entry(path, paint);
PathTexture* texture = mCache.get(entry);
+ float left, top, offset;
+ uint32_t width, height;
+
if (!texture) {
texture = addTexture(entry, path, paint);
} else if (path->getGenerationID() != texture->generation) {
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 30ce690..f180e94 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -489,18 +489,16 @@
}
}
+void computePathBounds(const SkPath *path, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+
template<class Entry>
PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
const SkPaint* paint) {
- const SkRect& bounds = path->getBounds();
- const float pathWidth = fmax(bounds.width(), 1.0f);
- const float pathHeight = fmax(bounds.height(), 1.0f);
-
- const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
-
- const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
- const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+ float left, top, offset;
+ uint32_t width, height;
+ computePathBounds(path, paint, left, top, offset, width, height);
if (width > mMaxTextureSize || height > mMaxTextureSize) {
ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
@@ -517,8 +515,8 @@
}
PathTexture* texture = new PathTexture;
- texture->left = bounds.fLeft;
- texture->top = bounds.fTop;
+ texture->left = left;
+ texture->top = top;
texture->offset = offset;
texture->width = width;
texture->height = height;
@@ -542,7 +540,7 @@
SkSafeUnref(pathPaint.setXfermode(mode));
SkCanvas canvas(bitmap);
- canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset);
+ canvas.translate(-left + offset, -top + offset);
canvas.drawPath(*path, pathPaint);
generateTexture(bitmap, texture);
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 2166ce7..9c5d06b 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -95,6 +95,7 @@
rsMatrix4x4.cpp \
rsMesh.cpp \
rsMutex.cpp \
+ rsPath.cpp \
rsProgram.cpp \
rsProgramFragment.cpp \
rsProgramStore.cpp \
@@ -117,6 +118,7 @@
driver/rsdGL.cpp \
driver/rsdMesh.cpp \
driver/rsdMeshObj.cpp \
+ driver/rsdPath.cpp \
driver/rsdProgram.cpp \
driver/rsdProgramRaster.cpp \
driver/rsdProgramStore.cpp \
@@ -201,6 +203,7 @@
rsMatrix4x4.cpp \
rsMesh.cpp \
rsMutex.cpp \
+ rsPath.cpp \
rsProgram.cpp \
rsProgramFragment.cpp \
rsProgramStore.cpp \
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 1f70e66..fb93d82 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -23,6 +23,11 @@
#include "rsAllocation.h"
+#include "system/window.h"
+#include "hardware/gralloc.h"
+#include "ui/Rect.h"
+#include "ui/GraphicBufferMapper.h"
+
#include <GLES/gl.h>
#include <GLES2/gl2.h>
#include <GLES/glext.h>
@@ -134,6 +139,13 @@
static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+ if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) {
+ if (!drv->textureID) {
+ RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
+ }
+ return;
+ }
+
if (!drv->glType || !drv->glFormat) {
return;
}
@@ -212,10 +224,14 @@
return false;
}
- void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
- if (!ptr) {
- free(drv);
- return false;
+ void * ptr = alloc->mHal.state.usrPtr;
+ if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) {
+ } else {
+ ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+ if (!ptr) {
+ free(drv);
+ return false;
+ }
}
drv->glTarget = GL_NONE;
@@ -238,7 +254,7 @@
alloc->mHal.drvState.mallocPtr = ptr;
drv->mallocPtr = (uint8_t *)ptr;
alloc->mHal.drv = drv;
- if (forceZero) {
+ if (forceZero && ptr) {
memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
}
@@ -269,7 +285,7 @@
drv->renderTargetID = 0;
}
- if (drv->mallocPtr) {
+ if (drv->mallocPtr && !alloc->mHal.state.usrPtr) {
free(drv->mallocPtr);
drv->mallocPtr = NULL;
}
@@ -370,9 +386,102 @@
drv->uploadDeferred = true;
}
+int32_t rsdAllocationInitSurfaceTexture(const Context *rsc, const Allocation *alloc) {
+ DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+ UploadToTexture(rsc, alloc);
+ return drv->textureID;
+}
+
+static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
+ DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+
+ int32_t r = nw->dequeueBuffer(nw, &drv->wndBuffer);
+ if (r) {
+ rsc->setError(RS_ERROR_DRIVER, "Error getting next IO output buffer.");
+ return false;
+ }
+
+ // This lock is implicitly released by the queue buffer in IoSend
+ r = nw->lockBuffer(nw, drv->wndBuffer);
+ if (r) {
+ rsc->setError(RS_ERROR_DRIVER, "Error locking next IO output buffer.");
+ return false;
+ }
+
+ // Must lock the whole surface
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ Rect bounds(drv->wndBuffer->width, drv->wndBuffer->height);
+
+ void *dst = NULL;
+ mapper.lock(drv->wndBuffer->handle,
+ GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ bounds, &dst);
+ alloc->mHal.drvState.mallocPtr = dst;
+ return true;
+}
+
+void rsdAllocationSetSurfaceTexture(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
+ DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+
+ //ALOGE("rsdAllocationSetSurfaceTexture %p %p", alloc, nw);
+
+ // Cleanup old surface if there is one.
+ if (alloc->mHal.state.wndSurface) {
+ ANativeWindow *old = alloc->mHal.state.wndSurface;
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.unlock(drv->wndBuffer->handle);
+ old->queueBuffer(old, drv->wndBuffer);
+ }
+
+ if (nw != NULL) {
+ int32_t r;
+ r = native_window_set_usage(nw, GRALLOC_USAGE_SW_READ_RARELY |
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+ if (r) {
+ rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer usage.");
+ return;
+ }
+
+ r = native_window_set_buffers_dimensions(nw, alloc->mHal.state.dimensionX,
+ alloc->mHal.state.dimensionY);
+ if (r) {
+ rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer dimensions.");
+ return;
+ }
+
+ r = native_window_set_buffer_count(nw, 3);
+ if (r) {
+ rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer count.");
+ return;
+ }
+
+ IoGetBuffer(rsc, alloc, nw);
+ }
+}
+
+void rsdAllocationIoSend(const Context *rsc, Allocation *alloc) {
+ DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+ ANativeWindow *nw = alloc->mHal.state.wndSurface;
+
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.unlock(drv->wndBuffer->handle);
+ int32_t r = nw->queueBuffer(nw, drv->wndBuffer);
+ if (r) {
+ rsc->setError(RS_ERROR_DRIVER, "Error sending IO output buffer.");
+ return;
+ }
+
+ IoGetBuffer(rsc, alloc, nw);
+}
+
+void rsdAllocationIoReceive(const Context *rsc, Allocation *alloc) {
+ ALOGE("not implemented");
+}
+
+
void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t lod, uint32_t count,
- const void *data, uint32_t sizeBytes) {
+ const void *data, size_t sizeBytes) {
DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes();
@@ -391,7 +500,7 @@
void rsdAllocationData2D(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
+ uint32_t w, uint32_t h, const void *data, size_t sizeBytes) {
DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
uint32_t eSize = alloc->mHal.state.elementSizeBytes;
diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h
index 4fc4419..e3a5126 100644
--- a/libs/rs/driver/rsdAllocation.h
+++ b/libs/rs/driver/rsdAllocation.h
@@ -24,6 +24,7 @@
#include <GLES2/gl2.h>
class RsdFrameBufferObj;
+struct ANativeWindowBuffer;
struct DrvAllocation {
// Is this a legal structure to be used as a texture source.
@@ -47,6 +48,7 @@
bool uploadDeferred;
RsdFrameBufferObj * readBackFBO;
+ ANativeWindowBuffer *wndBuffer;
};
GLenum rsdTypeToGLType(RsDataType t);
@@ -67,6 +69,14 @@
RsAllocationUsageType src);
void rsdAllocationMarkDirty(const android::renderscript::Context *rsc,
const android::renderscript::Allocation *alloc);
+int32_t rsdAllocationInitSurfaceTexture(const android::renderscript::Context *rsc,
+ const android::renderscript::Allocation *alloc);
+void rsdAllocationSetSurfaceTexture(const android::renderscript::Context *rsc,
+ android::renderscript::Allocation *alloc, ANativeWindow *nw);
+void rsdAllocationIoSend(const android::renderscript::Context *rsc,
+ android::renderscript::Allocation *alloc);
+void rsdAllocationIoReceive(const android::renderscript::Context *rsc,
+ android::renderscript::Allocation *alloc);
void rsdAllocationData1D(const android::renderscript::Context *rsc,
const android::renderscript::Allocation *alloc,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 1a535d0..bf2b62a 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -18,6 +18,7 @@
#include "rsdAllocation.h"
#include "rsdBcc.h"
#include "rsdGL.h"
+#include "rsdPath.h"
#include "rsdProgramStore.h"
#include "rsdProgramRaster.h"
#include "rsdProgramVertex.h"
@@ -72,6 +73,10 @@
rsdAllocationResize,
rsdAllocationSyncAll,
rsdAllocationMarkDirty,
+ rsdAllocationInitSurfaceTexture,
+ rsdAllocationSetSurfaceTexture,
+ rsdAllocationIoSend,
+ rsdAllocationIoReceive,
rsdAllocationData1D,
rsdAllocationData2D,
rsdAllocationData3D,
@@ -114,6 +119,13 @@
},
{
+ rsdPathInitStatic,
+ rsdPathInitDynamic,
+ rsdPathDraw,
+ rsdPathDestroy
+ },
+
+ {
rsdSamplerInit,
rsdSamplerDestroy
},
@@ -259,6 +271,9 @@
for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
}
+ if (dc->mHasGraphics) {
+ rsdGLSetPriority(rsc, priority);
+ }
}
void Shutdown(Context *rsc) {
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 126c87a..168bdf3 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -41,6 +41,7 @@
typedef struct RsdHalRec {
uint32_t version_major;
uint32_t version_minor;
+ bool mHasGraphics;
struct Workers {
volatile int mRunningCount;
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 368dd710..b136cc7 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -361,6 +361,7 @@
dc->gl.vertexArrayState = new RsdVertexArrayState();
dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
dc->gl.currentFrameBuffer = NULL;
+ dc->mHasGraphics = true;
ALOGV("%p initGLThread end", rsc);
rsc->setWatchdogGL(NULL, 0, NULL);
@@ -421,6 +422,15 @@
RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
}
+void rsdGLSetPriority(const Context *rsc, int32_t priority) {
+ if (priority > 0) {
+ // Mark context as low priority.
+ ALOGV("low pri");
+ } else {
+ ALOGV("normal pri");
+ }
+}
+
void rsdGLCheckError(const android::renderscript::Context *rsc,
const char *msg, bool isFatal) {
GLenum err = glGetError();
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 51893c3..e015cb1 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -82,6 +82,8 @@
void rsdGLSwap(const android::renderscript::Context *rsc);
void rsdGLCheckError(const android::renderscript::Context *rsc,
const char *msg, bool isFatal = false);
+void rsdGLSetPriority(const android::renderscript::Context *rsc,
+ int32_t priority);
#endif
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
index eb62ddb..50daf3e 100644
--- a/libs/rs/driver/rsdMesh.cpp
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -35,7 +35,7 @@
}
drv = new RsdMeshObj(rsc, m);
m->mHal.drv = drv;
- return drv->init();
+ return drv->init(rsc);
}
void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index 99d79dc..893f046 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -50,14 +50,9 @@
}
bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
- // Do not create attribs for padding
- if (elem->getFieldName(fieldIdx)[0] == '#') {
- return false;
- }
-
// Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
// Filter rs types accordingly
- RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+ RsDataType dt = elem->mHal.state.fields[fieldIdx]->mHal.state.dataType;
if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
dt != RS_TYPE_SIGNED_16) {
@@ -65,7 +60,7 @@
}
// Now make sure they are not arrays
- uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+ uint32_t arraySize = elem->mHal.state.fieldArraySizes[fieldIdx];
if (arraySize != 1) {
return false;
}
@@ -73,15 +68,15 @@
return true;
}
-bool RsdMeshObj::init() {
+bool RsdMeshObj::init(const Context *rsc) {
- updateGLPrimitives();
+ updateGLPrimitives(rsc);
// Count the number of gl attrs to initialize
mAttribCount = 0;
for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
- for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+ for (uint32_t ct=0; ct < elem->mHal.state.fieldsCount; ct++) {
if (isValidGLComponent(elem, ct)) {
mAttribCount ++;
}
@@ -104,21 +99,21 @@
uint32_t userNum = 0;
for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
- uint32_t stride = elem->getSizeBytes();
- for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
- const Component &c = elem->getField(fieldI)->getComponent();
+ uint32_t stride = elem->mHal.state.elementSizeBytes;
+ for (uint32_t fieldI=0; fieldI < elem->mHal.state.fieldsCount; fieldI++) {
+ const Element *f = elem->mHal.state.fields[fieldI];
if (!isValidGLComponent(elem, fieldI)) {
continue;
}
- mAttribs[userNum].size = c.getVectorSize();
- mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
- mAttribs[userNum].type = rsdTypeToGLType(c.getType());
- mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+ mAttribs[userNum].size = f->mHal.state.vectorSize;
+ mAttribs[userNum].offset = elem->mHal.state.fieldOffsetBytes[fieldI];
+ mAttribs[userNum].type = rsdTypeToGLType(f->mHal.state.dataType);
+ mAttribs[userNum].normalized = f->mHal.state.dataType != RS_TYPE_FLOAT_32;
mAttribs[userNum].stride = stride;
String8 tmp(RS_SHADER_ATTR);
- tmp.append(elem->getFieldName(fieldI));
+ tmp.append(elem->mHal.state.fieldNames[fieldI]);
mAttribs[userNum].name.setTo(tmp.string());
// Remember which allocation this attribute came from
@@ -133,7 +128,7 @@
void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
uint32_t start, uint32_t len) const {
if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
- ALOGE("Invalid mesh or parameters");
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh or parameters");
return;
}
@@ -186,7 +181,7 @@
rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange");
}
-void RsdMeshObj::updateGLPrimitives() {
+void RsdMeshObj::updateGLPrimitives(const Context *rsc) {
mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
switch (mRSMesh->mHal.state.primitives[i]) {
@@ -196,6 +191,7 @@
case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break;
case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+ default: rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh primitive"); break;
}
}
}
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
index 8b1271b..1370f01 100644
--- a/libs/rs/driver/rsdMeshObj.h
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -37,15 +37,16 @@
const android::renderscript::Mesh *);
~RsdMeshObj();
- void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+ void renderPrimitiveRange(const android::renderscript::Context *,
+ uint32_t primIndex, uint32_t start, uint32_t len) const;
- bool init();
+ bool init(const android::renderscript::Context *rsc);
protected:
const android::renderscript::Mesh *mRSMesh;
uint32_t *mGLPrimitives;
- void updateGLPrimitives();
+ void updateGLPrimitives(const android::renderscript::Context *rsc);
bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
// Attribues that allow us to map to GL
diff --git a/libs/rs/driver/rsdPath.cpp b/libs/rs/driver/rsdPath.cpp
new file mode 100644
index 0000000..e04bc02
--- /dev/null
+++ b/libs/rs/driver/rsdPath.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsPath.h>
+
+#include "rsdCore.h"
+#include "rsdPath.h"
+#include "rsdAllocation.h"
+#include "rsdGL.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+class DrvPath {
+protected:
+ DrvPath();
+public:
+ virtual ~DrvPath();
+ virtual void draw(Context *) = 0;
+};
+
+class DrvPathStatic : public DrvPath {
+public:
+ typedef struct {
+ float x1, xc, x2;
+ float y1, yc, y2;
+ } segment_t;
+
+ segment_t *mSegments;
+ uint32_t mSegmentCount;
+
+ DrvPathStatic(const Allocation *vtx, const Allocation *loops);
+ virtual ~DrvPathStatic();
+
+ virtual void draw(Context *);
+};
+
+class DrvPathDynamic : public DrvPath {
+public:
+ DrvPathDynamic();
+ virtual ~DrvPathDynamic();
+};
+
+static void cleanup(const Context *rsc, const Path *m) {
+ DrvPath *dp = (DrvPath *)m->mHal.drv;
+ if (dp) {
+ delete dp;
+ }
+}
+
+bool rsdPathInitStatic(const Context *rsc, const Path *m,
+ const Allocation *vtx, const Allocation *loops) {
+ DrvPathStatic *drv = NULL;
+ cleanup(rsc, m);
+
+ DrvPathStatic *dps = new DrvPathStatic(vtx, loops);
+ //LOGE("init path m %p, %p", m, dps);
+ m->mHal.drv = dps;
+ return dps != NULL;
+}
+
+bool rsdPathInitDynamic(const Context *rsc, const Path *m) {
+ return false;
+}
+
+
+void rsdPathDraw(const Context *rsc, const Path *m) {
+ //LOGE("render m=%p", m);
+
+ DrvPath *drv = (DrvPath *)m->mHal.drv;
+ if(drv) {
+ //LOGE("render 2 drv=%p", drv);
+ drv->draw((Context *)rsc);
+ }
+}
+
+void rsdPathDestroy(const Context *rsc, const Path *m) {
+ cleanup(rsc, m);
+ m->mHal.drv = NULL;
+}
+
+
+
+
+DrvPath::DrvPath() {
+}
+
+DrvPath::~DrvPath() {
+}
+
+DrvPathStatic::DrvPathStatic(const Allocation *vtx, const Allocation *loops) {
+ mSegmentCount = vtx->getType()->getDimX() / 3;
+ mSegments = new segment_t[mSegmentCount];
+
+ const float *fin = (const float *)vtx->getPtr();
+ for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+ segment_t *s = &mSegments[ct];
+ s->x1 = fin[0];
+ s->y1 = fin[1];
+
+ s->xc = fin[2];
+ s->yc = fin[3];
+
+ s->x2 = fin[4];
+ s->y2 = fin[5];
+ fin += 6;
+ }
+}
+
+DrvPathStatic::~DrvPathStatic() {
+}
+
+void DrvPathStatic::draw(Context *rsc) {
+ const static float color[24] = {
+ 1.f, 0.f, 0.f, 1.f, 0.5f, 0.f, 0.f, 1.f,
+ 1.f, 0.f, 0.f, 1.f, 0.5f, 0.f, 0.f, 1.f,
+ 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
+ float vtx[12];
+
+ //LOGE("draw");
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ if (!dc->gl.shaderCache->setup(rsc)) {
+ return;
+ }
+
+ RsdVertexArray::Attrib attribs[2];
+ attribs[0].set(GL_FLOAT, 2, 8, false, (uint32_t)vtx, "ATTRIB_position");
+ attribs[1].set(GL_FLOAT, 4, 16, false, (uint32_t)color, "ATTRIB_color");
+ RsdVertexArray va(attribs, 2);
+ va.setup(rsc);
+
+ //LOGE("mSegmentCount %i", mSegmentCount);
+ for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+ segment_t *s = &mSegments[ct];
+
+ vtx[0] = s->x1;
+ vtx[1] = s->y1;
+ vtx[2] = s->xc;
+ vtx[3] = s->yc;
+
+ vtx[4] = s->x2;
+ vtx[5] = s->y2;
+ vtx[6] = s->xc;
+ vtx[7] = s->yc;
+
+ vtx[8] = s->x1;
+ vtx[9] = s->y1;
+ vtx[10] = s->x2;
+ vtx[11] = s->y2;
+
+ RSD_CALL_GL(glDrawArrays, GL_LINES, 0, 6);
+ }
+
+}
+
+DrvPathDynamic::DrvPathDynamic() {
+}
+
+DrvPathDynamic::~DrvPathDynamic() {
+}
diff --git a/libs/rs/driver/rsdPath.h b/libs/rs/driver/rsdPath.h
new file mode 100644
index 0000000..fa00972
--- /dev/null
+++ b/libs/rs/driver/rsdPath.h
@@ -0,0 +1,35 @@
+/*
+ * 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 RSD_PATH_H
+#define RSD_PATH_H
+
+#include <rs_hal.h>
+
+
+bool rsdPathInitStatic(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m,
+ const android::renderscript::Allocation *vertex,
+ const android::renderscript::Allocation *loops);
+bool rsdPathInitDynamic(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m);
+void rsdPathDraw(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m);
+void rsdPathDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
index 54484df..fa4cb0f 100644
--- a/libs/rs/driver/rsdProgram.cpp
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -34,8 +34,11 @@
using namespace android::renderscript;
bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv,
- const char* shader, uint32_t shaderLen) {
- RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen);
+ const char* shader, size_t shaderLen,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength) {
+ RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen,
+ textureNames, textureNamesCount, textureNamesLength);
pv->mHal.drv = drv;
return drv->createShader();
@@ -78,8 +81,11 @@
}
bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf,
- const char* shader, uint32_t shaderLen) {
- RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen);
+ const char* shader, size_t shaderLen,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength) {
+ RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen,
+ textureNames, textureNamesCount, textureNamesLength);
pf->mHal.drv = drv;
return drv->createShader();
diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h
index 366cb40..b03a9fe 100644
--- a/libs/rs/driver/rsdProgramFragment.h
+++ b/libs/rs/driver/rsdProgramFragment.h
@@ -22,7 +22,9 @@
bool rsdProgramFragmentInit(const android::renderscript::Context *rsc,
const android::renderscript::ProgramFragment *,
- const char* shader, uint32_t shaderLen);
+ const char* shader, size_t shaderLen,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc,
const android::renderscript::ProgramFragment *);
void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp
index b493759..e5a0291 100644
--- a/libs/rs/driver/rsdProgramRaster.cpp
+++ b/libs/rs/driver/rsdProgramRaster.cpp
@@ -45,6 +45,9 @@
case RS_CULL_NONE:
RSD_CALL_GL(glDisable, GL_CULL_FACE);
break;
+ default:
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid cull type");
+ break;
}
}
diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp
index fca9ba9..c1295e8 100644
--- a/libs/rs/driver/rsdProgramStore.cpp
+++ b/libs/rs/driver/rsdProgramStore.cpp
@@ -111,7 +111,7 @@
drv->blendSrc = GL_SRC_ALPHA_SATURATE;
break;
default:
- ALOGE("Unknown blend src mode.");
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend src mode.");
goto error;
}
@@ -141,7 +141,7 @@
drv->blendDst = GL_ONE_MINUS_DST_ALPHA;
break;
default:
- ALOGE("Unknown blend dst mode.");
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend dst mode.");
goto error;
}
diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h
index e998572..f917a41 100644
--- a/libs/rs/driver/rsdProgramVertex.h
+++ b/libs/rs/driver/rsdProgramVertex.h
@@ -21,7 +21,9 @@
bool rsdProgramVertexInit(const android::renderscript::Context *rsc,
const android::renderscript::ProgramVertex *,
- const char* shader, uint32_t shaderLen);
+ const char* shader, size_t shaderLen,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
void rsdProgramVertexSetActive(const android::renderscript::Context *rsc,
const android::renderscript::ProgramVertex *);
void rsdProgramVertexDestroy(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index 14c2970..44bfb1c 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -25,6 +25,7 @@
#include "rsdCore.h"
#include "rsdRuntime.h"
+#include "rsdPath.h"
#include <time.h>
@@ -89,6 +90,16 @@
rsrBindTexture(rsc, sc, pf, slot, a);
}
+static void SC_BindVertexConstant(ProgramVertex *pv, uint32_t slot, Allocation *a) {
+ GET_TLS();
+ rsrBindConstant(rsc, sc, pv, slot, a);
+}
+
+static void SC_BindFragmentConstant(ProgramFragment *pf, uint32_t slot, Allocation *a) {
+ GET_TLS();
+ rsrBindConstant(rsc, sc, pf, slot, a);
+}
+
static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) {
GET_TLS();
rsrBindSampler(rsc, sc, pf, slot, s);
@@ -204,6 +215,12 @@
rsrDrawRect(rsc, sc, x1, y1, x2, y2, z);
}
+static void SC_DrawPath(Path *p) {
+ GET_TLS();
+ //rsrDrawPath(rsc, sc, p);
+ rsdPathDraw(rsc, p);
+}
+
static void SC_DrawMesh(Mesh *m) {
GET_TLS();
rsrDrawMesh(rsc, sc, m);
@@ -533,6 +550,10 @@
{ "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true },
{ "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true },
+ { "_Z11rsSetObjectP7rs_pathS_", (void *)&SC_SetObject, true },
+ { "_Z13rsClearObjectP7rs_path", (void *)&SC_ClearObject, true },
+ { "_Z10rsIsObject7rs_path", (void *)&SC_IsObject, true },
+
{ "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true },
{ "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true },
{ "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true },
@@ -580,6 +601,8 @@
{ "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false },
{ "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false },
{ "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false },
+ { "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", (void *)&SC_BindFragmentConstant, false },
+ { "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", (void *)&SC_BindVertexConstant, false },
{ "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false },
{ "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false },
@@ -603,6 +626,8 @@
{ "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false },
{ "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false },
+ { "_Z11rsgDrawPath7rs_path", (void *)&SC_DrawPath, false },
+
{ "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
{ "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index c70193ae..1e73b95 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -30,14 +30,16 @@
using namespace android::renderscript;
RsdShader::RsdShader(const Program *p, uint32_t type,
- const char * shaderText, uint32_t shaderLength) {
-
+ const char * shaderText, size_t shaderLength,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength) {
mUserShader.setTo(shaderText, shaderLength);
mRSProgram = p;
mType = type;
initMemberVars();
initAttribAndUniformArray();
- init();
+ init(textureNames, textureNamesCount, textureNamesLength);
+ createTexturesString(textureNames, textureNamesCount, textureNamesLength);
}
RsdShader::~RsdShader() {
@@ -65,37 +67,38 @@
mIsValid = false;
}
-void RsdShader::init() {
+void RsdShader::init(const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength) {
uint32_t attribCount = 0;
uint32_t uniformCount = 0;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
- initAddUserElement(mRSProgram->mHal.state.inputElements[ct], mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
+ initAddUserElement(mRSProgram->mHal.state.inputElements[ct], mAttribNames,
+ NULL, &attribCount, RS_SHADER_ATTR);
}
for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
- initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
+ initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(),
+ mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
}
mTextureUniformIndexStart = uniformCount;
- char buf[256];
for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
- snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
- mUniformNames[uniformCount].setTo(buf);
+ mUniformNames[uniformCount].setTo("UNI_");
+ mUniformNames[uniformCount].append(textureNames[ct], textureNamesLength[ct]);
mUniformArraySizes[uniformCount] = 1;
uniformCount++;
}
-
}
String8 RsdShader::getGLSLInputString() const {
String8 s;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
const Element *e = mRSProgram->mHal.state.inputElements[ct];
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
// Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
+ rsAssert(!f->mHal.state.fieldsCount);
+ switch (f->mHal.state.vectorSize) {
case 1: s.append("attribute float ATTRIB_"); break;
case 2: s.append("attribute vec2 ATTRIB_"); break;
case 3: s.append("attribute vec3 ATTRIB_"); break;
@@ -104,7 +107,7 @@
rsAssert(0);
}
- s.append(e->getFieldName(field));
+ s.append(e->mHal.state.fieldNames[field]);
s.append(";\n");
}
}
@@ -114,17 +117,13 @@
void RsdShader::appendAttributes() {
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
const Element *e = mRSProgram->mHal.state.inputElements[ct];
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
+ const char *fn = e->mHal.state.fieldNames[field];
// Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
+ rsAssert(!f->mHal.state.fieldsCount);
+ switch (f->mHal.state.vectorSize) {
case 1: mShader.append("attribute float ATTRIB_"); break;
case 2: mShader.append("attribute vec2 ATTRIB_"); break;
case 3: mShader.append("attribute vec3 ATTRIB_"); break;
@@ -139,17 +138,25 @@
}
}
-void RsdShader::appendTextures() {
- char buf[256];
- for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+void RsdShader::createTexturesString(const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength) {
+ mShaderTextures.setTo("");
+ for (uint32_t ct = 0; ct < mRSProgram->mHal.state.texturesCount; ct ++) {
if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
- snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+ Allocation *a = mRSProgram->mHal.state.textures[ct];
+ if (a && a->mHal.state.surfaceTextureID) {
+ mShaderTextures.append("uniform samplerExternalOES UNI_");
+ } else {
+ mShaderTextures.append("uniform sampler2D UNI_");
+ }
mTextureTargets[ct] = GL_TEXTURE_2D;
} else {
- snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
+ mShaderTextures.append("uniform samplerCube UNI_");
mTextureTargets[ct] = GL_TEXTURE_CUBE_MAP;
}
- mShader.append(buf);
+
+ mShaderTextures.append(textureNames[ct], textureNamesLength[ct]);
+ mShaderTextures.append(";\n");
}
}
@@ -160,7 +167,7 @@
}
appendUserConstants();
appendAttributes();
- appendTextures();
+ mShader.append(mShaderTextures);
mShader.append(mUserShader);
@@ -190,12 +197,11 @@
char* buf = (char*) malloc(infoLen);
if (buf) {
RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
- ALOGE("Could not compile shader \n%s\n", buf);
+ rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
free(buf);
}
RSD_CALL_GL(glDeleteShader, mShaderID);
mShaderID = 0;
- rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
return false;
}
}
@@ -211,24 +217,20 @@
void RsdShader::appendUserConstants() {
for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
+ const char *fn = e->mHal.state.fieldNames[field];
// Cannot be complex
- rsAssert(!f->getFieldCount());
- if (f->getType() == RS_TYPE_MATRIX_4X4) {
+ rsAssert(!f->mHal.state.fieldsCount);
+ if (f->mHal.state.dataType == RS_TYPE_MATRIX_4X4) {
mShader.append("uniform mat4 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+ } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_3X3) {
mShader.append("uniform mat3 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+ } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_2X2) {
mShader.append("uniform mat2 UNI_");
} else {
- switch (f->getComponent().getVectorSize()) {
+ switch (f->mHal.state.vectorSize) {
case 1: mShader.append("uniform float UNI_"); break;
case 2: mShader.append("uniform vec2 UNI_"); break;
case 3: mShader.append("uniform vec3 UNI_"); break;
@@ -239,8 +241,8 @@
}
mShader.append(fn);
- if (e->getFieldArraySize(field) > 1) {
- mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+ if (e->mHal.state.fieldArraySizes[field] > 1) {
+ mShader.appendFormat("[%d]", e->mHal.state.fieldArraySizes[field]);
}
mShader.append(";\n");
}
@@ -248,8 +250,8 @@
}
void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
- uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+ RsDataType dataType = field->mHal.state.dataType;
+ uint32_t elementSize = field->mHal.state.elementSizeBytes / sizeof(float);
for (uint32_t i = 0; i < arraySize; i ++) {
if (arraySize > 1) {
ALOGV("Array Element [%u]", i);
@@ -270,7 +272,7 @@
ALOGV("{%f, %f", fd[0], fd[2]);
ALOGV(" %f, %f}", fd[1], fd[3]);
} else {
- switch (field->getComponent().getVectorSize()) {
+ switch (field->mHal.state.vectorSize) {
case 1:
ALOGV("Uniform 1 = %f", fd[0]);
break;
@@ -295,7 +297,7 @@
void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
int32_t slot, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
+ RsDataType dataType = field->mHal.state.dataType;
if (dataType == RS_TYPE_MATRIX_4X4) {
RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd);
} else if (dataType == RS_TYPE_MATRIX_3X3) {
@@ -303,7 +305,7 @@
} else if (dataType == RS_TYPE_MATRIX_2X2) {
RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd);
} else {
- switch (field->getComponent().getVectorSize()) {
+ switch (field->mHal.state.vectorSize) {
case 1:
RSD_CALL_GL(glUniform1fv, slot, arraySize, fd);
break;
@@ -422,7 +424,8 @@
DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv;
if (drvTex->glTarget != GL_TEXTURE_2D && drvTex->glTarget != GL_TEXTURE_CUBE_MAP) {
- ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
+ ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u",
+ (uint)this, ct);
rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
}
RSD_CALL_GL(glBindTexture, drvTex->glTarget, drvTex->textureID);
@@ -458,15 +461,11 @@
const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fieldName = e->getFieldName(field);
- // If this field is padding, skip it
- if (fieldName[0] == '#') {
- continue;
- }
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
+ const char *fieldName = e->mHal.state.fieldNames[field];
- uint32_t offset = e->getFieldOffsetBytes(field);
+ uint32_t offset = e->mHal.state.fieldOffsetBytes[field];
const float *fd = reinterpret_cast<const float *>(&data[offset]);
int32_t slot = -1;
@@ -505,22 +504,13 @@
mAttribCount = 0;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
const Element *elem = mRSProgram->mHal.state.inputElements[ct];
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mAttribCount ++;
- }
- }
+ mAttribCount += elem->mHal.state.fieldsCount;
}
mUniformCount = 0;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mUniformCount ++;
- }
- }
+ mUniformCount += elem->mHal.state.fieldsCount;
}
mUniformCount += mRSProgram->mHal.state.texturesCount;
@@ -540,17 +530,17 @@
void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
uint32_t *count, const char *prefix) {
- rsAssert(e->getFieldCount());
- for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
- const Element *ce = e->getField(ct);
- if (ce->getFieldCount()) {
+ rsAssert(e->mHal.state.fieldsCount);
+ for (uint32_t ct=0; ct < e->mHal.state.fieldsCount; ct++) {
+ const Element *ce = e->mHal.state.fields[ct];
+ if (ce->mHal.state.fieldsCount) {
initAddUserElement(ce, names, arrayLengths, count, prefix);
- } else if (e->getFieldName(ct)[0] != '#') {
+ } else {
String8 tmp(prefix);
- tmp.append(e->getFieldName(ct));
+ tmp.append(e->mHal.state.fieldNames[ct]);
names[*count].setTo(tmp.string());
if (arrayLengths) {
- arrayLengths[*count] = e->getFieldArraySize(ct);
+ arrayLengths[*count] = e->mHal.state.fieldArraySizes[ct];
}
(*count)++;
}
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
index 3f0d6ea..e32145f 100644
--- a/libs/rs/driver/rsdShader.h
+++ b/libs/rs/driver/rsdShader.h
@@ -39,7 +39,9 @@
public:
RsdShader(const android::renderscript::Program *p, uint32_t type,
- const char * shaderText, uint32_t shaderLength);
+ const char * shaderText, uint32_t shaderLength,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
virtual ~RsdShader();
bool createShader();
@@ -67,19 +69,27 @@
// Applies to vertex and fragment shaders only
void appendUserConstants();
- void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment);
- void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
+ void setupUserConstants(const android::renderscript::Context *rsc,
+ RsdShaderCache *sc, bool isFragment);
+ void initAddUserElement(const android::renderscript::Element *e,
+ android::String8 *names, uint32_t *arrayLengths,
+ uint32_t *count, const char *prefix);
void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc);
- void setupSampler(const android::renderscript::Context *rsc, const android::renderscript::Sampler *s, const android::renderscript::Allocation *tex);
+ void setupSampler(const android::renderscript::Context *rsc,
+ const android::renderscript::Sampler *s,
+ const android::renderscript::Allocation *tex);
void appendAttributes();
void appendTextures();
+ void createTexturesString(const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
void initAttribAndUniformArray();
mutable bool mDirty;
android::String8 mShader;
android::String8 mUserShader;
+ android::String8 mShaderTextures;
uint32_t mShaderID;
uint32_t mType;
@@ -93,10 +103,14 @@
int32_t mTextureUniformIndexStart;
- void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize );
- void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize );
+ void logUniform(const android::renderscript::Element *field,
+ const float *fd, uint32_t arraySize);
+ void setUniform(const android::renderscript::Context *rsc,
+ const android::renderscript::Element *field,
+ const float *fd, int32_t slot, uint32_t arraySize );
void initMemberVars();
- void init();
+ void init(const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
};
#endif //ANDROID_RSD_SHADER_H
diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index f6236e7..89d3c45 100644
--- a/libs/rs/driver/rsdShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -167,12 +167,11 @@
char* buf = (char*) malloc(bufLength);
if (buf) {
glGetProgramInfoLog(pgm, bufLength, NULL, buf);
- ALOGE("Could not link program:\n%s\n", buf);
+ rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
free(buf);
}
}
glDeleteProgram(pgm);
- rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs");
return false;
}
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 17ee3e8..0beecae 100644
--- a/libs/rs/driver/rsdShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -98,7 +98,8 @@
struct ProgramEntry {
ProgramEntry(uint32_t numVtxAttr, uint32_t numVtxUnis,
uint32_t numFragUnis) : vtx(0), frag(0), program(0), vtxAttrCount(0),
- vtxAttrs(0), vtxUniforms(0), fragUniforms(0) {
+ vtxAttrs(0), vtxUniforms(0), fragUniforms(0),
+ fragUniformIsSTO(0) {
vtxAttrCount = numVtxAttr;
if (numVtxAttr) {
vtxAttrs = new AttrData[numVtxAttr];
@@ -108,6 +109,7 @@
}
if (numFragUnis) {
fragUniforms = new UniformData[numFragUnis];
+ fragUniformIsSTO = new bool[numFragUnis];
}
}
~ProgramEntry() {
@@ -123,6 +125,10 @@
delete[] fragUniforms;
fragUniforms = NULL;
}
+ if (fragUniformIsSTO) {
+ delete[] fragUniformIsSTO;
+ fragUniformIsSTO = NULL;
+ }
}
uint32_t vtx;
uint32_t frag;
@@ -131,6 +137,7 @@
AttrData *vtxAttrs;
UniformData *vtxUniforms;
UniformData *fragUniforms;
+ bool *fragUniformIsSTO;
};
android::Vector<ProgramEntry*> mEntries;
ProgramEntry *mCurrent;
diff --git a/libs/rs/RenderScript.h b/libs/rs/rs.h
similarity index 98%
rename from libs/rs/RenderScript.h
rename to libs/rs/rs.h
index 6d54268..fbcaf4a 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/rs.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-#include "RenderScriptDefines.h"
+#include "rsDefines.h"
//
// A3D loading and object update code.
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ffb1196..cf4a391 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -42,6 +42,7 @@
param RsType vtype
param RsAllocationMipmapControl mips
param uint32_t usages
+ param uint32_t ptr
ret RsAllocation
}
@@ -63,170 +64,188 @@
ret RsAllocation
}
+AllocationGetSurfaceTextureID {
+ param RsAllocation alloc
+ ret int32_t
+}
+
+AllocationSetSurface {
+ param RsAllocation alloc
+ param RsNativeWindow sur
+ sync
+ }
+
+AllocationIoSend {
+ param RsAllocation alloc
+ }
+
+AllocationIoReceive {
+ param RsAllocation alloc
+ }
ContextFinish {
- sync
- }
+ sync
+ }
ContextBindRootScript {
- param RsScript sampler
- }
+ param RsScript sampler
+ }
ContextBindProgramStore {
- param RsProgramStore pgm
- }
+ param RsProgramStore pgm
+ }
ContextBindProgramFragment {
- param RsProgramFragment pgm
- }
+ param RsProgramFragment pgm
+ }
ContextBindProgramVertex {
- param RsProgramVertex pgm
- }
+ param RsProgramVertex pgm
+ }
ContextBindProgramRaster {
- param RsProgramRaster pgm
- }
+ param RsProgramRaster pgm
+ }
ContextBindFont {
- param RsFont pgm
- }
+ param RsFont pgm
+ }
ContextPause {
- }
+ }
ContextResume {
- }
+ }
ContextSetSurface {
- param uint32_t width
- param uint32_t height
- param RsNativeWindow sur
+ param uint32_t width
+ param uint32_t height
+ param RsNativeWindow sur
sync
- }
+ }
ContextDump {
- param int32_t bits
+ param int32_t bits
}
ContextSetPriority {
- param int32_t priority
- }
+ param int32_t priority
+ }
ContextDestroyWorker {
sync
}
AssignName {
- param RsObjectBase obj
- param const char *name
- }
+ param RsObjectBase obj
+ param const char *name
+ }
ObjDestroy {
- param RsAsyncVoidPtr objPtr
- }
+ param RsAsyncVoidPtr objPtr
+ }
ElementCreate {
direct
- param RsDataType mType
- param RsDataKind mKind
- param bool mNormalized
- param uint32_t mVectorSize
- ret RsElement
- }
+ param RsDataType mType
+ param RsDataKind mKind
+ param bool mNormalized
+ param uint32_t mVectorSize
+ ret RsElement
+ }
ElementCreate2 {
direct
- param const RsElement * elements
- param const char ** names
- param const uint32_t * arraySize
- ret RsElement
- }
+ param const RsElement * elements
+ param const char ** names
+ param const uint32_t * arraySize
+ ret RsElement
+ }
AllocationCopyToBitmap {
- param RsAllocation alloc
- param void * data
- }
+ param RsAllocation alloc
+ param void * data
+ }
Allocation1DData {
- param RsAllocation va
- param uint32_t xoff
- param uint32_t lod
- param uint32_t count
- param const void *data
- }
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t lod
+ param uint32_t count
+ param const void *data
+ }
Allocation1DElementData {
- param RsAllocation va
- param uint32_t x
- param uint32_t lod
- param const void *data
- param size_t comp_offset
- }
+ param RsAllocation va
+ param uint32_t x
+ param uint32_t lod
+ param const void *data
+ param size_t comp_offset
+ }
Allocation2DData {
- param RsAllocation va
- param uint32_t xoff
- param uint32_t yoff
- param uint32_t lod
- param RsAllocationCubemapFace face
- param uint32_t w
- param uint32_t h
- param const void *data
- }
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t lod
+ param RsAllocationCubemapFace face
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
Allocation2DElementData {
- param RsAllocation va
- param uint32_t x
- param uint32_t y
- param uint32_t lod
- param RsAllocationCubemapFace face
- param const void *data
- param size_t element_offset
- }
+ param RsAllocation va
+ param uint32_t x
+ param uint32_t y
+ param uint32_t lod
+ param RsAllocationCubemapFace face
+ param const void *data
+ param size_t element_offset
+ }
AllocationGenerateMipmaps {
- param RsAllocation va
+ param RsAllocation va
}
AllocationRead {
- param RsAllocation va
- param void * data
- }
+ param RsAllocation va
+ param void * data
+ }
AllocationSyncAll {
- param RsAllocation va
- param RsAllocationUsageType src
+ param RsAllocation va
+ param RsAllocationUsageType src
}
AllocationResize1D {
- param RsAllocation va
- param uint32_t dimX
- }
+ param RsAllocation va
+ param uint32_t dimX
+ }
AllocationResize2D {
- param RsAllocation va
- param uint32_t dimX
- param uint32_t dimY
- }
+ param RsAllocation va
+ param uint32_t dimX
+ param uint32_t dimY
+ }
AllocationCopy2DRange {
- param RsAllocation dest
- param uint32_t destXoff
- param uint32_t destYoff
- param uint32_t destMip
- param uint32_t destFace
- param uint32_t width
- param uint32_t height
- param RsAllocation src
- param uint32_t srcXoff
- param uint32_t srcYoff
- param uint32_t srcMip
- param uint32_t srcFace
- }
+ param RsAllocation dest
+ param uint32_t destXoff
+ param uint32_t destYoff
+ param uint32_t destMip
+ param uint32_t destFace
+ param uint32_t width
+ param uint32_t height
+ param RsAllocation src
+ param uint32_t srcXoff
+ param uint32_t srcYoff
+ param uint32_t srcMip
+ param uint32_t srcFace
+ }
SamplerCreate {
direct
@@ -240,26 +259,26 @@
}
ScriptBindAllocation {
- param RsScript vtm
- param RsAllocation va
- param uint32_t slot
- }
+ param RsScript vtm
+ param RsAllocation va
+ param uint32_t slot
+ }
ScriptSetTimeZone {
- param RsScript s
- param const char * timeZone
- }
+ param RsScript s
+ param const char * timeZone
+ }
ScriptInvoke {
- param RsScript s
- param uint32_t slot
- }
+ param RsScript s
+ param uint32_t slot
+ }
ScriptInvokeV {
- param RsScript s
- param uint32_t slot
- param const void * data
- }
+ param RsScript s
+ param uint32_t slot
+ param const void * data
+ }
ScriptForEach {
param RsScript s
@@ -270,122 +289,133 @@
}
ScriptSetVarI {
- param RsScript s
- param uint32_t slot
- param int value
- }
+ param RsScript s
+ param uint32_t slot
+ param int value
+ }
ScriptSetVarObj {
- param RsScript s
- param uint32_t slot
- param RsObjectBase value
- }
+ param RsScript s
+ param uint32_t slot
+ param RsObjectBase value
+ }
ScriptSetVarJ {
- param RsScript s
- param uint32_t slot
- param int64_t value
- }
+ param RsScript s
+ param uint32_t slot
+ param int64_t value
+ }
ScriptSetVarF {
- param RsScript s
- param uint32_t slot
- param float value
- }
+ param RsScript s
+ param uint32_t slot
+ param float value
+ }
ScriptSetVarD {
- param RsScript s
- param uint32_t slot
- param double value
- }
+ param RsScript s
+ param uint32_t slot
+ param double value
+ }
ScriptSetVarV {
- param RsScript s
- param uint32_t slot
- param const void * data
- }
+ param RsScript s
+ param uint32_t slot
+ param const void * data
+ }
ScriptCCreate {
param const char * resName
param const char * cacheDir
- param const char * text
- ret RsScript
- }
+ param const char * text
+ ret RsScript
+ }
ProgramStoreCreate {
- direct
- param bool colorMaskR
- param bool colorMaskG
- param bool colorMaskB
- param bool colorMaskA
+ direct
+ param bool colorMaskR
+ param bool colorMaskG
+ param bool colorMaskB
+ param bool colorMaskA
param bool depthMask
param bool ditherEnable
- param RsBlendSrcFunc srcFunc
- param RsBlendDstFunc destFunc
+ param RsBlendSrcFunc srcFunc
+ param RsBlendDstFunc destFunc
param RsDepthFunc depthFunc
- ret RsProgramStore
- }
+ ret RsProgramStore
+ }
ProgramRasterCreate {
- direct
- param bool pointSprite
- param RsCullMode cull
- ret RsProgramRaster
+ direct
+ param bool pointSprite
+ param RsCullMode cull
+ ret RsProgramRaster
}
ProgramBindConstants {
- param RsProgram vp
- param uint32_t slot
- param RsAllocation constants
- }
+ param RsProgram vp
+ param uint32_t slot
+ param RsAllocation constants
+ }
ProgramBindTexture {
- param RsProgramFragment pf
- param uint32_t slot
- param RsAllocation a
- }
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsAllocation a
+ }
ProgramBindSampler {
- param RsProgramFragment pf
- param uint32_t slot
- param RsSampler s
- }
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsSampler s
+ }
ProgramFragmentCreate {
- direct
- param const char * shaderText
- param const uint32_t * params
- ret RsProgramFragment
- }
+ direct
+ param const char * shaderText
+ param const char ** textureNames
+ param const uint32_t * params
+ ret RsProgramFragment
+ }
ProgramVertexCreate {
- direct
- param const char * shaderText
- param const uint32_t * params
- ret RsProgramVertex
- }
+ direct
+ param const char * shaderText
+ param const char ** textureNames
+ param const uint32_t * params
+ ret RsProgramVertex
+ }
FontCreateFromFile {
- param const char *name
- param float fontSize
- param uint32_t dpi
- ret RsFont
- }
+ param const char *name
+ param float fontSize
+ param uint32_t dpi
+ ret RsFont
+ }
FontCreateFromMemory {
- param const char *name
- param float fontSize
- param uint32_t dpi
- param const void *data
- ret RsFont
- }
+ param const char *name
+ param float fontSize
+ param uint32_t dpi
+ param const void *data
+ ret RsFont
+ }
MeshCreate {
- param RsAllocation *vtx
- param RsAllocation *idx
- param uint32_t *primType
- ret RsMesh
- }
+ param RsAllocation *vtx
+ param RsAllocation *idx
+ param uint32_t *primType
+ ret RsMesh
+ }
+
+PathCreate {
+ param RsPathPrimitive pp
+ param bool isStatic
+ param RsAllocation vertex
+ param RsAllocation loops
+ param float quality
+ ret RsPath
+ }
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index fd85b07..83c88fd 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -17,32 +17,35 @@
#include "rsContext.h"
#include "rs_hal.h"
+#include "system/window.h"
using namespace android;
using namespace android::renderscript;
Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages,
- RsAllocationMipmapControl mc)
+ RsAllocationMipmapControl mc, void * ptr)
: ObjectBase(rsc) {
memset(&mHal, 0, sizeof(mHal));
mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
mHal.state.usageFlags = usages;
mHal.state.mipmapControl = mc;
+ mHal.state.usrPtr = ptr;
setType(type);
updateCache();
}
Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages,
- RsAllocationMipmapControl mc) {
- Allocation *a = new Allocation(rsc, type, usages, mc);
+ RsAllocationMipmapControl mc, void * ptr) {
+ Allocation *a = new Allocation(rsc, type, usages, mc, ptr);
if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) {
rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure");
delete a;
return NULL;
}
+
return a;
}
@@ -413,6 +416,34 @@
ALOGE("not implemented");
}
+int32_t Allocation::getSurfaceTextureID(const Context *rsc) {
+ int32_t id = rsc->mHal.funcs.allocation.initSurfaceTexture(rsc, this);
+ mHal.state.surfaceTextureID = id;
+ return id;
+}
+
+void Allocation::setSurface(const Context *rsc, RsNativeWindow sur) {
+ ANativeWindow *nw = (ANativeWindow *)sur;
+ ANativeWindow *old = mHal.state.wndSurface;
+ if (nw) {
+ nw->incStrong(NULL);
+ }
+ rsc->mHal.funcs.allocation.setSurfaceTexture(rsc, this, nw);
+ mHal.state.wndSurface = nw;
+ if (old) {
+ old->decStrong(NULL);
+ }
+}
+
+void Allocation::ioSend(const Context *rsc) {
+ rsc->mHal.funcs.allocation.ioSend(rsc, this);
+}
+
+void Allocation::ioReceive(const Context *rsc) {
+ rsc->mHal.funcs.allocation.ioReceive(rsc, this);
+}
+
+
/////////////////
//
@@ -571,8 +602,8 @@
RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
RsAllocationMipmapControl mips,
- uint32_t usages) {
- Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips);
+ uint32_t usages, uint32_t ptr) {
+ Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips, (void *)ptr);
if (!alloc) {
return NULL;
}
@@ -585,7 +616,7 @@
const void *data, size_t data_length, uint32_t usages) {
Type *t = static_cast<Type *>(vtype);
- RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
if (texAlloc == NULL) {
ALOGE("Memory allocation failure");
@@ -609,7 +640,7 @@
// Cubemap allocation's faces should be Width by Width each.
// Source data should have 6 * Width by Width pixels
// Error checking is done in the java layer
- RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
if (texAlloc == NULL) {
ALOGE("Memory allocation failure");
@@ -658,6 +689,26 @@
(RsAllocationCubemapFace)srcFace);
}
+int32_t rsi_AllocationGetSurfaceTextureID(Context *rsc, RsAllocation valloc) {
+ Allocation *alloc = static_cast<Allocation *>(valloc);
+ return alloc->getSurfaceTextureID(rsc);
+}
+
+void rsi_AllocationSetSurface(Context *rsc, RsAllocation valloc, RsNativeWindow sur) {
+ Allocation *alloc = static_cast<Allocation *>(valloc);
+ alloc->setSurface(rsc, sur);
+}
+
+void rsi_AllocationIoSend(Context *rsc, RsAllocation valloc) {
+ Allocation *alloc = static_cast<Allocation *>(valloc);
+ alloc->ioSend(rsc);
+}
+
+void rsi_AllocationIoReceive(Context *rsc, RsAllocation valloc) {
+ Allocation *alloc = static_cast<Allocation *>(valloc);
+ alloc->ioReceive(rsc);
+}
+
}
}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 20201ca..58a6fca 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -19,6 +19,8 @@
#include "rsType.h"
+struct ANativeWindow;
+
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
@@ -55,6 +57,9 @@
bool hasMipmaps;
bool hasFaces;
bool hasReferences;
+ void * usrPtr;
+ int32_t surfaceTextureID;
+ ANativeWindow *wndSurface;
};
State state;
@@ -66,7 +71,8 @@
Hal mHal;
static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages,
- RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE);
+ RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE,
+ void *ptr = 0);
virtual ~Allocation();
void updateCache();
@@ -123,6 +129,10 @@
return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE;
}
+ int32_t getSurfaceTextureID(const Context *rsc);
+ void setSurface(const Context *rsc, RsNativeWindow sur);
+ void ioSend(const Context *rsc);
+ void ioReceive(const Context *rsc);
protected:
Vector<const Program *> mToDirtyList;
@@ -134,7 +144,7 @@
private:
void freeChildrenUnlocked();
- Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc);
+ Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc, void *ptr);
uint32_t getPackedSize() const;
static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded);
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index 21b98f6..9c2c200 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -62,6 +62,7 @@
rsAssert(mNormalized == true);
break;
default:
+ rsAssert(mKind != RS_KIND_INVALID);
break;
}
@@ -167,6 +168,9 @@
case RS_TYPE_BOOLEAN:
mTypeBits = 8;
break;
+ default:
+ rsAssert(mType != RS_TYPE_INVALID);
+ break;
}
mBitsUnpadded = mTypeBits * mVectorSize;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 04284dd..95ac76e 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -248,7 +248,7 @@
rsc->mRunning = true;
if (!rsc->mIsGraphicsContext) {
while (!rsc->mExit) {
- rsc->mIO.playCoreCommands(rsc, true, -1);
+ rsc->mIO.playCoreCommands(rsc, -1);
}
} else {
#ifndef ANDROID_RS_SERIALIZE
@@ -263,19 +263,23 @@
rsc->timerSet(RS_TIMER_IDLE);
#ifndef ANDROID_RS_SERIALIZE
+ if (!rsc->mRootScript.get() || !rsc->mHasSurface || rsc->mPaused) {
+ targetRate = 0;
+ }
+
if (vsyncRate != targetRate) {
displayEvent.setVsyncRate(targetRate);
vsyncRate = targetRate;
}
if (targetRate) {
- drawOnce |= rsc->mIO.playCoreCommands(rsc, true, displayEvent.getFd());
+ drawOnce |= rsc->mIO.playCoreCommands(rsc, displayEvent.getFd());
while (displayEvent.getEvents(eventBuffer, 1) != 0) {
//ALOGE("vs2 time past %lld", (rsc->getTime() - eventBuffer[0].header.timestamp) / 1000000);
}
} else
#endif
{
- drawOnce |= rsc->mIO.playCoreCommands(rsc, true, -1);
+ drawOnce |= rsc->mIO.playCoreCommands(rsc, -1);
}
if ((rsc->mRootScript.get() != NULL) && rsc->mHasSurface &&
@@ -361,6 +365,7 @@
#else
setpriority(PRIO_PROCESS, mNativeThreadId, p);
#endif
+ mHal.funcs.setPriority(this, mThreadPriority);
}
Context::Context() {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index a844a20..05c799e 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -32,6 +32,7 @@
#include "rsAdapter.h"
#include "rsSampler.h"
#include "rsFont.h"
+#include "rsPath.h"
#include "rsProgramFragment.h"
#include "rsProgramStore.h"
#include "rsProgramRaster.h"
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/rsDefines.h
similarity index 91%
rename from libs/rs/RenderScriptDefines.h
rename to libs/rs/rsDefines.h
index d092520..990ef26 100644
--- a/libs/rs/RenderScriptDefines.h
+++ b/libs/rs/rsDefines.h
@@ -41,6 +41,7 @@
typedef void * RsSampler;
typedef void * RsScript;
typedef void * RsMesh;
+typedef void * RsPath;
typedef void * RsType;
typedef void * RsObjectBase;
@@ -99,8 +100,11 @@
RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010,
+ RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020,
+ RS_ALLOCATION_USAGE_IO_INPUT = 0x0040,
+ RS_ALLOCATION_USAGE_IO_OUTPUT = 0x0080,
- RS_ALLOCATION_USAGE_ALL = 0x000F
+ RS_ALLOCATION_USAGE_ALL = 0x00FF
};
enum RsAllocationMipmapControl {
@@ -152,6 +156,8 @@
RS_TYPE_PROGRAM_VERTEX,
RS_TYPE_PROGRAM_RASTER,
RS_TYPE_PROGRAM_STORE,
+
+ RS_TYPE_INVALID = 10000,
};
enum RsDataKind {
@@ -163,6 +169,8 @@
RS_KIND_PIXEL_RGB,
RS_KIND_PIXEL_RGBA,
RS_KIND_PIXEL_DEPTH,
+
+ RS_KIND_INVALID = 100,
};
enum RsSamplerParam {
@@ -181,6 +189,8 @@
RS_SAMPLER_WRAP,
RS_SAMPLER_CLAMP,
RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+ RS_SAMPLER_INVALID = 100,
};
enum RsTextureTarget {
@@ -221,7 +231,8 @@
RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
RS_BLEND_SRC_DST_ALPHA, // 6
RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
- RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE, // 8
+ RS_BLEND_SRC_INVALID = 100,
};
enum RsBlendDstFunc {
@@ -232,7 +243,9 @@
RS_BLEND_DST_SRC_ALPHA, // 4
RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
RS_BLEND_DST_DST_ALPHA, // 6
- RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA, // 7
+
+ RS_BLEND_DST_INVALID = 100,
};
enum RsTexEnvMode {
@@ -255,7 +268,14 @@
RS_PRIMITIVE_LINE_STRIP,
RS_PRIMITIVE_TRIANGLE,
RS_PRIMITIVE_TRIANGLE_STRIP,
- RS_PRIMITIVE_TRIANGLE_FAN
+ RS_PRIMITIVE_TRIANGLE_FAN,
+
+ RS_PRIMITIVE_INVALID = 100,
+};
+
+enum RsPathPrimitive {
+ RS_PATH_PRIMITIVE_QUADRATIC_BEZIER,
+ RS_PATH_PRIMITIVE_CUBIC_BEZIER
};
enum RsError {
@@ -309,7 +329,8 @@
enum RsCullMode {
RS_CULL_BACK,
RS_CULL_FRONT,
- RS_CULL_NONE
+ RS_CULL_NONE,
+ RS_CULL_INVALID = 100,
};
typedef struct {
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index dff9585..fb2892c 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -27,6 +27,7 @@
mFields = NULL;
mFieldCount = 0;
mHasReference = false;
+ memset(&mHal, 0, sizeof(mHal));
}
Element::~Element() {
@@ -47,6 +48,12 @@
mFields = NULL;
mFieldCount = 0;
mHasReference = false;
+
+ delete [] mHal.state.fields;
+ delete [] mHal.state.fieldArraySizes;
+ delete [] mHal.state.fieldNames;
+ delete [] mHal.state.fieldNameLengths;
+ delete [] mHal.state.fieldOffsetBytes;
}
size_t Element::getSizeBits() const {
@@ -157,16 +164,36 @@
}
void Element::compute() {
+ mHal.state.dataType = mComponent.getType();
+ mHal.state.dataKind = mComponent.getKind();
+ mHal.state.vectorSize = mComponent.getVectorSize();
+
if (mFieldCount == 0) {
mBits = mComponent.getBits();
mBitsUnpadded = mComponent.getBitsUnpadded();
mHasReference = mComponent.isReference();
+
+ mHal.state.elementSizeBytes = getSizeBytes();
return;
}
+ uint32_t noPaddingFieldCount = 0;
+ for (uint32_t ct = 0; ct < mFieldCount; ct ++) {
+ if (mFields[ct].name.string()[0] != '#') {
+ noPaddingFieldCount ++;
+ }
+ }
+
+ mHal.state.fields = new const Element*[noPaddingFieldCount];
+ mHal.state.fieldArraySizes = new uint32_t[noPaddingFieldCount];
+ mHal.state.fieldNames = new const char*[noPaddingFieldCount];
+ mHal.state.fieldNameLengths = new uint32_t[noPaddingFieldCount];
+ mHal.state.fieldOffsetBytes = new uint32_t[noPaddingFieldCount];
+ mHal.state.fieldsCount = noPaddingFieldCount;
+
size_t bits = 0;
size_t bitsUnpadded = 0;
- for (size_t ct=0; ct < mFieldCount; ct++) {
+ for (size_t ct = 0, ctNoPadding = 0; ct < mFieldCount; ct++) {
mFields[ct].offsetBits = bits;
mFields[ct].offsetBitsUnpadded = bitsUnpadded;
bits += mFields[ct].e->getSizeBits() * mFields[ct].arraySize;
@@ -175,8 +202,21 @@
if (mFields[ct].e->mHasReference) {
mHasReference = true;
}
+
+ if (mFields[ct].name.string()[0] == '#') {
+ continue;
+ }
+
+ mHal.state.fields[ctNoPadding] = mFields[ct].e.get();
+ mHal.state.fieldArraySizes[ctNoPadding] = mFields[ct].arraySize;
+ mHal.state.fieldNames[ctNoPadding] = mFields[ct].name.string();
+ mHal.state.fieldNameLengths[ctNoPadding] = mFields[ct].name.length() + 1; // to include 0
+ mHal.state.fieldOffsetBytes[ctNoPadding] = mFields[ct].offsetBits >> 3;
+
+ ctNoPadding ++;
}
+ mHal.state.elementSizeBytes = getSizeBytes();
}
ObjectBaseRef<const Element> Element::createRef(Context *rsc, RsDataType dt, RsDataKind dk,
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 04010fa..4b6b460 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -24,10 +24,38 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
// An element is a group of Components that occupies one cell in a structure.
class Element : public ObjectBase {
public:
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ RsDataType dataType;
+ RsDataKind dataKind;
+ uint32_t vectorSize;
+ uint32_t elementSizeBytes;
+
+ // Subelements
+ const Element **fields;
+ uint32_t *fieldArraySizes;
+ const char **fieldNames;
+ uint32_t *fieldNameLengths;
+ uint32_t *fieldOffsetBytes;
+ uint32_t fieldsCount;
+ };
+ State state;
+ };
+ Hal mHal;
+
class Builder {
public:
Builder();
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/rsEnv.h
similarity index 100%
rename from libs/rs/RenderScriptEnv.h
rename to libs/rs/rsEnv.h
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
index 056b5af..baf81de5 100644
--- a/libs/rs/rsFileA3D.h
+++ b/libs/rs/rsFileA3D.h
@@ -17,11 +17,11 @@
#ifndef ANDROID_RS_FILE_A3D_H
#define ANDROID_RS_FILE_A3D_H
-#include "RenderScript.h"
+#include "rs.h"
#include "rsMesh.h"
+#include <androidfw/Asset.h>
#include <utils/String8.h>
-#include <utils/Asset.h>
#include "rsStream.h"
#include <stdio.h>
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 4f21b3b..c4276cf 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -490,8 +490,14 @@
shaderString.append(" gl_FragColor = col;\n");
shaderString.append("}\n");
- ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
- ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
+ const char *textureNames[] = { "Tex0" };
+ const size_t textureNamesLengths[] = { 4 };
+ size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
+
+ ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
+ RS_KIND_USER, false, 4);
+ ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
+ RS_KIND_USER, false, 1);
Element::Builder builder;
builder.add(colorElem.get(), "Color", 1);
builder.add(gammaElem.get(), "Gamma", 1);
@@ -506,14 +512,17 @@
tmp[3] = RS_TEXTURE_2D;
mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
- RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
- ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
- shaderString.length(), tmp, 4);
+ RS_ALLOCATION_USAGE_SCRIPT |
+ RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
+ ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
+ textureNames, numTextures, textureNamesLengths,
+ tmp, 4);
mFontShaderF.set(pf);
mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
- RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP).get());
+ RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
+ RS_SAMPLER_CLAMP).get());
mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
@@ -525,10 +534,12 @@
}
void FontState::initTextTexture() {
- ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
+ ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
+ RS_KIND_PIXEL_A, true, 1);
// We will allocate a texture to initially hold 32 character bitmaps
- ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), 1024, 256, 0, false, false);
+ ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
+ 1024, 256, 0, false, false);
Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 4ca794d..88c4795 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_RS_FONT_H
#define ANDROID_RS_FONT_H
-#include "RenderScript.h"
+#include "rs.h"
#include "rsStream.h"
#include <utils/String8.h>
#include <utils/Vector.h>
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 0fc73fb..8eea427 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -18,25 +18,23 @@
#define ANDROID_RS_MESH_H
-#include "RenderScript.h"
+#include "rs.h"
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
// An element is a group of Components that occupies one cell in a structure.
class Mesh : public ObjectBase {
public:
- Mesh(Context *);
- Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
- ~Mesh();
-
- virtual void serialize(OStream *stream) const;
- virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
- static Mesh *createFromStream(Context *rsc, IStream *stream);
- void init();
-
struct Hal {
mutable void *drv;
@@ -57,6 +55,15 @@
};
Hal mHal;
+ Mesh(Context *);
+ Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+ ~Mesh();
+
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
+ static Mesh *createFromStream(Context *rsc, IStream *stream);
+ void init();
+
void setVertexBuffer(Allocation *vb, uint32_t index) {
mVertexBuffers[index].set(vb);
mHal.state.vertexBuffers[index] = vb;
diff --git a/libs/rs/rsPath.cpp b/libs/rs/rsPath.cpp
new file mode 100644
index 0000000..c4f4978
--- /dev/null
+++ b/libs/rs/rsPath.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Path::Path(Context *rsc) : ObjectBase(rsc) {
+}
+
+Path::Path(Context *rsc, RsPathPrimitive pp, bool isStatic,
+ Allocation *vtx, Allocation *loops, float quality)
+: ObjectBase(rsc) {
+
+ memset(&mHal, 0, sizeof(mHal));
+ mHal.state.quality = quality;
+ mHal.state.primitive = pp;
+
+ //LOGE("i1");
+ rsc->mHal.funcs.path.initStatic(rsc, this, vtx, loops);
+
+ //LOGE("i2");
+}
+
+Path::Path(Context *rsc, uint32_t vertexBuffersCount, uint32_t primitivesCount)
+: ObjectBase(rsc) {
+
+}
+
+Path::~Path() {
+
+}
+
+
+void Path::rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc) {
+
+ for (uint32_t i=0; i < num; i++) {
+
+ }
+
+}
+
+void Path::render(Context *rsc) {
+}
+
+void Path::serialize(OStream *stream) const {
+
+}
+
+RsA3DClassID Path::getClassId() const {
+ return RS_A3D_CLASS_ID_UNKNOWN;
+}
+
+namespace android {
+namespace renderscript {
+
+RsPath rsi_PathCreate(Context *rsc, RsPathPrimitive pp, bool isStatic,
+ RsAllocation vtx, RsAllocation loops, float quality) {
+ return new Path(rsc, pp, isStatic, (Allocation *)vtx, (Allocation *)loops, quality);
+}
+
+}
+}
diff --git a/libs/rs/rsPath.h b/libs/rs/rsPath.h
new file mode 100644
index 0000000..7c05503
--- /dev/null
+++ b/libs/rs/rsPath.h
@@ -0,0 +1,69 @@
+/*
+ * 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 ANDROID_RS_PATH_H
+#define ANDROID_RS_PATH_H
+
+
+#include "rs.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Path : public ObjectBase {
+public:
+ struct {
+ mutable void * drv;
+
+ struct State {
+ RsPathPrimitive primitive;
+ float quality;
+ };
+ State state;
+ } mHal;
+
+ Path(Context *);
+ Path(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+ Path(Context *, RsPathPrimitive pp, bool isStatic, Allocation *vtx, Allocation *loop, float q);
+
+ ~Path();
+
+ void render(Context *);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const;
+
+private:
+
+
+ typedef struct {
+ float x[4];
+ float y[4];
+ } BezierSegment_t;
+
+ bool subdivideCheck(const BezierSegment_t *s, float u1, float u2);
+
+ void rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc);
+
+
+};
+
+}
+}
+#endif //ANDROID_RS_PATH_H
+
+
+
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 8061515..7114f29 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -20,8 +20,8 @@
using namespace android;
using namespace android::renderscript;
-Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
- const uint32_t * params, uint32_t paramLength)
+Program::Program(Context *rsc, const char * shaderText, size_t shaderLength,
+ const uint32_t * params, size_t paramLength)
: ProgramBase(rsc) {
initMemberVars();
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index 06fc3ec..d032930 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -58,8 +58,8 @@
};
Hal mHal;
- Program(Context *, const char * shaderText, uint32_t shaderLength,
- const uint32_t * params, uint32_t paramLength);
+ Program(Context *, const char * shaderText, size_t shaderLength,
+ const uint32_t * params, size_t paramLength);
virtual ~Program();
virtual bool freeChildren();
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 4e73ca6..bebde1e 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -20,16 +20,18 @@
using namespace android;
using namespace android::renderscript;
-ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText,
- uint32_t shaderLength, const uint32_t * params,
- uint32_t paramLength)
+ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, size_t shaderLength,
+ const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+
+ const uint32_t * params, size_t paramLength)
: Program(rsc, shaderText, shaderLength, params, paramLength) {
mConstantColor[0] = 1.f;
mConstantColor[1] = 1.f;
mConstantColor[2] = 1.f;
mConstantColor[3] = 1.f;
- mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length());
+ mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length(),
+ textureNames, textureNamesCount, textureNamesLength);
}
ProgramFragment::~ProgramFragment() {
@@ -110,8 +112,8 @@
Allocation *constAlloc = Allocation::createAllocation(rsc, inputType.get(),
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS);
- ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(),
- shaderString.length(), tmp, 2);
+ ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), shaderString.length(),
+ NULL, 0, NULL, tmp, 2);
pf->bindAllocation(rsc, constAlloc, 0);
pf->setConstantColor(rsc, 1.0f, 1.0f, 1.0f, 1.0f);
@@ -127,9 +129,14 @@
namespace renderscript {
RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, const char * shaderText,
- size_t shaderLength, const uint32_t * params,
- size_t paramLength) {
- ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength);
+ size_t shaderLength,
+ const char** textureNames,
+ size_t textureNamesCount,
+ const size_t *textureNamesLength,
+ const uint32_t * params, size_t paramLength) {
+ ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength,
+ textureNames, textureNamesCount, textureNamesLength,
+ params, paramLength);
pf->incUserRef();
//ALOGE("rsi_ProgramFragmentCreate %p", pf);
return pf;
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index d6e20cd..4eb28e7 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -27,9 +27,9 @@
class ProgramFragment : public Program {
public:
- ProgramFragment(Context *rsc, const char * shaderText,
- uint32_t shaderLength, const uint32_t * params,
- uint32_t paramLength);
+ ProgramFragment(Context *rsc, const char * shaderText, size_t shaderLength,
+ const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+ const uint32_t * params, size_t paramLength);
virtual ~ProgramFragment();
virtual void setup(Context *, ProgramFragmentState *);
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 871caac..c8a53ea 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -21,11 +21,13 @@
using namespace android::renderscript;
-ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText,
- uint32_t shaderLength, const uint32_t * params,
- uint32_t paramLength)
+ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, size_t shaderLength,
+ const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+
+ const uint32_t * params, size_t paramLength)
: Program(rsc, shaderText, shaderLength, params, paramLength) {
- mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length());
+ mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length(),
+ textureNames, textureNamesCount, textureNamesLength);
}
ProgramVertex::~ProgramVertex() {
@@ -191,8 +193,8 @@
tmp[2] = RS_PROGRAM_PARAM_INPUT;
tmp[3] = (uint32_t)attrElem.get();
- ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(),
- shaderString.length(), tmp, 4);
+ ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), shaderString.length(),
+ NULL, 0, NULL, tmp, 4);
Allocation *alloc = Allocation::createAllocation(rsc, inputType.get(),
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS);
pv->bindAllocation(rsc, alloc, 0);
@@ -229,10 +231,13 @@
namespace android {
namespace renderscript {
-RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText,
- size_t shaderLength, const uint32_t * params,
- size_t paramLength) {
- ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength, params, paramLength);
+RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, size_t shaderLength,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength,
+ const uint32_t * params, size_t paramLength) {
+ ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength,
+ textureNames, textureNamesCount, textureNamesLength,
+ params, paramLength);
pv->incUserRef();
return pv;
}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 5cfdd8b..67c2a88 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -27,8 +27,9 @@
class ProgramVertex : public Program {
public:
- ProgramVertex(Context *,const char * shaderText, uint32_t shaderLength,
- const uint32_t * params, uint32_t paramLength);
+ ProgramVertex(Context *,const char * shaderText, size_t shaderLength,
+ const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+ const uint32_t * params, size_t paramLength);
virtual ~ProgramVertex();
virtual void setup(Context *rsc, ProgramVertexState *state);
diff --git a/libs/rs/rsRuntime.h b/libs/rs/rsRuntime.h
index cb962a8..3bded62 100644
--- a/libs/rs/rsRuntime.h
+++ b/libs/rs/rsRuntime.h
@@ -30,6 +30,8 @@
//////////////////////////////////////////////////////////////////////////////
void rsrBindTexture(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramVertex*, uint32_t slot, Allocation *);
void rsrBindSampler(Context *, Script *, ProgramFragment *, uint32_t slot, Sampler *);
void rsrBindProgramStore(Context *, Script *, ProgramStore *);
void rsrBindProgramFragment(Context *, Script *, ProgramFragment *);
@@ -68,6 +70,7 @@
void rsrDrawSpriteScreenspace(Context *, Script *,
float x, float y, float z, float w, float h);
void rsrDrawRect(Context *, Script *, float x1, float y1, float x2, float y2, float z);
+void rsrDrawPath(Context *, Script *, Path *);
void rsrDrawMesh(Context *, Script *, Mesh *);
void rsrDrawMeshPrimitive(Context *, Script *, Mesh *, uint32_t primIndex);
void rsrDrawMeshPrimitiveRange(Context *, Script *, Mesh *,
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index 654cd9c..013e4ca 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -18,7 +18,7 @@
#define ANDROID_RS_SAMPLER_H
#include "rsAllocation.h"
-#include "RenderScript.h"
+#include "rs.h"
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index c65a5bf..fc4df51 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -19,7 +19,7 @@
#include "rsScript.h"
-#include "RenderScriptEnv.h"
+#include "rsEnv.h"
#ifndef ANDROID_RS_SERIALIZE
#include "bcinfo/BitcodeTranslator.h"
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 7964792..97469d3 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -50,6 +50,18 @@
pf->bindTexture(rsc, slot, a);
}
+void rsrBindConstant(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Allocation *a) {
+ CHECK_OBJ_OR_NULL(a);
+ CHECK_OBJ(pf);
+ pf->bindAllocation(rsc, a, slot);
+}
+
+void rsrBindConstant(Context *rsc, Script *sc, ProgramVertex *pv, uint32_t slot, Allocation *a) {
+ CHECK_OBJ_OR_NULL(a);
+ CHECK_OBJ(pv);
+ pv->bindAllocation(rsc, a, slot);
+}
+
void rsrBindSampler(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Sampler *s) {
CHECK_OBJ_OR_NULL(vs);
CHECK_OBJ(vpf);
@@ -200,6 +212,14 @@
rsrDrawQuad(rsc, sc, x1, y2, z, x2, y2, z, x2, y1, z, x1, y1, z);
}
+void rsrDrawPath(Context *rsc, Script *sc, Path *sm) {
+ CHECK_OBJ(sm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->render(rsc);
+}
+
void rsrDrawMesh(Context *rsc, Script *sc, Mesh *sm) {
CHECK_OBJ(sm);
if (!rsc->setupCheck()) {
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 8e4b988..7182f53 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -31,6 +31,8 @@
ThreadIO::ThreadIO() {
mRunning = true;
+ mPureFifo = false;
+ mMaxInlineSize = 1024;
}
ThreadIO::~ThreadIO() {
@@ -65,6 +67,16 @@
mToClient.shutdown();
}
+void ThreadIO::coreWrite(const void *data, size_t len) {
+ //ALOGV("core write %p %i", data, (int)len);
+ mToCore.writeAsync(data, len, true);
+}
+
+void ThreadIO::coreRead(void *data, size_t len) {
+ //ALOGV("core read %p %i", data, (int)len);
+ mToCore.read(data, len);
+}
+
void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
uint32_t buf;
if (data == NULL) {
@@ -89,8 +101,9 @@
//mToCore.setTimeoutCallback(cb, dat, timeout);
}
-bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, int waitFd) {
+bool ThreadIO::playCoreCommands(Context *con, int waitFd) {
bool ret = false;
+ const bool isLocal = !isPureFifo();
uint8_t buf[2 * 1024];
const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
@@ -120,26 +133,35 @@
}
if (p[0].revents) {
- size_t r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
- mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
-
- if (r != sizeof(CoreCmdHeader)) {
- // exception or timeout occurred.
- break;
+ size_t r = 0;
+ if (isLocal) {
+ r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
+ mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
+ if (r != sizeof(CoreCmdHeader)) {
+ // exception or timeout occurred.
+ break;
+ }
+ } else {
+ r = mToCore.read((void *)&cmd->cmdID, sizeof(cmd->cmdID));
}
+
ret = true;
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_INTERNAL);
}
- waitForCommand = false;
//ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);
if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
}
- gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
+
+ if (isLocal) {
+ gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
+ } else {
+ gPlaybackRemoteFuncs[cmd->cmdID](con, this);
+ }
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_IDLE);
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index d56a1c9..cb7d4ab 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -34,16 +34,31 @@
void init();
void shutdown();
+ size_t getMaxInlineSize() {
+ return mMaxInlineSize;
+ }
+ bool isPureFifo() {
+ return mPureFifo;
+ }
+
// Plays back commands from the client.
// Returns true if any commands were processed.
- bool playCoreCommands(Context *con, bool waitForCommand, int waitFd);
+ bool playCoreCommands(Context *con, int waitFd);
void setTimeoutCallback(void (*)(void *), void *, uint64_t timeout);
void * coreHeader(uint32_t, size_t dataLen);
void coreCommit();
+
void coreSetReturn(const void *data, size_t dataLen);
void coreGetReturn(void *data, size_t dataLen);
+ void coreWrite(const void *data, size_t len);
+ void coreRead(void *data, size_t len);
+
+ void asyncSetReturn(const void *data, size_t dataLen);
+ void asyncGetReturn(void *data, size_t dataLen);
+ void asyncWrite(const void *data, size_t len);
+ void asyncRead(void *data, size_t len);
RsMessageToClientType getClientHeader(size_t *receiveLen, uint32_t *usrID);
@@ -65,6 +80,8 @@
ClientCmdHeader mLastClientHeader;
bool mRunning;
+ bool mPureFifo;
+ size_t mMaxInlineSize;
FifoSocket mToClient;
FifoSocket mToCore;
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 7966470..70ab7b7 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -46,12 +46,8 @@
delete [] mLODs;
mLODs = NULL;
}
- mDimX = 0;
- mDimY = 0;
- mDimZ = 0;
- mDimLOD = 0;
- mFaces = false;
mElement.clear();
+ memset(&mHal, 0, sizeof(mHal));
}
TypeState::TypeState() {
@@ -62,16 +58,16 @@
}
size_t Type::getOffsetForFace(uint32_t face) const {
- rsAssert(mFaces);
+ rsAssert(mHal.state.faces);
return 0;
}
void Type::compute() {
uint32_t oldLODCount = mLODCount;
- if (mDimLOD) {
- uint32_t l2x = rsFindHighBit(mDimX) + 1;
- uint32_t l2y = rsFindHighBit(mDimY) + 1;
- uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+ if (mHal.state.dimLOD) {
+ uint32_t l2x = rsFindHighBit(mHal.state.dimX) + 1;
+ uint32_t l2y = rsFindHighBit(mHal.state.dimY) + 1;
+ uint32_t l2z = rsFindHighBit(mHal.state.dimZ) + 1;
mLODCount = rsMax(l2x, l2y);
mLODCount = rsMax(mLODCount, l2z);
@@ -85,9 +81,9 @@
mLODs = new LOD[mLODCount];
}
- uint32_t tx = mDimX;
- uint32_t ty = mDimY;
- uint32_t tz = mDimZ;
+ uint32_t tx = mHal.state.dimX;
+ uint32_t ty = mHal.state.dimY;
+ uint32_t tz = mHal.state.dimZ;
size_t offset = 0;
for (uint32_t lod=0; lod < mLODCount; lod++) {
mLODs[lod].mX = tx;
@@ -103,10 +99,11 @@
// At this point the offset is the size of a mipmap chain;
mMipChainSizeBytes = offset;
- if (mFaces) {
+ if (mHal.state.faces) {
offset *= 6;
}
mTotalSizeBytes = offset;
+ mHal.state.element = mElement.get();
}
uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const {
@@ -127,7 +124,8 @@
return offset;
}
-uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const {
+uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+ uint32_t x, uint32_t y) const {
uint32_t offset = mLODs[lod].mOffset;
offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
@@ -141,7 +139,12 @@
void Type::dumpLOGV(const char *prefix) const {
char buf[1024];
ObjectBase::dumpLOGV(prefix);
- ALOGV("%s Type: x=%zu y=%zu z=%zu mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces);
+ ALOGV("%s Type: x=%u y=%u z=%u mip=%i face=%i", prefix,
+ mHal.state.dimX,
+ mHal.state.dimY,
+ mHal.state.dimZ,
+ mHal.state.dimLOD,
+ mHal.state.faces);
snprintf(buf, sizeof(buf), "%s element: ", prefix);
mElement->dumpLOGV(buf);
}
@@ -155,12 +158,12 @@
mElement->serialize(stream);
- stream->addU32(mDimX);
- stream->addU32(mDimY);
- stream->addU32(mDimZ);
+ stream->addU32(mHal.state.dimX);
+ stream->addU32(mHal.state.dimY);
+ stream->addU32(mHal.state.dimZ);
- stream->addU8((uint8_t)(mDimLOD ? 1 : 0));
- stream->addU8((uint8_t)(mFaces ? 1 : 0));
+ stream->addU8((uint8_t)(mHal.state.dimLOD ? 1 : 0));
+ stream->addU8((uint8_t)(mHal.state.faces ? 1 : 0));
}
Type *Type::createFromStream(Context *rsc, IStream *stream) {
@@ -232,11 +235,11 @@
Type *nt = new Type(rsc);
returnRef.set(nt);
nt->mElement.set(e);
- nt->mDimX = dimX;
- nt->mDimY = dimY;
- nt->mDimZ = dimZ;
- nt->mDimLOD = dimLOD;
- nt->mFaces = dimFaces;
+ nt->mHal.state.dimX = dimX;
+ nt->mHal.state.dimY = dimY;
+ nt->mHal.state.dimZ = dimZ;
+ nt->mHal.state.dimLOD = dimLOD;
+ nt->mHal.state.faces = dimFaces;
nt->compute();
ObjectBase::asyncLock();
@@ -248,14 +251,14 @@
ObjectBaseRef<Type> Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const {
return getTypeRef(rsc, mElement.get(), dimX,
- mDimY, mDimZ, mDimLOD, mFaces);
+ mHal.state.dimY, mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
}
ObjectBaseRef<Type> Type::cloneAndResize2D(Context *rsc,
uint32_t dimX,
uint32_t dimY) const {
return getTypeRef(rsc, mElement.get(), dimX, dimY,
- mDimZ, mDimLOD, mFaces);
+ mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
}
@@ -276,8 +279,8 @@
void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) {
rsAssert(typeDataSize == 6);
- // Pack the data in the follofing way mDimX; mDimY; mDimZ;
- // mDimLOD; mDimFaces; mElement; into typeData
+ // Pack the data in the follofing way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
+ // mHal.state.dimLOD; mHal.state.faces; mElement; into typeData
Type *t = static_cast<Type *>(type);
(*typeData++) = t->getDimX();
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index bc0d9ff..3878156 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -22,10 +22,35 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
class Type : public ObjectBase {
public:
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ const Element * element;
+
+ // Size of the structure in the various dimensions. A missing Dimension is
+ // specified as a 0 and not a 1.
+ uint32_t dimX;
+ uint32_t dimY;
+ uint32_t dimZ;
+ bool dimLOD;
+ bool faces;
+ };
+ State state;
+ };
+ Hal mHal;
+
Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
size_t getOffsetForFace(uint32_t face) const;
@@ -34,22 +59,25 @@
size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
const Element * getElement() const {return mElement.get();}
- uint32_t getDimX() const {return mDimX;}
- uint32_t getDimY() const {return mDimY;}
- uint32_t getDimZ() const {return mDimZ;}
- uint32_t getDimLOD() const {return mDimLOD;}
- bool getDimFaces() const {return mFaces;}
+ uint32_t getDimX() const {return mHal.state.dimX;}
+ uint32_t getDimY() const {return mHal.state.dimY;}
+ uint32_t getDimZ() const {return mHal.state.dimZ;}
+ uint32_t getDimLOD() const {return mHal.state.dimLOD;}
+ bool getDimFaces() const {return mHal.state.faces;}
uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
- uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+ uint32_t getLODOffset(uint32_t lod) const {
+ rsAssert(lod < mLODCount); return mLODs[lod].mOffset;
+ }
uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
- uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const;
+ uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+ uint32_t x, uint32_t y) const;
uint32_t getLODCount() const {return mLODCount;}
bool getIsNp2() const;
@@ -95,14 +123,6 @@
ObjectBaseRef<const Element> mElement;
- // Size of the structure in the various dimensions. A missing Dimension is
- // specified as a 0 and not a 1.
- size_t mDimX;
- size_t mDimY;
- size_t mDimZ;
- bool mDimLOD;
- bool mFaces;
-
// count of mipmap levels, 0 indicates no mipmapping
size_t mMipChainSizeBytes;
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
index db6f592..a9a992a 100644
--- a/libs/rs/rsUtils.h
+++ b/libs/rs/rsUtils.h
@@ -34,7 +34,7 @@
#include <math.h>
-#include "RenderScript.h"
+#include "rs.h"
namespace android {
namespace renderscript {
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index b8d7351..e4bf17f 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -17,7 +17,9 @@
#ifndef RS_HAL_H
#define RS_HAL_H
-#include <RenderScriptDefines.h>
+#include <rsDefines.h>
+
+struct ANativeWindow;
namespace android {
namespace renderscript {
@@ -29,6 +31,7 @@
class Allocation;
class Script;
class ScriptC;
+class Path;
class Program;
class ProgramStore;
class ProgramRaster;
@@ -115,17 +118,22 @@
void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src);
void (*markDirty)(const Context *rsc, const Allocation *alloc);
+ int32_t (*initSurfaceTexture)(const Context *rsc, const Allocation *alloc);
+ void (*setSurfaceTexture)(const Context *rsc, Allocation *alloc, ANativeWindow *sur);
+ void (*ioSend)(const Context *rsc, Allocation *alloc);
+ void (*ioReceive)(const Context *rsc, Allocation *alloc);
+
void (*data1D)(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t lod, uint32_t count,
- const void *data, uint32_t sizeBytes);
+ const void *data, size_t sizeBytes);
void (*data2D)(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t yoff, uint32_t lod,
RsAllocationCubemapFace face, uint32_t w, uint32_t h,
- const void *data, uint32_t sizeBytes);
+ const void *data, size_t sizeBytes);
void (*data3D)(const Context *rsc, const Allocation *alloc,
uint32_t xoff, uint32_t yoff, uint32_t zoff,
uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes);
+ uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes);
// Allocation to allocation copies
void (*allocData1D)(const Context *rsc,
@@ -149,9 +157,9 @@
uint32_t srcLod, RsAllocationCubemapFace srcFace);
void (*elementData1D)(const Context *rsc, const Allocation *alloc, uint32_t x,
- const void *data, uint32_t elementOff, uint32_t sizeBytes);
+ const void *data, uint32_t elementOff, size_t sizeBytes);
void (*elementData2D)(const Context *rsc, const Allocation *alloc, uint32_t x, uint32_t y,
- const void *data, uint32_t elementOff, uint32_t sizeBytes);
+ const void *data, uint32_t elementOff, size_t sizeBytes);
} allocation;
@@ -170,14 +178,18 @@
struct {
bool (*init)(const Context *rsc, const ProgramVertex *pv,
- const char* shader, uint32_t shaderLen);
+ const char* shader, size_t shaderLen,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
void (*setActive)(const Context *rsc, const ProgramVertex *pv);
void (*destroy)(const Context *rsc, const ProgramVertex *pv);
} vertex;
struct {
bool (*init)(const Context *rsc, const ProgramFragment *pf,
- const char* shader, uint32_t shaderLen);
+ const char* shader, size_t shaderLen,
+ const char** textureNames, size_t textureNamesCount,
+ const size_t *textureNamesLength);
void (*setActive)(const Context *rsc, const ProgramFragment *pf);
void (*destroy)(const Context *rsc, const ProgramFragment *pf);
} fragment;
@@ -189,6 +201,13 @@
} mesh;
struct {
+ bool (*initStatic)(const Context *rsc, const Path *m, const Allocation *vtx, const Allocation *loops);
+ bool (*initDynamic)(const Context *rsc, const Path *m);
+ void (*draw)(const Context *rsc, const Path *m);
+ void (*destroy)(const Context *rsc, const Path *m);
+ } path;
+
+ struct {
bool (*init)(const Context *rsc, const Sampler *m);
void (*destroy)(const Context *rsc, const Sampler *m);
} sampler;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 385c8b5..99c305e 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -238,7 +238,7 @@
//fprintf(f, " ALOGE(\"add command %s\\n\");\n", api->name);
if (hasInlineDataPointers(api)) {
fprintf(f, " RS_CMD_%s *cmd = NULL;\n", api->name);
- fprintf(f, " if (dataSize < 1024) {;\n");
+ fprintf(f, " if (dataSize < io->getMaxInlineSize()) {;\n");
fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name);
fprintf(f, " } else {\n");
fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name);
@@ -252,7 +252,7 @@
const VarType *vt = &api->params[ct2];
needFlush += vt->ptrLevel;
if (vt->ptrLevel && hasInlineDataPointers(api)) {
- fprintf(f, " if (dataSize < 1024) {\n");
+ fprintf(f, " if (dataSize < io->getMaxInlineSize()) {\n");
fprintf(f, " memcpy(payload, %s, %s_length);\n", vt->name, vt->name);
fprintf(f, " cmd->%s = (", vt->name);
printVarType(f, vt);
@@ -272,7 +272,7 @@
fprintf(f, " io->coreCommit();\n");
if (hasInlineDataPointers(api)) {
- fprintf(f, " if (dataSize >= 1024) {\n");
+ fprintf(f, " if (dataSize >= io->getMaxInlineSize()) {\n");
fprintf(f, " io->coreGetReturn(NULL, 0);\n");
fprintf(f, " }\n");
} else if (api->ret.typeName[0]) {
@@ -288,81 +288,71 @@
fprintf(f, "};\n\n");
+ // Generate a remote sender function
+ const char * str = "core";
+ if (api->direct) {
+ str = "async";
+ }
+
fprintf(f, "static ");
printFuncDecl(f, api, "RF_", 0, 0);
fprintf(f, "\n{\n");
- fprintf(f, " Fifo *f = NULL;\n");
- fprintf(f, " RS_CMD_%s cmd;\n", api->name);
- fprintf(f, " const uint32_t cmdSize = sizeof(cmd);\n");
+ fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\n");
fprintf(f, " const uint32_t cmdID = RS_CMD_ID_%s;\n", api->name);
- fprintf(f, " f->writeAsync(&cmdID, sizeof(cmdID));\n");
- fprintf(f, " intptr_t offset = cmdSize;\n");
- fprintf(f, " uint32_t dataSize = 0;\n");
+ fprintf(f, " io->%sWrite(&cmdID, sizeof(cmdID));\n\n", str);
+
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
- if (vt->isConst && vt->ptrLevel) {
- switch(vt->ptrLevel) {
- case 1:
- fprintf(f, " dataSize += %s_length;\n", vt->name);
- break;
- case 2:
- fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " dataSize += %s_length[ct];\n", vt->name);
- fprintf(f, " }\n");
- break;
- default:
- printf("pointer level not handled!!");
- }
+ if (vt->ptrLevel == 0) {
+ fprintf(f, " io->%sWrite(& %s, sizeof(%s));\n", str, vt->name, vt->name);
}
}
fprintf(f, "\n");
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
- switch(vt->ptrLevel) {
- case 0:
- fprintf(f, " cmd.%s = %s;\n", vt->name, vt->name);
- break;
- case 1:
- fprintf(f, " cmd.%s = (", vt->name);
- printVarType(f, vt);
- fprintf(f, ")offset;\n");
- fprintf(f, " offset += %s_length;\n", vt->name);
- break;
- case 2:
- fprintf(f, " cmd.%s = (", vt->name);
- printVarType(f, vt);
- fprintf(f, ")offset;\n");
- fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " offset += %s_length[ct];\n", vt->name);
- fprintf(f, " }\n");
- break;
- default:
- fprintf(stderr, "pointer level not handled!!");
+ if ((vt->ptrLevel == 1) && (vt->isConst)) {
+ fprintf(f, " io->%sWrite(%s, %s_length);\n", str, vt->name, vt->name);
}
}
fprintf(f, "\n");
- fprintf(f, " f->writeAsync(&cmd, cmdSize);\n");
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
- if (vt->ptrLevel == 1) {
- fprintf(f, " f->writeAsync(%s, %s_length);\n", vt->name, vt->name);
- }
- if (vt->ptrLevel == 2) {
+ if ((vt->ptrLevel == 2) && (vt->isConst)) {
fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " f->writeAsync(%s, %s_length[ct]);\n", vt->name, vt->name);
- fprintf(f, " offset += %s_length[ct];\n", vt->name);
+ fprintf(f, " io->%sWrite(%s[ct], %s_length[ct]);\n", str, vt->name, vt->name);
fprintf(f, " }\n");
}
}
+ fprintf(f, "\n");
+
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if ((vt->ptrLevel == 1) && (!vt->isConst)) {
+ fprintf(f, " io->%sGetReturn(%s, %s_length);\n", str, vt->name, vt->name);
+ }
+ }
+ fprintf(f, "\n");
+
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if ((vt->ptrLevel == 2) && (!vt->isConst)) {
+ fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
+ fprintf(f, " io->%sGetReturn(%s[ct], %s_length[ct]);\n", str, vt->name, vt->name);
+ fprintf(f, " }\n");
+ }
+ }
+ fprintf(f, "\n");
if (api->ret.typeName[0]) {
fprintf(f, " ");
printVarType(f, &api->ret);
fprintf(f, " retValue;\n");
- fprintf(f, " f->writeWaitReturn(&retValue, sizeof(retValue));\n");
+ fprintf(f, " io->%sGetReturn(&retValue, sizeof(retValue));\n", str);
fprintf(f, " return retValue;\n");
+ } else /*if (api->sync)*/ {
+ fprintf(f, " io->%sGetReturn(NULL, 0);\n", str);
}
fprintf(f, "}\n\n");
}
@@ -418,7 +408,6 @@
fprintf(f, "#include \"rsDevice.h\"\n");
fprintf(f, "#include \"rsContext.h\"\n");
fprintf(f, "#include \"rsThreadIO.h\"\n");
- //fprintf(f, "#include \"rsgApiStructs.h\"\n");
fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
fprintf(f, "\n");
fprintf(f, "namespace android {\n");
@@ -434,8 +423,6 @@
}
fprintf(f, "void rsp_%s(Context *con, const void *vp, size_t cmdSizeBytes) {\n", api->name);
-
- //fprintf(f, " ALOGE(\"play command %s\\n\");\n", api->name);
fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
if (hasInlineDataPointers(api)) {
@@ -488,30 +475,40 @@
const ApiEntry * api = &apis[ct];
int needFlush = 0;
- fprintf(f, "void rspr_%s(Context *con, Fifo *f, uint8_t *scratch, size_t scratchSize) {\n", api->name);
-
- //fprintf(f, " ALOGE(\"play command %s\\n\");\n", api->name);
+ fprintf(f, "void rspr_%s(Context *con, ThreadIO *io) {\n", api->name);
fprintf(f, " RS_CMD_%s cmd;\n", api->name);
- fprintf(f, " f->read(&cmd, sizeof(cmd));\n");
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
- needFlush += vt->ptrLevel;
+ if (vt->ptrLevel == 0) {
+ fprintf(f, " io->coreRead(&cmd.%s, sizeof(cmd.%s));\n", vt->name, vt->name);
+ }
+ }
+ fprintf(f, "\n");
+
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
if (vt->ptrLevel == 1) {
fprintf(f, " cmd.%s = (", vt->name);
printVarType(f, vt);
- fprintf(f, ")scratch;\n");
- fprintf(f, " f->read(scratch, cmd.%s_length);\n", vt->name);
- fprintf(f, " scratch += cmd.%s_length;\n", vt->name);
+ fprintf(f, ")malloc(cmd.%s_length);\n", vt->name);
+
+ if (vt->isConst) {
+ fprintf(f, " if (cmd.%s_length) io->coreRead((void *)cmd.%s, cmd.%s_length);\n", vt->name, vt->name, vt->name);
+ }
}
+ }
+ fprintf(f, "\n");
+
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
if (vt->ptrLevel == 2) {
- fprintf(f, " size_t sum_%s = 0;\n", vt->name);
fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " ((size_t *)scratch)[ct] = cmd.%s_length[ct];\n", vt->name);
- fprintf(f, " sum_%s += cmd.%s_length[ct];\n", vt->name, vt->name);
+ fprintf(f, " cmd.%s = (", vt->name);
+ printVarType(f, vt);
+ fprintf(f, ")malloc(cmd.%s_length[ct]);\n", vt->name);
+ fprintf(f, " io->coreRead(& cmd.%s, cmd.%s_length[ct]);\n", vt->name, vt->name);
fprintf(f, " }\n");
- fprintf(f, " f->read(scratch, sum_%s);\n", vt->name);
- fprintf(f, " scratch += sum_%s;\n", vt->name);
}
}
fprintf(f, "\n");
@@ -535,10 +532,42 @@
}
fprintf(f, ");\n");
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if ((vt->ptrLevel == 1) && (!vt->isConst)) {
+ fprintf(f, " io->coreSetReturn((void *)cmd.%s, cmd.%s_length);\n", vt->name, vt->name);
+ }
+ }
+
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if ((vt->ptrLevel == 2) && (!vt->isConst)) {
+ fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name);
+ fprintf(f, " io->coreSetReturn((void *)cmd.%s[ct], cmd.%s_length[ct]);\n", vt->name, vt->name);
+ fprintf(f, " }\n");
+ }
+ }
+ fprintf(f, "\n");
+
if (api->ret.typeName[0]) {
- fprintf(f, " f->readReturn(&ret, sizeof(ret));\n");
- } else if (needFlush) {
- fprintf(f, " f->readReturn(NULL, 0);\n");
+ fprintf(f, " io->coreSetReturn(&ret, sizeof(ret));\n");
+ } else /*if (needFlush)*/ {
+ fprintf(f, " io->coreSetReturn(NULL, 0);\n");
+ }
+
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if (vt->ptrLevel == 1) {
+ fprintf(f, " free((void *)cmd.%s);\n", vt->name);
+ }
+ }
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if (vt->ptrLevel == 2) {
+ fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name);
+ fprintf(f, " free((void *)cmd.%s);\n", vt->name);
+ fprintf(f, " }\n");
+ }
}
fprintf(f, "};\n\n");
@@ -608,7 +637,7 @@
fprintf(f, " uint32_t size;\n");
fprintf(f, "} RsPlaybackRemoteHeader;\n\n");
fprintf(f, "typedef void (*RsPlaybackLocalFunc)(Context *, const void *, size_t sizeBytes);\n");
- fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, Fifo *, uint8_t *scratch, size_t scratchSize);\n");
+ fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, ThreadIO *);\n");
fprintf(f, "extern RsPlaybackLocalFunc gPlaybackFuncs[%i];\n", apiCount + 1);
fprintf(f, "extern RsPlaybackRemoteFunc gPlaybackRemoteFuncs[%i];\n", apiCount + 1);
diff --git a/libs/rs/scriptc/rs_allocation.rsh b/libs/rs/scriptc/rs_allocation.rsh
index 9ec03bf..a2f69d9 100644
--- a/libs/rs/scriptc/rs_allocation.rsh
+++ b/libs/rs/scriptc/rs_allocation.rsh
@@ -168,5 +168,135 @@
extern const void * __attribute__((overloadable))
rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z);
+/**
+ * @param a allocation to get data from
+ * @return element describing allocation layout
+ */
+extern rs_element __attribute__((overloadable))
+ rsAllocationGetElement(rs_allocation a);
+
+/**
+ * @param m mesh to get data from
+ * @return number of allocations in the mesh that contain vertex
+ * data
+ */
+extern uint32_t __attribute__((overloadable))
+ rsMeshGetVertexAllocationCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @return number of primitive groups in the mesh. This would
+ * include simple primitives as well as allocations
+ * containing index data
+ */
+extern uint32_t __attribute__((overloadable))
+ rsMeshGetPrimitiveCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the vertex allocation
+ * @return allocation containing vertex data
+ */
+extern rs_allocation __attribute__((overloadable))
+ rsMeshGetVertexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the index allocation
+ * @return allocation containing index data
+ */
+extern rs_allocation __attribute__((overloadable))
+ rsMeshGetIndexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the primitive
+ * @return primitive describing how the mesh is rendered
+ */
+extern rs_primitive __attribute__((overloadable))
+ rsMeshGetPrimitive(rs_mesh m, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return number of sub-elements in this element
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementCount(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return sub-element in this element at given index
+ */
+extern rs_element __attribute__((overloadable))
+ rsElementGetSubElement(rs_element, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return length of the sub-element name including the null
+ * terminator (size of buffer needed to write the name)
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementNameLength(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @param name array to store the name into
+ * @param nameLength length of the provided name array
+ * @return number of characters actually written, excluding the
+ * null terminator
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return array size of sub-element in this element at given
+ * index
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementArraySize(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return offset in bytes of sub-element in this element at
+ * given index
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return total size of the element in bytes
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSizeBytes(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data type
+ */
+extern rs_data_type __attribute__((overloadable))
+ rsElementGetDataType(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data size
+ */
+extern rs_data_kind __attribute__((overloadable))
+ rsElementGetDataKind(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return length of the element vector (for float2, float3,
+ * etc.)
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetVectorSize(rs_element e);
+
#endif
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 2581953..7fdebdc 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -22,6 +22,66 @@
*/
#ifndef __RS_GRAPHICS_RSH__
#define __RS_GRAPHICS_RSH__
+
+// These are API 15 once it get official
+typedef enum {
+ RS_DEPTH_FUNC_ALWAYS,
+ RS_DEPTH_FUNC_LESS,
+ RS_DEPTH_FUNC_LEQUAL,
+ RS_DEPTH_FUNC_GREATER,
+ RS_DEPTH_FUNC_GEQUAL,
+ RS_DEPTH_FUNC_EQUAL,
+ RS_DEPTH_FUNC_NOTEQUAL,
+
+ RS_DEPTH_FUNC_INVALID = 100,
+} rs_depth_func;
+
+typedef enum {
+ RS_BLEND_SRC_ZERO, // 0
+ RS_BLEND_SRC_ONE, // 1
+ RS_BLEND_SRC_DST_COLOR, // 2
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3
+ RS_BLEND_SRC_SRC_ALPHA, // 4
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_SRC_DST_ALPHA, // 6
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE, // 8
+
+ RS_BLEND_SRC_INVALID = 100,
+} rs_blend_src_func;
+
+typedef enum {
+ RS_BLEND_DST_ZERO, // 0
+ RS_BLEND_DST_ONE, // 1
+ RS_BLEND_DST_SRC_COLOR, // 2
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3
+ RS_BLEND_DST_SRC_ALPHA, // 4
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_DST_DST_ALPHA, // 6
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA, // 7
+
+ RS_BLEND_DST_INVALID = 100,
+} rs_blend_dst_func;
+
+typedef enum {
+ RS_CULL_BACK,
+ RS_CULL_FRONT,
+ RS_CULL_NONE,
+
+ RS_CULL_INVALID = 100,
+} rs_cull_mode;
+
+typedef enum {
+ RS_SAMPLER_NEAREST,
+ RS_SAMPLER_LINEAR,
+ RS_SAMPLER_LINEAR_MIP_LINEAR,
+ RS_SAMPLER_WRAP,
+ RS_SAMPLER_CLAMP,
+ RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+ RS_SAMPLER_INVALID = 100,
+} rs_sampler_value;
+
#if (defined(RS_VERSION) && (RS_VERSION >= 14))
/**
* Set the color target used for all subsequent rendering calls
@@ -82,6 +142,88 @@
extern void __attribute__((overloadable))
rsgBindProgramStore(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+ rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+
/**
* Bind a new ProgramVertex to the rendering context.
*
@@ -99,6 +241,24 @@
rsgBindProgramRaster(rs_program_raster pr);
/**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+ rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+/**
* Bind a new Sampler object to a ProgramFragment. The sampler will
* operate on the texture bound at the matching slot.
*
@@ -108,6 +268,51 @@
rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
/**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+ rsgSamplerGetAnisotropy(rs_sampler s);
+
+/**
* Bind a new Allocation object to a ProgramFragment. The
* Allocation must be a valid texture for the Program. The sampling
* of the texture will be controled by the Sampler bound at the
@@ -164,6 +369,28 @@
rsgProgramFragmentConstantColor(rs_program_fragment pf, float r, float g, float b, float a);
/**
+ * Bind a new Allocation object to a ProgramFragment. The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param ps program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+ rsgBindConstant(rs_program_fragment ps, uint slot, rs_allocation c);
+
+/**
+ * Bind a new Allocation object to a ProgramVertex. The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param pv program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+ rsgBindConstant(rs_program_vertex pv, uint slot, rs_allocation c);
+
+/**
* Get the width of the current rendering surface.
*
* @return uint
@@ -288,6 +515,9 @@
extern void __attribute__((overloadable))
rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h);
+extern void __attribute__((overloadable))
+ rsgDrawPath(rs_path p);
+
/**
* Draw a mesh using the current context state. The whole mesh is
* rendered.
diff --git a/libs/rs/scriptc/rs_object.rsh b/libs/rs/scriptc/rs_object.rsh
index a431219..1fc3f83 100644
--- a/libs/rs/scriptc/rs_object.rsh
+++ b/libs/rs/scriptc/rs_object.rsh
@@ -56,6 +56,11 @@
* \overload
*/
extern void __attribute__((overloadable))
+ rsSetObject(rs_path *dst, rs_path src);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
rsSetObject(rs_mesh *dst, rs_mesh src);
/**
* \overload
@@ -114,6 +119,11 @@
* \overload
*/
extern void __attribute__((overloadable))
+ rsClearObject(rs_path *dst);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
rsClearObject(rs_mesh *dst);
/**
* \overload
@@ -175,6 +185,11 @@
* \overload
*/
extern bool __attribute__((overloadable))
+ rsIsObject(rs_path);
+/**
+ * \overload
+ */
+extern bool __attribute__((overloadable))
rsIsObject(rs_mesh);
/**
* \overload
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 84bca9c..5345a48 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -138,6 +138,12 @@
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
/**
+ * \brief Opaque handle to a Renderscript Path object.
+ *
+ * See: android.renderscript.Path
+ */
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_path;
+/**
* \brief Opaque handle to a Renderscript ProgramFragment object.
*
* See: android.renderscript.ProgramFragment
@@ -396,4 +402,96 @@
#endif //defined(RS_VERSION) && (RS_VERSION >= 14)
+/**
+ * Describes the way mesh vertex data is interpreted when rendering
+ *
+ **/
+typedef enum {
+ RS_PRIMITIVE_POINT,
+ RS_PRIMITIVE_LINE,
+ RS_PRIMITIVE_LINE_STRIP,
+ RS_PRIMITIVE_TRIANGLE,
+ RS_PRIMITIVE_TRIANGLE_STRIP,
+ RS_PRIMITIVE_TRIANGLE_FAN,
+
+ RS_PRIMITIVE_INVALID = 100,
+} rs_primitive;
+
+/**
+ * \brief Enumeration for possible element data types
+ *
+ * DataType represents the basic type information for a basic element. The
+ * naming convention follows. For numeric types it is FLOAT,
+ * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ * size of the data. BOOLEAN is a true / false (1,0)
+ * represented in an 8 bit container. The UNSIGNED variants
+ * with multiple bit definitions are for packed graphical data
+ * formats and represent vectors with per vector member sizes
+ * which are treated as a single unit for packing and alignment
+ * purposes.
+ *
+ * MATRIX the three matrix types contain FLOAT_32 elements and are treated
+ * as 32 bits for alignment purposes.
+ *
+ * RS_* objects. 32 bit opaque handles.
+ */
+typedef enum {
+ RS_TYPE_NONE,
+ //RS_TYPE_FLOAT_16,
+ RS_TYPE_FLOAT_32 = 2,
+ RS_TYPE_FLOAT_64,
+ RS_TYPE_SIGNED_8,
+ RS_TYPE_SIGNED_16,
+ RS_TYPE_SIGNED_32,
+ RS_TYPE_SIGNED_64,
+ RS_TYPE_UNSIGNED_8,
+ RS_TYPE_UNSIGNED_16,
+ RS_TYPE_UNSIGNED_32,
+ RS_TYPE_UNSIGNED_64,
+
+ RS_TYPE_BOOLEAN,
+
+ RS_TYPE_UNSIGNED_5_6_5,
+ RS_TYPE_UNSIGNED_5_5_5_1,
+ RS_TYPE_UNSIGNED_4_4_4_4,
+
+ RS_TYPE_MATRIX_4X4,
+ RS_TYPE_MATRIX_3X3,
+ RS_TYPE_MATRIX_2X2,
+
+ RS_TYPE_ELEMENT = 1000,
+ RS_TYPE_TYPE,
+ RS_TYPE_ALLOCATION,
+ RS_TYPE_SAMPLER,
+ RS_TYPE_SCRIPT,
+ RS_TYPE_MESH,
+ RS_TYPE_PROGRAM_FRAGMENT,
+ RS_TYPE_PROGRAM_VERTEX,
+ RS_TYPE_PROGRAM_RASTER,
+ RS_TYPE_PROGRAM_STORE,
+
+ RS_TYPE_INVALID = 10000,
+} rs_data_type;
+
+/**
+ * \brief Enumeration for possible element data kind
+ *
+ * The special interpretation of the data if required. This is primarly
+ * useful for graphical data. USER indicates no special interpretation is
+ * expected. PIXEL is used in conjunction with the standard data types for
+ * representing texture formats.
+ */
+typedef enum {
+ RS_KIND_USER,
+
+ RS_KIND_PIXEL_L = 7,
+ RS_KIND_PIXEL_A,
+ RS_KIND_PIXEL_LA,
+ RS_KIND_PIXEL_RGB,
+ RS_KIND_PIXEL_RGBA,
+ RS_KIND_PIXEL_DEPTH,
+
+ RS_KIND_INVALID = 100,
+} rs_data_kind;
+
#endif
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 263c8d9..ca09caf 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -24,7 +24,7 @@
#include <unistd.h>
#include <ctype.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <math.h>
#include <limits.h>
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 09cbb31..1ebd75c 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -7,325 +7,203 @@
//#define LOG_NDEBUG 0
-// Log debug messages about channel signalling (send signal, receive signal)
-#define DEBUG_CHANNEL_SIGNALS 0
+// Log debug messages about channel messages (send message, receive message)
+#define DEBUG_CHANNEL_MESSAGES 0
// Log debug messages whenever InputChannel objects are created/destroyed
#define DEBUG_CHANNEL_LIFECYCLE 0
-// Log debug messages about transport actions (initialize, reset, publish, ...)
+// Log debug messages about transport actions
#define DEBUG_TRANSPORT_ACTIONS 0
-#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/mman.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
namespace android {
-#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
-#define MIN_HISTORY_DEPTH 20
+// Socket buffer size. The default is typically about 128KB, which is much larger than
+// we really need. So we make it smaller. It just needs to be big enough to hold
+// a few dozen large multi-finger motion events in the case where an application gets
+// behind processing touches.
+static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
-// Must be at least sizeof(InputMessage) + sufficient space for pointer data
-static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
- sizeof(InputMessage) + MIN_HISTORY_DEPTH
- * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
- 4096);
-// Signal sent by the producer to the consumer to inform it that a new message is
-// available to be consumed in the shared memory buffer.
-static const char INPUT_SIGNAL_DISPATCH = 'D';
+// --- InputMessage ---
-// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message and it handled it.
-static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
+bool InputMessage::isValid(size_t actualSize) const {
+ if (size() == actualSize) {
+ switch (header.type) {
+ case TYPE_KEY:
+ return true;
+ case TYPE_MOTION:
+ return body.motion.pointerCount > 0
+ && body.motion.pointerCount <= MAX_POINTERS;
+ case TYPE_FINISHED:
+ return true;
+ }
+ }
+ return false;
+}
-// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message but it did not handle it.
-static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
+size_t InputMessage::size() const {
+ switch (header.type) {
+ case TYPE_KEY:
+ return sizeof(Header) + body.key.size();
+ case TYPE_MOTION:
+ return sizeof(Header) + body.motion.size();
+ case TYPE_FINISHED:
+ return sizeof(Header) + body.finished.size();
+ }
+ return sizeof(Header);
+}
// --- InputChannel ---
-InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
- int32_t sendPipeFd) :
- mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
+InputChannel::InputChannel(const String8& name, int fd) :
+ mName(name), mFd(fd) {
#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
- mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
+ ALOGD("Input channel constructed: name='%s', fd=%d",
+ mName.string(), fd);
#endif
- int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
- "non-blocking. errno=%d", mName.string(), errno);
-
- result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
+ int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
+ LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
"non-blocking. errno=%d", mName.string(), errno);
}
InputChannel::~InputChannel() {
#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
- mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
+ ALOGD("Input channel destroyed: name='%s', fd=%d",
+ mName.string(), mFd);
#endif
- ::close(mAshmemFd);
- ::close(mReceivePipeFd);
- ::close(mSendPipeFd);
+ ::close(mFd);
}
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
- status_t result;
-
- String8 ashmemName("InputChannel ");
- ashmemName.append(name);
- int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
- if (serverAshmemFd < 0) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
+ int sockets[2];
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
+ status_t result = -errno;
+ ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.string(), errno);
- } else {
- result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
- if (result < 0) {
- ALOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
- name.string(), result, serverAshmemFd);
- } else {
- // Dup the file descriptor because the server and client input channel objects that
- // are returned may have different lifetimes but they share the same shared memory region.
- int clientAshmemFd;
- clientAshmemFd = dup(serverAshmemFd);
- if (clientAshmemFd < 0) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
- name.string(), errno);
- } else {
- int forward[2];
- if (pipe(forward)) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not create forward pipe. errno=%d",
- name.string(), errno);
- } else {
- int reverse[2];
- if (pipe(reverse)) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not create reverse pipe. errno=%d",
- name.string(), errno);
- } else {
- String8 serverChannelName = name;
- serverChannelName.append(" (server)");
- outServerChannel = new InputChannel(serverChannelName,
- serverAshmemFd, reverse[0], forward[1]);
-
- String8 clientChannelName = name;
- clientChannelName.append(" (client)");
- outClientChannel = new InputChannel(clientChannelName,
- clientAshmemFd, forward[0], reverse[1]);
- return OK;
- }
- ::close(forward[0]);
- ::close(forward[1]);
- }
- ::close(clientAshmemFd);
- }
- }
- ::close(serverAshmemFd);
+ outServerChannel.clear();
+ outClientChannel.clear();
+ return result;
}
- outServerChannel.clear();
- outClientChannel.clear();
- return result;
+ int bufferSize = SOCKET_BUFFER_SIZE;
+ setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
+ setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
+ setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
+ setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
+
+ String8 serverChannelName = name;
+ serverChannelName.append(" (server)");
+ outServerChannel = new InputChannel(serverChannelName, sockets[0]);
+
+ String8 clientChannelName = name;
+ clientChannelName.append(" (client)");
+ outClientChannel = new InputChannel(clientChannelName, sockets[1]);
+ return OK;
}
-status_t InputChannel::sendSignal(char signal) {
+status_t InputChannel::sendMessage(const InputMessage* msg) {
+ size_t msgLength = msg->size();
ssize_t nWrite;
do {
- nWrite = ::write(mSendPipeFd, & signal, 1);
+ nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
- if (nWrite == 1) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
+ if (nWrite < 0) {
+ int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
+ msg->header.type, error);
#endif
- return OK;
+ if (error == EAGAIN || error == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+ if (error == EPIPE || error == ENOTCONN) {
+ return DEAD_OBJECT;
+ }
+ return -error;
}
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
-#endif
- return -errno;
-}
-
-status_t InputChannel::receiveSignal(char* outSignal) {
- ssize_t nRead;
- do {
- nRead = ::read(mReceivePipeFd, outSignal, 1);
- } while (nRead == -1 && errno == EINTR);
-
- if (nRead == 1) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
-#endif
- return OK;
- }
-
- if (nRead == 0) { // check for EOF
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
+ if (size_t(nWrite) != msgLength) {
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
+ mName.string(), msg->header.type);
#endif
return DEAD_OBJECT;
}
- if (errno == EAGAIN) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
#endif
- return WOULD_BLOCK;
+ return OK;
+}
+
+status_t InputChannel::receiveMessage(InputMessage* msg) {
+ ssize_t nRead;
+ do {
+ nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
+ } while (nRead == -1 && errno == EINTR);
+
+ if (nRead < 0) {
+ int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
+#endif
+ if (error == EAGAIN || error == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+ if (error == EPIPE || error == ENOTCONN) {
+ return DEAD_OBJECT;
+ }
+ return -error;
}
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
+ if (nRead == 0) { // check for EOF
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
#endif
- return -errno;
+ return DEAD_OBJECT;
+ }
+
+ if (!msg->isValid(nRead)) {
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ received invalid message", mName.string());
+#endif
+ return BAD_VALUE;
+ }
+
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
+#endif
+ return OK;
}
// --- InputPublisher ---
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
- mChannel(channel), mSharedMessage(NULL),
- mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
- mMotionEventSampleDataTail(NULL) {
+ mChannel(channel) {
}
InputPublisher::~InputPublisher() {
- reset();
-
- if (mSharedMessage) {
- munmap(mSharedMessage, mAshmemSize);
- }
-}
-
-status_t InputPublisher::initialize() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ initialize",
- mChannel->getName().string());
-#endif
-
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_get_size_region(ashmemFd);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
- mAshmemSize = (size_t) result;
-
- mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
- if (! mSharedMessage) {
- ALOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
- mChannel->getName().string(), ashmemFd);
- return NO_MEMORY;
- }
-
- mPinned = true;
- mSharedMessage->consumed = false;
-
- return reset();
-}
-
-status_t InputPublisher::reset() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ reset",
- mChannel->getName().string());
-#endif
-
- if (mPinned) {
- // Destroy the semaphore since we are about to unpin the memory region that contains it.
- int result;
- if (mSemaphoreInitialized) {
- if (mSharedMessage->consumed) {
- result = sem_post(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
- }
-
- result = sem_destroy(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
-
- mSemaphoreInitialized = false;
- }
-
- // Unpin the region since we no longer care about its contents.
- int ashmemFd = mChannel->getAshmemFd();
- result = ashmem_unpin_region(ashmemFd, 0, 0);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
-
- mPinned = false;
- }
-
- mMotionEventSampleDataTail = NULL;
- mWasDispatched = false;
- return OK;
-}
-
-status_t InputPublisher::publishInputEvent(
- int32_t type,
- int32_t deviceId,
- int32_t source) {
- if (mPinned) {
- ALOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
- "not yet been reset.", mChannel->getName().string());
- return INVALID_OPERATION;
- }
-
- // Pin the region.
- // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
- // contents of the buffer so it does not matter whether it was purged in the meantime.
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_pin_region(ashmemFd, 0, 0);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
-
- mPinned = true;
-
- result = sem_init(& mSharedMessage->semaphore, 1, 1);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_init.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
-
- mSemaphoreInitialized = true;
-
- mSharedMessage->consumed = false;
- mSharedMessage->type = type;
- mSharedMessage->deviceId = deviceId;
- mSharedMessage->source = source;
- return OK;
}
status_t InputPublisher::publishKeyEvent(
+ uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
@@ -337,31 +215,37 @@
nsecs_t downTime,
nsecs_t eventTime) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
+ ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%lld, eventTime=%lld",
- mChannel->getName().string(),
+ mChannel->getName().string(), seq,
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
downTime, eventTime);
#endif
- status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
- if (result < 0) {
- return result;
+ if (!seq) {
+ ALOGE("Attempted to publish a key event with sequence number 0.");
+ return BAD_VALUE;
}
- mSharedMessage->key.action = action;
- mSharedMessage->key.flags = flags;
- mSharedMessage->key.keyCode = keyCode;
- mSharedMessage->key.scanCode = scanCode;
- mSharedMessage->key.metaState = metaState;
- mSharedMessage->key.repeatCount = repeatCount;
- mSharedMessage->key.downTime = downTime;
- mSharedMessage->key.eventTime = eventTime;
- return OK;
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_KEY;
+ msg.body.key.seq = seq;
+ msg.body.key.deviceId = deviceId;
+ msg.body.key.source = source;
+ msg.body.key.action = action;
+ msg.body.key.flags = flags;
+ msg.body.key.keyCode = keyCode;
+ msg.body.key.scanCode = scanCode;
+ msg.body.key.metaState = metaState;
+ msg.body.key.repeatCount = repeatCount;
+ msg.body.key.downTime = downTime;
+ msg.body.key.eventTime = eventTime;
+ return mChannel->sendMessage(&msg);
}
status_t InputPublisher::publishMotionEvent(
+ uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
@@ -379,349 +263,349 @@
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
+ ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
"xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
"pointerCount=%d",
- mChannel->getName().string(),
+ mChannel->getName().string(), seq,
deviceId, source, action, flags, edgeFlags, metaState, buttonState,
xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
+ if (!seq) {
+ ALOGE("Attempted to publish a motion event with sequence number 0.");
+ return BAD_VALUE;
+ }
+
if (pointerCount > MAX_POINTERS || pointerCount < 1) {
ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
mChannel->getName().string(), pointerCount);
return BAD_VALUE;
}
- status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
- if (result < 0) {
- return result;
- }
-
- mSharedMessage->motion.action = action;
- mSharedMessage->motion.flags = flags;
- mSharedMessage->motion.edgeFlags = edgeFlags;
- mSharedMessage->motion.metaState = metaState;
- mSharedMessage->motion.buttonState = buttonState;
- mSharedMessage->motion.xOffset = xOffset;
- mSharedMessage->motion.yOffset = yOffset;
- mSharedMessage->motion.xPrecision = xPrecision;
- mSharedMessage->motion.yPrecision = yPrecision;
- mSharedMessage->motion.downTime = downTime;
- mSharedMessage->motion.pointerCount = pointerCount;
-
- mSharedMessage->motion.sampleCount = 1;
- mSharedMessage->motion.sampleData[0].eventTime = eventTime;
-
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_MOTION;
+ msg.body.motion.seq = seq;
+ msg.body.motion.deviceId = deviceId;
+ msg.body.motion.source = source;
+ msg.body.motion.action = action;
+ msg.body.motion.flags = flags;
+ msg.body.motion.edgeFlags = edgeFlags;
+ msg.body.motion.metaState = metaState;
+ msg.body.motion.buttonState = buttonState;
+ msg.body.motion.xOffset = xOffset;
+ msg.body.motion.yOffset = yOffset;
+ msg.body.motion.xPrecision = xPrecision;
+ msg.body.motion.yPrecision = yPrecision;
+ msg.body.motion.downTime = downTime;
+ msg.body.motion.eventTime = eventTime;
+ msg.body.motion.pointerCount = pointerCount;
for (size_t i = 0; i < pointerCount; i++) {
- mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
- mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
+ msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
+ msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
-
- // Cache essential information about the motion event to ensure that a malicious consumer
- // cannot confuse the publisher by modifying the contents of the shared memory buffer while
- // it is being updated.
- if (action == AMOTION_EVENT_ACTION_MOVE
- || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- mMotionEventPointerCount = pointerCount;
- mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
- mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
- mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
- } else {
- mMotionEventSampleDataTail = NULL;
- }
- return OK;
+ return mChannel->sendMessage(&msg);
}
-status_t InputPublisher::appendMotionSample(
- nsecs_t eventTime,
- const PointerCoords* pointerCoords) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
- mChannel->getName().string(), eventTime);
-#endif
-
- if (! mPinned || ! mMotionEventSampleDataTail) {
- ALOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
- "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
- mChannel->getName().string());
- return INVALID_OPERATION;
- }
-
- InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
- mMotionEventSampleDataTail, mMotionEventSampleDataStride);
- size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
- reinterpret_cast<char*>(mSharedMessage);
-
- if (newBytesUsed > mAshmemSize) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
- "buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
- mChannel->getName().string(),
- mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
-#endif
- return NO_MEMORY;
- }
-
- int result;
- if (mWasDispatched) {
- result = sem_trywait(& mSharedMessage->semaphore);
- if (result < 0) {
- if (errno == EAGAIN) {
- // Only possible source of contention is the consumer having consumed (or being in the
- // process of consuming) the message and left the semaphore count at 0.
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
- "already been consumed.", mChannel->getName().string());
-#endif
- return FAILED_TRANSACTION;
- } else {
- ALOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
- }
- }
-
- mMotionEventSampleDataTail->eventTime = eventTime;
- for (size_t i = 0; i < mMotionEventPointerCount; i++) {
- mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
- }
- mMotionEventSampleDataTail = newTail;
-
- mSharedMessage->motion.sampleCount += 1;
-
- if (mWasDispatched) {
- result = sem_post(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
- }
- return OK;
-}
-
-status_t InputPublisher::sendDispatchSignal() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ sendDispatchSignal",
- mChannel->getName().string());
-#endif
-
- mWasDispatched = true;
- return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
-}
-
-status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
+status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
mChannel->getName().string());
#endif
- char signal;
- status_t result = mChannel->receiveSignal(& signal);
+ InputMessage msg;
+ status_t result = mChannel->receiveMessage(&msg);
if (result) {
+ *outSeq = 0;
*outHandled = false;
return result;
}
- if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
- *outHandled = true;
- } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
- *outHandled = false;
- } else {
- ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
- mChannel->getName().string(), signal);
+ if (msg.header.type != InputMessage::TYPE_FINISHED) {
+ ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
+ mChannel->getName().string(), msg.header.type);
return UNKNOWN_ERROR;
}
+ *outSeq = msg.body.finished.seq;
+ *outHandled = msg.body.finished.handled;
return OK;
}
// --- InputConsumer ---
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
- mChannel(channel), mSharedMessage(NULL) {
+ mChannel(channel), mMsgDeferred(false) {
}
InputConsumer::~InputConsumer() {
- if (mSharedMessage) {
- munmap(mSharedMessage, mAshmemSize);
- }
}
-status_t InputConsumer::initialize() {
+status_t InputConsumer::consume(InputEventFactoryInterface* factory,
+ bool consumeBatches, uint32_t* outSeq, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ initialize",
- mChannel->getName().string());
+ ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s",
+ mChannel->getName().string(), consumeBatches ? "true" : "false");
#endif
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_get_size_region(ashmemFd);
- if (result < 0) {
- ALOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
-
- mAshmemSize = (size_t) result;
-
- mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
- if (! mSharedMessage) {
- ALOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
- mChannel->getName().string(), ashmemFd);
- return NO_MEMORY;
- }
-
- return OK;
-}
-
-status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consume",
- mChannel->getName().string());
-#endif
-
+ *outSeq = 0;
*outEvent = NULL;
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_pin_region(ashmemFd, 0, 0);
- if (result != ASHMEM_NOT_PURGED) {
- if (result == ASHMEM_WAS_PURGED) {
- ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
- "which probably indicates that the publisher and consumer are out of sync.",
- mChannel->getName().string(), result, ashmemFd);
- return INVALID_OPERATION;
+ // Fetch the next input message.
+ // Loop until an event can be returned or no additional events are received.
+ while (!*outEvent) {
+ if (mMsgDeferred) {
+ // mMsg contains a valid input message from the previous call to consume
+ // that has not yet been processed.
+ mMsgDeferred = false;
+ } else {
+ // Receive a fresh message.
+ status_t result = mChannel->receiveMessage(&mMsg);
+ if (result) {
+ // Consume the next batched event unless batches are being held for later.
+ if (!mBatches.isEmpty() && (consumeBatches || result != WOULD_BLOCK)) {
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
+
+ const Batch& batch = mBatches.top();
+ motionEvent->copyFrom(&batch.event, true /*keepHistory*/);
+ *outSeq = batch.seq;
+ *outEvent = motionEvent;
+ mBatches.pop();
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
+ return result;
+ }
}
- ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
+ switch (mMsg.header.type) {
+ case InputMessage::TYPE_KEY: {
+ KeyEvent* keyEvent = factory->createKeyEvent();
+ if (!keyEvent) return NO_MEMORY;
- if (mSharedMessage->consumed) {
- ALOGE("channel '%s' consumer ~ The current message has already been consumed.",
- mChannel->getName().string());
- return INVALID_OPERATION;
- }
-
- // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
- // to the publisher that the message has been consumed (or is in the process of being
- // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
- result = sem_wait(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' consumer ~ Error %d in sem_wait.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
-
- mSharedMessage->consumed = true;
-
- switch (mSharedMessage->type) {
- case AINPUT_EVENT_TYPE_KEY: {
- KeyEvent* keyEvent = factory->createKeyEvent();
- if (! keyEvent) return NO_MEMORY;
-
- populateKeyEvent(keyEvent);
-
- *outEvent = keyEvent;
- break;
- }
-
- case AINPUT_EVENT_TYPE_MOTION: {
- MotionEvent* motionEvent = factory->createMotionEvent();
- if (! motionEvent) return NO_MEMORY;
-
- populateMotionEvent(motionEvent);
-
- *outEvent = motionEvent;
- break;
- }
-
- default:
- ALOGE("channel '%s' consumer ~ Received message of unknown type %d",
- mChannel->getName().string(), mSharedMessage->type);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t InputConsumer::sendFinishedSignal(bool handled) {
+ initializeKeyEvent(keyEvent, &mMsg);
+ *outSeq = mMsg.body.key.seq;
+ *outEvent = keyEvent;
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
- mChannel->getName().string(), handled);
+ ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
+ mChannel->getName().string(), *outSeq);
#endif
+ break;
+ }
- return mChannel->sendSignal(handled
- ? INPUT_SIGNAL_FINISHED_HANDLED
- : INPUT_SIGNAL_FINISHED_UNHANDLED);
-}
+ case AINPUT_EVENT_TYPE_MOTION: {
+ ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
+ if (batchIndex >= 0) {
+ Batch& batch = mBatches.editItemAt(batchIndex);
+ if (canAppendSamples(&batch.event, &mMsg)) {
+ // Append to the batch and save the new sequence number for the tail end.
+ uint32_t chain = batch.seq;
+ appendSamples(&batch.event, &mMsg);
+ batch.seq = mMsg.body.motion.seq;
-status_t InputConsumer::receiveDispatchSignal() {
+ // Update the sequence number chain.
+ SeqChain seqChain;
+ seqChain.seq = batch.seq;
+ seqChain.chain = chain;
+ mSeqChains.push(seqChain);
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ receiveDispatchSignal",
- mChannel->getName().string());
+ ALOGD("channel '%s' consumer ~ appended to batch event",
+ mChannel->getName().string());
#endif
+ break;
+ } else {
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
- char signal;
- status_t result = mChannel->receiveSignal(& signal);
- if (result) {
- return result;
- }
- if (signal != INPUT_SIGNAL_DISPATCH) {
- ALOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
- mChannel->getName().string(), signal);
- return UNKNOWN_ERROR;
+ // We cannot append to the batch in progress, so we need to consume
+ // the previous batch right now and defer the new message until later.
+ mMsgDeferred = true;
+
+ // Return the end of the previous batch.
+ motionEvent->copyFrom(&batch.event, true /*keepHistory*/);
+ *outSeq = batch.seq;
+ *outEvent = motionEvent;
+ mBatches.removeAt(batchIndex);
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed batch event and "
+ "deferred current event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
+ }
+
+ // Start a new batch if needed.
+ if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
+ || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ mBatches.push();
+ Batch& batch = mBatches.editTop();
+ batch.seq = mMsg.body.motion.seq;
+ initializeMotionEvent(&batch.event, &mMsg);
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ started batch event",
+ mChannel->getName().string());
+#endif
+ break;
+ }
+
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
+
+ initializeMotionEvent(motionEvent, &mMsg);
+ *outSeq = mMsg.body.motion.seq;
+ *outEvent = motionEvent;
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
+
+ default:
+ ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
+ mChannel->getName().string(), mMsg.header.type);
+ return UNKNOWN_ERROR;
+ }
}
return OK;
}
-void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
- keyEvent->initialize(
- mSharedMessage->deviceId,
- mSharedMessage->source,
- mSharedMessage->key.action,
- mSharedMessage->key.flags,
- mSharedMessage->key.keyCode,
- mSharedMessage->key.scanCode,
- mSharedMessage->key.metaState,
- mSharedMessage->key.repeatCount,
- mSharedMessage->key.downTime,
- mSharedMessage->key.eventTime);
-}
+status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
+ mChannel->getName().string(), seq, handled ? "true" : "false");
+#endif
-void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
- motionEvent->initialize(
- mSharedMessage->deviceId,
- mSharedMessage->source,
- mSharedMessage->motion.action,
- mSharedMessage->motion.flags,
- mSharedMessage->motion.edgeFlags,
- mSharedMessage->motion.metaState,
- mSharedMessage->motion.buttonState,
- mSharedMessage->motion.xOffset,
- mSharedMessage->motion.yOffset,
- mSharedMessage->motion.xPrecision,
- mSharedMessage->motion.yPrecision,
- mSharedMessage->motion.downTime,
- mSharedMessage->motion.sampleData[0].eventTime,
- mSharedMessage->motion.pointerCount,
- mSharedMessage->motion.pointerProperties,
- mSharedMessage->motion.sampleData[0].coords);
+ if (!seq) {
+ ALOGE("Attempted to send a finished signal with sequence number 0.");
+ return BAD_VALUE;
+ }
- size_t sampleCount = mSharedMessage->motion.sampleCount;
- if (sampleCount > 1) {
- InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
- size_t sampleDataStride = InputMessage::sampleDataStride(
- mSharedMessage->motion.pointerCount);
-
- while (--sampleCount > 0) {
- sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
- motionEvent->addSample(sampleData->eventTime, sampleData->coords);
+ // Send finished signals for the batch sequence chain first.
+ size_t seqChainCount = mSeqChains.size();
+ if (seqChainCount) {
+ uint32_t currentSeq = seq;
+ uint32_t chainSeqs[seqChainCount];
+ size_t chainIndex = 0;
+ for (size_t i = seqChainCount; i-- > 0; ) {
+ const SeqChain& seqChain = mSeqChains.itemAt(i);
+ if (seqChain.seq == currentSeq) {
+ currentSeq = seqChain.chain;
+ chainSeqs[chainIndex++] = currentSeq;
+ mSeqChains.removeAt(i);
+ }
+ }
+ status_t status = OK;
+ while (!status && chainIndex-- > 0) {
+ status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
+ }
+ if (status) {
+ // An error occurred so at least one signal was not sent, reconstruct the chain.
+ do {
+ SeqChain seqChain;
+ seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
+ seqChain.chain = chainSeqs[chainIndex];
+ mSeqChains.push(seqChain);
+ } while (chainIndex-- > 0);
+ return status;
}
}
+
+ // Send finished signal for the last message in the batch.
+ return sendUnchainedFinishedSignal(seq, handled);
+}
+
+status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_FINISHED;
+ msg.body.finished.seq = seq;
+ msg.body.finished.handled = handled;
+ return mChannel->sendMessage(&msg);
+}
+
+bool InputConsumer::hasPendingBatch() const {
+ return !mBatches.isEmpty();
+}
+
+ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
+ for (size_t i = 0; i < mBatches.size(); i++) {
+ const Batch& batch = mBatches.itemAt(i);
+ if (batch.event.getDeviceId() == deviceId && batch.event.getSource() == source) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
+ event->initialize(
+ msg->body.key.deviceId,
+ msg->body.key.source,
+ msg->body.key.action,
+ msg->body.key.flags,
+ msg->body.key.keyCode,
+ msg->body.key.scanCode,
+ msg->body.key.metaState,
+ msg->body.key.repeatCount,
+ msg->body.key.downTime,
+ msg->body.key.eventTime);
+}
+
+void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
+ size_t pointerCount = msg->body.motion.pointerCount;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
+ pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+ }
+
+ event->initialize(
+ msg->body.motion.deviceId,
+ msg->body.motion.source,
+ msg->body.motion.action,
+ msg->body.motion.flags,
+ msg->body.motion.edgeFlags,
+ msg->body.motion.metaState,
+ msg->body.motion.buttonState,
+ msg->body.motion.xOffset,
+ msg->body.motion.yOffset,
+ msg->body.motion.xPrecision,
+ msg->body.motion.yPrecision,
+ msg->body.motion.downTime,
+ msg->body.motion.eventTime,
+ pointerCount,
+ pointerProperties,
+ pointerCoords);
+}
+
+bool InputConsumer::canAppendSamples(const MotionEvent* event, const InputMessage *msg) {
+ size_t pointerCount = msg->body.motion.pointerCount;
+ if (event->getPointerCount() != pointerCount
+ || event->getAction() != msg->body.motion.action) {
+ return false;
+ }
+ for (size_t i = 0; i < pointerCount; i++) {
+ if (*event->getPointerProperties(i) != msg->body.motion.pointers[i].properties) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void InputConsumer::appendSamples(MotionEvent* event, const InputMessage* msg) {
+ size_t pointerCount = msg->body.motion.pointerCount;
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+ }
+
+ event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
+ event->addSample(msg->body.motion.eventTime, pointerCoords);
}
} // namespace android
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
index 485234c..6984084 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -19,8 +19,8 @@
#include <stdlib.h>
#include <string.h>
#include <android/keycodes.h>
-#include <ui/Keyboard.h>
-#include <ui/KeyCharacterMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeyCharacterMap.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
index 44a9420..15d81ee 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -18,8 +18,8 @@
#include <stdlib.h>
#include <android/keycodes.h>
-#include <ui/Keyboard.h>
-#include <ui/KeyLayoutMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeyLayoutMap.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index e4611f7..e97a5eb 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -20,10 +20,10 @@
#include <unistd.h>
#include <limits.h>
-#include <ui/Keyboard.h>
-#include <ui/KeycodeLabels.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/KeyCharacterMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeycodeLabels.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/KeyCharacterMap.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <cutils/properties.h>
diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/ui/VirtualKeyMap.cpp
index 62d5b59..2ba1673 100644
--- a/libs/ui/VirtualKeyMap.cpp
+++ b/libs/ui/VirtualKeyMap.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
#include <string.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/VirtualKeyMap.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp
index eff22ee..0e5d19d 100644
--- a/libs/ui/tests/InputChannel_test.cpp
+++ b/libs/ui/tests/InputChannel_test.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include <utils/Timers.h>
#include <utils/StopWatch.h>
+#include <utils/StrongPointer.h>
#include <gtest/gtest.h>
#include <unistd.h>
#include <time.h>
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
+#include <errno.h>
#include "../../utils/tests/TestHelpers.h"
@@ -36,35 +36,24 @@
TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
// Our purpose here is to verify that the input channel destructor closes the
- // file descriptors provided to it. One easy way is to provide it with one end
+ // file descriptor provided to it. One easy way is to provide it with one end
// of a pipe and to check for EPIPE on the other end after the channel is destroyed.
- Pipe fakeAshmem, sendPipe, receivePipe;
+ Pipe pipe;
- sp<InputChannel> inputChannel = new InputChannel(String8("channel name"),
- fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd);
+ sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
EXPECT_STREQ("channel name", inputChannel->getName().string())
<< "channel should have provided name";
- EXPECT_EQ(fakeAshmem.sendFd, inputChannel->getAshmemFd())
- << "channel should have provided ashmem fd";
- EXPECT_EQ(receivePipe.receiveFd, inputChannel->getReceivePipeFd())
- << "channel should have provided receive pipe fd";
- EXPECT_EQ(sendPipe.sendFd, inputChannel->getSendPipeFd())
- << "channel should have provided send pipe fd";
+ EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
+ << "channel should have provided fd";
inputChannel.clear(); // destroys input channel
- EXPECT_EQ(-EPIPE, fakeAshmem.readSignal())
- << "channel should have closed ashmem fd when destroyed";
- EXPECT_EQ(-EPIPE, receivePipe.writeSignal())
- << "channel should have closed receive pipe fd when destroyed";
- EXPECT_EQ(-EPIPE, sendPipe.readSignal())
- << "channel should have closed send pipe fd when destroyed";
+ EXPECT_EQ(-EPIPE, pipe.readSignal())
+ << "channel should have closed fd when destroyed";
// clean up fds of Pipe endpoints that were closed so we don't try to close them again
- fakeAshmem.sendFd = -1;
- receivePipe.receiveFd = -1;
- sendPipe.sendFd = -1;
+ pipe.sendFd = -1;
}
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
@@ -82,43 +71,40 @@
EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
<< "client channel should have suffixed name";
- // Ashmem uniqueness
- EXPECT_NE(serverChannel->getAshmemFd(), clientChannel->getAshmemFd())
- << "server and client channel should have different ashmem fds because it was dup'd";
-
- // Ashmem usability
- ssize_t serverAshmemSize = ashmem_get_size_region(serverChannel->getAshmemFd());
- ssize_t clientAshmemSize = ashmem_get_size_region(clientChannel->getAshmemFd());
- uint32_t* serverAshmem = static_cast<uint32_t*>(mmap(NULL, serverAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, serverChannel->getAshmemFd(), 0));
- uint32_t* clientAshmem = static_cast<uint32_t*>(mmap(NULL, clientAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, clientChannel->getAshmemFd(), 0));
- ASSERT_TRUE(serverAshmem != NULL)
- << "server channel ashmem should be mappable";
- ASSERT_TRUE(clientAshmem != NULL)
- << "client channel ashmem should be mappable";
- *serverAshmem = 0xf00dd00d;
- EXPECT_EQ(0xf00dd00d, *clientAshmem)
- << "ashmem buffer should be shared by client and server";
- munmap(serverAshmem, serverAshmemSize);
- munmap(clientAshmem, clientAshmemSize);
-
// Server->Client communication
- EXPECT_EQ(OK, serverChannel->sendSignal('S'))
- << "server channel should be able to send signal to client channel";
- char signal;
- EXPECT_EQ(OK, clientChannel->receiveSignal(& signal))
- << "client channel should be able to receive signal from server channel";
- EXPECT_EQ('S', signal)
- << "client channel should receive the correct signal from server channel";
+ InputMessage serverMsg;
+ memset(&serverMsg, 0, sizeof(InputMessage));
+ serverMsg.header.type = InputMessage::TYPE_KEY;
+ serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
+ EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
+ << "server channel should be able to send message to client channel";
+
+ InputMessage clientMsg;
+ EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+ << "client channel should be able to receive message from server channel";
+ EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
+ << "client channel should receive the correct message from server channel";
+ EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
+ << "client channel should receive the correct message from server channel";
// Client->Server communication
- EXPECT_EQ(OK, clientChannel->sendSignal('c'))
- << "client channel should be able to send signal to server channel";
- EXPECT_EQ(OK, serverChannel->receiveSignal(& signal))
- << "server channel should be able to receive signal from client channel";
- EXPECT_EQ('c', signal)
- << "server channel should receive the correct signal from client channel";
+ InputMessage clientReply;
+ memset(&clientReply, 0, sizeof(InputMessage));
+ clientReply.header.type = InputMessage::TYPE_FINISHED;
+ clientReply.body.finished.seq = 0x11223344;
+ clientReply.body.finished.handled = true;
+ EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
+ << "client channel should be able to send message to server channel";
+
+ InputMessage serverReply;
+ EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply))
+ << "server channel should be able to receive message from client channel";
+ EXPECT_EQ(clientReply.header.type, serverReply.header.type)
+ << "server channel should receive the correct message from client channel";
+ EXPECT_EQ(clientReply.body.finished.seq, serverReply.body.finished.seq)
+ << "server channel should receive the correct message from client channel";
+ EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled)
+ << "server channel should receive the correct message from client channel";
}
TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
@@ -130,9 +116,9 @@
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
- char signal;
- EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveSignal(& signal))
- << "receiveSignal should have returned WOULD_BLOCK";
+ InputMessage msg;
+ EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
+ << "receiveMessage should have returned WOULD_BLOCK";
}
TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
@@ -146,9 +132,9 @@
serverChannel.clear(); // close server channel
- char signal;
- EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveSignal(& signal))
- << "receiveSignal should have returned DEAD_OBJECT";
+ InputMessage msg;
+ EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
+ << "receiveMessage should have returned DEAD_OBJECT";
}
TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
@@ -162,8 +148,10 @@
serverChannel.clear(); // close server channel
- EXPECT_EQ(DEAD_OBJECT, clientChannel->sendSignal('S'))
- << "sendSignal should have returned DEAD_OBJECT";
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_KEY;
+ EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
+ << "sendMessage should have returned DEAD_OBJECT";
}
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
index e21c464..ac5549c 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <gtest/gtest.h>
#include <binder/Parcel.h>
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index fcc4cad..bb45247 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
#include <utils/Timers.h>
#include <utils/StopWatch.h>
#include <gtest/gtest.h>
@@ -57,11 +57,8 @@
clientChannel.clear();
}
- void Initialize();
void PublishAndConsumeKeyEvent();
- void PublishAndConsumeMotionEvent(
- size_t samplesToAppendBeforeDispatch = 0,
- size_t samplesToAppendAfterDispatch = 0);
+ void PublishAndConsumeMotionEvent();
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -69,21 +66,10 @@
EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
}
-void InputPublisherAndConsumerTest::Initialize() {
- status_t status;
-
- status = mPublisher->initialize();
- ASSERT_EQ(OK, status)
- << "publisher initialize should return OK";
-
- status = mConsumer->initialize();
- ASSERT_EQ(OK, status)
- << "consumer initialize should return OK";
-}
-
void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
status_t status;
+ const uint32_t seq = 15;
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_KEYBOARD;
const int32_t action = AKEY_EVENT_ACTION_DOWN;
@@ -95,21 +81,14 @@
const nsecs_t downTime = 3;
const nsecs_t eventTime = 4;
- status = mPublisher->publishKeyEvent(deviceId, source, action, flags,
+ status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK";
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status)
- << "publisher sendDispatchSignal should return OK";
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status)
- << "consumer receiveDispatchSignal should return OK";
-
+ uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -119,6 +98,7 @@
<< "consumer should have returned a key event";
KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
+ EXPECT_EQ(seq, consumeSeq);
EXPECT_EQ(deviceId, keyEvent->getDeviceId());
EXPECT_EQ(source, keyEvent->getSource());
EXPECT_EQ(action, keyEvent->getAction());
@@ -130,26 +110,25 @@
EXPECT_EQ(downTime, keyEvent->getDownTime());
EXPECT_EQ(eventTime, keyEvent->getEventTime());
- status = mConsumer->sendFinishedSignal(true);
+ status = mConsumer->sendFinishedSignal(seq, true);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
+ uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&handled);
+ status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, finishedSeq)
+ << "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
-
- status = mPublisher->reset();
- ASSERT_EQ(OK, status)
- << "publisher reset should return OK";
}
-void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
- size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) {
+void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
status_t status;
+ const uint32_t seq = 15;
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
const int32_t action = AMOTION_EVENT_ACTION_MOVE;
@@ -163,67 +142,36 @@
const float yPrecision = 0.5;
const nsecs_t downTime = 3;
const size_t pointerCount = 3;
+ const nsecs_t eventTime = 4;
PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
for (size_t i = 0; i < pointerCount; i++) {
pointerProperties[i].clear();
pointerProperties[i].id = (i + 2) % pointerCount;
pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ pointerCoords[i].clear();
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
}
- Vector<nsecs_t> sampleEventTimes;
- Vector<PointerCoords> samplePointerCoords;
-
- for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) {
- sampleEventTimes.push(i + 10);
- for (size_t j = 0; j < pointerCount; j++) {
- samplePointerCoords.push();
- PointerCoords& pc = samplePointerCoords.editTop();
- pc.clear();
- pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i + j);
- }
- }
-
- status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
+ status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
- downTime, sampleEventTimes[0], pointerCount,
- pointerProperties, samplePointerCoords.array());
+ downTime, eventTime, pointerCount,
+ pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
- for (size_t i = 0; i < samplesToAppendBeforeDispatch; i++) {
- size_t sampleIndex = i + 1;
- status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
- samplePointerCoords.array() + sampleIndex * pointerCount);
- ASSERT_EQ(OK, status)
- << "publisher appendMotionEvent should return OK";
- }
-
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status)
- << "publisher sendDispatchSignal should return OK";
-
- for (size_t i = 0; i < samplesToAppendAfterDispatch; i++) {
- size_t sampleIndex = i + 1 + samplesToAppendBeforeDispatch;
- status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
- samplePointerCoords.array() + sampleIndex * pointerCount);
- ASSERT_EQ(OK, status)
- << "publisher appendMotionEvent should return OK";
- }
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status)
- << "consumer receiveDispatchSignal should return OK";
-
+ uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -232,9 +180,8 @@
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
<< "consumer should have returned a motion event";
- size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
-
MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
+ EXPECT_EQ(seq, consumeSeq);
EXPECT_EQ(deviceId, motionEvent->getDeviceId());
EXPECT_EQ(source, motionEvent->getSource());
EXPECT_EQ(action, motionEvent->getAction());
@@ -245,150 +192,69 @@
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(downTime, motionEvent->getDownTime());
- EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
+ EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
- EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize());
+ EXPECT_EQ(0U, motionEvent->getHistorySize());
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
- }
- for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
- SCOPED_TRACE(sampleIndex);
- EXPECT_EQ(sampleEventTimes[sampleIndex],
- motionEvent->getHistoricalEventTime(sampleIndex));
- for (size_t i = 0; i < pointerCount; i++) {
- SCOPED_TRACE(i);
- size_t offset = sampleIndex * pointerCount + i;
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
- motionEvent->getHistoricalRawX(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
- motionEvent->getHistoricalRawY(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
- motionEvent->getHistoricalX(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
- motionEvent->getHistoricalY(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- motionEvent->getHistoricalPressure(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- motionEvent->getHistoricalSize(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- motionEvent->getHistoricalTouchMajor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- motionEvent->getHistoricalTouchMinor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- motionEvent->getHistoricalToolMajor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- motionEvent->getHistoricalToolMinor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
- motionEvent->getHistoricalOrientation(i, sampleIndex));
- }
- }
-
- SCOPED_TRACE(lastSampleIndex);
- EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
- for (size_t i = 0; i < pointerCount; i++) {
- SCOPED_TRACE(i);
- size_t offset = lastSampleIndex * pointerCount + i;
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
motionEvent->getRawX(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
motionEvent->getRawY(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
motionEvent->getX(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
motionEvent->getY(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
motionEvent->getPressure(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
motionEvent->getSize(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
motionEvent->getTouchMajor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
motionEvent->getTouchMinor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
motionEvent->getToolMajor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
motionEvent->getToolMinor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
motionEvent->getOrientation(i));
}
- status = mConsumer->sendFinishedSignal(false);
+ status = mConsumer->sendFinishedSignal(seq, false);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
+ uint32_t finishedSeq = 0;
bool handled = true;
- status = mPublisher->receiveFinishedSignal(&handled);
+ status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, finishedSeq)
+ << "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_FALSE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
-
- status = mPublisher->reset();
- ASSERT_EQ(OK, status)
- << "publisher reset should return OK";
}
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
-TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_WhenNotReset_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ASSERT_EQ(OK, status)
- << "publisher publishKeyEvent should return OK first time";
-
- status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher publishKeyEvent should return INVALID_OPERATION because "
- "the publisher was not reset";
-}
-
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
}
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = 1;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status)
- << "publisher publishMotionEvent should return OK";
-
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher publishMotionEvent should return INVALID_OPERATION because ";
- "the publisher was not reset";
-}
-
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
const size_t pointerCount = 0;
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -396,8 +262,6 @@
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
const size_t pointerCount = MAX_POINTERS + 1;
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
@@ -406,14 +270,13 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
@@ -421,111 +284,4 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- PointerCoords pointerCoords[1];
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status);
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status);
-
- InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(status_t(FAILED_TRANSACTION), status)
- << "publisher appendMotionSample should return FAILED_TRANSACTION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- for (int count = 1;; count++) {
- ASSERT_LT(count, 100000) << "should eventually reach OOM";
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- if (status != OK) {
- ASSERT_GT(count, 12) << "should be able to add at least a dozen samples";
- ASSERT_EQ(NO_MEMORY, status)
- << "publisher appendMotionSample should return NO_MEMORY when buffer is full";
- break;
- }
- }
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(NO_MEMORY, status)
- << "publisher appendMotionSample should return NO_MEMORY persistently until reset";
-}
-
} // namespace android
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
index 50e701a..cb7628d 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/utils/Asset.cpp
@@ -21,23 +21,23 @@
#define LOG_TAG "asset"
//#define NDEBUG 0
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
+#include <androidfw/StreamingZipInflater.h>
+#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
#include <utils/Atomic.h>
#include <utils/FileMap.h>
-#include <utils/StreamingZipInflater.h>
-#include <utils/ZipUtils.h>
-#include <utils/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/threads.h>
-#include <string.h>
-#include <memory.h>
-#include <fcntl.h>
-#include <errno.h>
#include <assert.h>
-#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <unistd.h>
using namespace android;
diff --git a/libs/utils/AssetDir.cpp b/libs/utils/AssetDir.cpp
index c5f664e..475f521 100644
--- a/libs/utils/AssetDir.cpp
+++ b/libs/utils/AssetDir.cpp
@@ -19,7 +19,7 @@
// implementation is in the header file or in friend functions in
// AssetManager.
//
-#include <utils/AssetDir.h>
+#include <androidfw/AssetDir.h>
using namespace android;
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 47a2b99..4829add 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -21,23 +21,23 @@
#define LOG_TAG "asset"
//#define LOG_NDEBUG 0
-#include <utils/AssetManager.h>
-#include <utils/AssetDir.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetDir.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <androidfw/ZipFileRO.h>
#include <utils/Atomic.h>
-#include <utils/String8.h>
-#include <utils/ResourceTypes.h>
-#include <utils/String8.h>
-#include <utils/ZipFileRO.h>
#include <utils/Log.h>
-#include <utils/Timers.h>
+#include <utils/String8.h>
+#include <utils/String8.h>
#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <assert.h>
#include <dirent.h>
#include <errno.h>
-#include <assert.h>
-#include <strings.h>
#include <fcntl.h>
+#include <strings.h>
#include <sys/stat.h>
#include <unistd.h>
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index f956306..7b1bcba 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "backup_data"
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
#include <utils/ByteOrder.h>
#include <stdio.h>
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index f77a891..7a817a7 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "file_backup_helper"
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
#include <utils/KeyedVector.h>
#include <utils/ByteOrder.h>
@@ -546,7 +546,7 @@
// read/write up to this much at a time.
const size_t BUFSIZE = 32 * 1024;
- char* buf = new char[BUFSIZE];
+ char* buf = (char *)calloc(1,BUFSIZE);
char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
char* paxData = buf + 1024;
@@ -556,9 +556,6 @@
goto cleanup;
}
- // Good to go -- first construct the standard tar header at the start of the buffer
- memset(buf, 0, BUFSIZE);
-
// Magic fields for the ustar file format
strcat(buf + 257, "ustar");
strcat(buf + 263, "00");
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
index ddf5991..21e06c8 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/utils/ObbFile.cpp
@@ -23,9 +23,9 @@
#define LOG_TAG "ObbFile"
+#include <androidfw/ObbFile.h>
#include <utils/Compat.h>
#include <utils/Log.h>
-#include <utils/ObbFile.h>
//#define DEBUG 1
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 3fa562e..07f3b16 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -17,14 +17,14 @@
#define LOG_TAG "ResourceType"
//#define LOG_NDEBUG 0
+#include <androidfw/ResourceTypes.h>
#include <utils/Atomic.h>
#include <utils/ByteOrder.h>
#include <utils/Debug.h>
-#include <utils/ResourceTypes.h>
+#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/TextOutput.h>
-#include <utils/Log.h>
#include <stdlib.h>
#include <string.h>
@@ -379,8 +379,7 @@
size_t charSize;
if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
charSize = sizeof(uint8_t);
- mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount);
- memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount);
+ mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
} else {
charSize = sizeof(char16_t);
}
@@ -3252,16 +3251,14 @@
// Bag not found, we need to compute it!
if (!grp->bags) {
- grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount);
+ grp->bags = (bag_set***)calloc(grp->typeCount, sizeof(bag_set*));
if (!grp->bags) return NO_MEMORY;
- memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount);
}
bag_set** typeSet = grp->bags[t];
if (!typeSet) {
- typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY);
+ typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
if (!typeSet) return NO_MEMORY;
- memset(typeSet, 0, sizeof(bag_set*)*NENTRY);
grp->bags[t] = typeSet;
}
diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp
index 8512170a..d3fb98d 100644
--- a/libs/utils/StreamingZipInflater.cpp
+++ b/libs/utils/StreamingZipInflater.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "szipinf"
#include <utils/Log.h>
+#include <androidfw/StreamingZipInflater.h>
#include <utils/FileMap.h>
-#include <utils/StreamingZipInflater.h>
#include <string.h>
#include <stddef.h>
#include <assert.h>
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
index 55dfd9f..c8df845 100644
--- a/libs/utils/ZipFileCRO.cpp
+++ b/libs/utils/ZipFileCRO.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <utils/ZipFileCRO.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileCRO.h>
+#include <androidfw/ZipFileRO.h>
using namespace android;
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 1498aac..4b7f1e7 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -19,7 +19,7 @@
//
#define LOG_TAG "zipro"
//#define LOG_NDEBUG 0
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/threads.h>
diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp
index 2dbdc1d..db3479d 100644
--- a/libs/utils/ZipUtils.cpp
+++ b/libs/utils/ZipUtils.cpp
@@ -20,8 +20,8 @@
#define LOG_TAG "ziputil"
-#include <utils/ZipUtils.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
+#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <stdlib.h>
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp
index 46b30c2..09d4d7d 100644
--- a/libs/utils/tests/ObbFile_test.cpp
+++ b/libs/utils/tests/ObbFile_test.cpp
@@ -15,8 +15,8 @@
*/
#define LOG_TAG "ObbFile_test"
+#include <androidfw/ObbFile.h>
#include <utils/Log.h>
-#include <utils/ObbFile.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp
index 7a1d0bd..344f974 100644
--- a/libs/utils/tests/ZipFileRO_test.cpp
+++ b/libs/utils/tests/ZipFileRO_test.cpp
@@ -15,8 +15,8 @@
*/
#define LOG_TAG "ZipFileRO_test"
+#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
-#include <utils/ZipFileRO.h>
#include <gtest/gtest.h>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 78eb89f..9748d3b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -48,6 +48,7 @@
private final Context mContext;
private long mVolumeKeyUpTime;
private int mVolumeControlStream = -1;
+ private final boolean mUseMasterVolume;
private static String TAG = "AudioManager";
/**
@@ -90,7 +91,8 @@
* @see #EXTRA_VIBRATE_SETTING
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
+ public static final String VIBRATE_SETTING_CHANGED_ACTION =
+ "android.media.VIBRATE_SETTING_CHANGED";
/**
* @hide Broadcast intent when the volume for a particular stream type changes.
@@ -104,6 +106,27 @@
public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
/**
+ * @hide Broadcast intent when the master volume changes.
+ * Includes the new volume
+ *
+ * @see #EXTRA_MASTER_VOLUME_VALUE
+ * @see #EXTRA_PREV_MASTER_VOLUME_VALUE
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String MASTER_VOLUME_CHANGED_ACTION =
+ "android.media.MASTER_VOLUME_CHANGED_ACTION";
+
+ /**
+ * @hide Broadcast intent when the master mute state changes.
+ * Includes the the new volume
+ *
+ * @see #EXTRA_MASTER_VOLUME_MUTED
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String MASTER_MUTE_CHANGED_ACTION =
+ "android.media.MASTER_MUTE_CHANGED_ACTION";
+
+ /**
* The new vibrate setting for a particular type.
*
* @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -140,6 +163,27 @@
public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
"android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
+ /**
+ * @hide The new master volume value for the master volume changed intent.
+ * Value is integer between 0 and 100 inclusive.
+ */
+ public static final String EXTRA_MASTER_VOLUME_VALUE =
+ "android.media.EXTRA_MASTER_VOLUME_VALUE";
+
+ /**
+ * @hide The previous master volume value for the master volume changed intent.
+ * Value is integer between 0 and 100 inclusive.
+ */
+ public static final String EXTRA_PREV_MASTER_VOLUME_VALUE =
+ "android.media.EXTRA_PREV_MASTER_VOLUME_VALUE";
+
+ /**
+ * @hide The new master volume mute state for the master mute changed intent.
+ * Value is boolean
+ */
+ public static final String EXTRA_MASTER_VOLUME_MUTED =
+ "android.media.EXTRA_MASTER_VOLUME_MUTED";
+
/** The audio stream for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** The audio stream for system sounds */
@@ -354,6 +398,8 @@
*/
public AudioManager(Context context) {
mContext = context;
+ mUseMasterVolume = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
}
private static IAudioService getService()
@@ -369,11 +415,12 @@
/**
* @hide
*/
- public void preDispatchKeyEvent(int keyCode, int stream) {
+ public void preDispatchKeyEvent(KeyEvent event, int stream) {
/*
* If the user hits another key within the play sound delay, then
* cancel the sound
*/
+ int keyCode = event.getKeyCode();
if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
&& keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
&& mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
@@ -382,15 +429,20 @@
* The user has hit another key during the delay (e.g., 300ms)
* since the last volume key up, so cancel any sounds.
*/
- adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
+ if (mUseMasterVolume) {
+ adjustMasterVolume(ADJUST_SAME, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+ } else {
+ adjustSuggestedStreamVolume(ADJUST_SAME,
stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+ }
}
}
/**
* @hide
*/
- public void handleKeyDown(int keyCode, int stream) {
+ public void handleKeyDown(KeyEvent event, int stream) {
+ int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -399,19 +451,33 @@
* responsive to the user.
*/
int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
- if (mVolumeControlStream != -1) {
- stream = mVolumeControlStream;
- flags |= FLAG_FORCE_STREAM;
+ if (mUseMasterVolume) {
+ adjustMasterVolume(
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ ? ADJUST_RAISE
+ : ADJUST_LOWER,
+ flags);
+ } else {
+ if (mVolumeControlStream != -1) {
+ stream = mVolumeControlStream;
+ flags |= FLAG_FORCE_STREAM;
+ }
+ adjustSuggestedStreamVolume(
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ ? ADJUST_RAISE
+ : ADJUST_LOWER,
+ stream,
+ flags);
}
- adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? ADJUST_RAISE
- : ADJUST_LOWER,
- stream,
- flags);
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO: Actually handle MUTE.
+ if (event.getRepeatCount() == 0) {
+ if (mUseMasterVolume) {
+ setMasterMute(!isMasterMute());
+ } else {
+ // TODO: Actually handle MUTE.
+ }
+ }
break;
}
}
@@ -419,7 +485,8 @@
/**
* @hide
*/
- public void handleKeyUp(int keyCode, int stream) {
+ public void handleKeyUp(KeyEvent event, int stream) {
+ int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -427,21 +494,24 @@
* Play a sound. This is done on key up since we don't want the
* sound to play when a user holds down volume down to mute.
*/
- int flags = FLAG_PLAY_SOUND;
- if (mVolumeControlStream != -1) {
- stream = mVolumeControlStream;
- flags |= FLAG_FORCE_STREAM;
+ if (mUseMasterVolume) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ adjustMasterVolume(ADJUST_SAME, FLAG_PLAY_SOUND);
+ }
+ } else {
+ int flags = FLAG_PLAY_SOUND;
+ if (mVolumeControlStream != -1) {
+ stream = mVolumeControlStream;
+ flags |= FLAG_FORCE_STREAM;
+ }
+ adjustSuggestedStreamVolume(
+ ADJUST_SAME,
+ stream,
+ flags);
}
- adjustSuggestedStreamVolume(
- ADJUST_SAME,
- stream,
- flags);
mVolumeKeyUpTime = SystemClock.uptimeMillis();
break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO: Actually handle MUTE.
- break;
}
}
@@ -464,7 +534,11 @@
public void adjustStreamVolume(int streamType, int direction, int flags) {
IAudioService service = getService();
try {
- service.adjustStreamVolume(streamType, direction, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustStreamVolume(streamType, direction, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustStreamVolume", e);
}
@@ -490,7 +564,11 @@
public void adjustVolume(int direction, int flags) {
IAudioService service = getService();
try {
- service.adjustVolume(direction, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustVolume(direction, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
}
@@ -516,9 +594,32 @@
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
IAudioService service = getService();
try {
- service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ }
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in adjustVolume", e);
+ Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
+ }
+ }
+
+ /**
+ * Adjusts the master volume for the device's audio amplifier.
+ * <p>
+ *
+ * @param direction The direction to adjust the volume. One of
+ * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
+ * {@link #ADJUST_SAME}.
+ * @param flags One or more flags.
+ * @hide
+ */
+ public void adjustMasterVolume(int direction, int flags) {
+ IAudioService service = getService();
+ try {
+ service.adjustMasterVolume(direction, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in adjustMasterVolume", e);
}
}
@@ -564,7 +665,11 @@
public int getStreamMaxVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getStreamMaxVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getMasterMaxVolume();
+ } else {
+ return service.getStreamMaxVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getStreamMaxVolume", e);
return 0;
@@ -582,7 +687,11 @@
public int getStreamVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getStreamVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getMasterVolume();
+ } else {
+ return service.getStreamVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getStreamVolume", e);
return 0;
@@ -597,7 +706,11 @@
public int getLastAudibleStreamVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getLastAudibleStreamVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getLastAudibleMasterVolume();
+ } else {
+ return service.getLastAudibleStreamVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
return 0;
@@ -640,13 +753,82 @@
public void setStreamVolume(int streamType, int index, int flags) {
IAudioService service = getService();
try {
- service.setStreamVolume(streamType, index, flags);
+ if (mUseMasterVolume) {
+ service.setMasterVolume(index, flags);
+ } else {
+ service.setStreamVolume(streamType, index, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setStreamVolume", e);
}
}
/**
+ * Returns the maximum volume index for master volume.
+ *
+ * @hide
+ */
+ public int getMasterMaxVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getMasterMaxVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getMasterMaxVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the current volume index for master volume.
+ *
+ * @return The current volume index for master volume.
+ * @hide
+ */
+ public int getMasterVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getMasterVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getMasterVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Get last audible volume before master volume was muted.
+ *
+ * @hide
+ */
+ public int getLastAudibleMasterVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getLastAudibleMasterVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getLastAudibleMasterVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the volume index for master volume.
+ *
+ * @param index The volume index to set. See
+ * {@link #getMasterMaxVolume(int)} for the largest valid value.
+ * @param flags One or more flags.
+ * @see #getMasterMaxVolume(int)
+ * @see #getMasterVolume(int)
+ * @hide
+ */
+ public void setMasterVolume(int index, int flags) {
+ IAudioService service = getService();
+ try {
+ service.setMasterVolume(index, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMasterVolume", e);
+ }
+ }
+
+ /**
* Solo or unsolo a particular stream. All other streams are muted.
* <p>
* The solo command is protected against client process death: if a process
@@ -717,6 +899,35 @@
}
/**
+ * set master mute state.
+ *
+ * @hide
+ */
+ public void setMasterMute(boolean state) {
+ IAudioService service = getService();
+ try {
+ service.setMasterMute(state, mICallBack);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMasterMute", e);
+ }
+ }
+
+ /**
+ * get master mute state.
+ *
+ * @hide
+ */
+ public boolean isMasterMute() {
+ IAudioService service = getService();
+ try {
+ return service.isMasterMute();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isMasterMute", e);
+ return false;
+ }
+ }
+
+ /**
* forces the stream controlled by hard volume keys
* specifying streamType == -1 releases control to the
* logic.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 13e3982..1c7f577 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,6 +112,7 @@
// AudioHandler message.whats
private static final int MSG_SET_DEVICE_VOLUME = 0;
private static final int MSG_PERSIST_VOLUME = 1;
+ private static final int MSG_PERSIST_MASTER_VOLUME = 2;
private static final int MSG_PERSIST_RINGER_MODE = 3;
private static final int MSG_PERSIST_VIBRATE_SETTING = 4;
private static final int MSG_MEDIA_SERVER_DIED = 5;
@@ -136,7 +137,6 @@
// Timeout for connection to bluetooth headset service
private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
-
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -155,6 +155,10 @@
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
private static final int SOUND_EFFECT_VOLUME = 1000;
+ // Internally master volume is a float in the 0.0 - 1.0 range,
+ // but to support integer based AudioManager API we translate it to 0 - 100
+ private static final int MAX_MASTER_VOLUME = 100;
+
/* Sound effect file names */
private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
private static final String[] SOUND_EFFECT_FILES = new String[] {
@@ -275,6 +279,11 @@
// Forced device usage for communications
private int mForcedUseForComm;
+ // True if we have master volume support
+ private final boolean mUseMasterVolume;
+
+ private final int[] mMasterVolumeRamp;
+
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
@@ -401,6 +410,13 @@
TelephonyManager tmgr = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+ mUseMasterVolume = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
+ restoreMasterVolume();
+
+ mMasterVolumeRamp = context.getResources().getIntArray(
+ com.android.internal.R.array.config_masterVolumeRamp);
}
private void createAudioSystemThread() {
@@ -575,7 +591,7 @@
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
- SENDMSG_REPLACE,
+ SENDMSG_QUEUE,
PERSIST_LAST_AUDIBLE,
device,
s,
@@ -590,7 +606,7 @@
// to persist). Do not change volume if stream is muted.
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
- SENDMSG_NOOP,
+ SENDMSG_QUEUE,
device,
0,
streamState,
@@ -602,6 +618,32 @@
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
+ /** @see AudioManager#adjustMasterVolume(int) */
+ public void adjustMasterVolume(int direction, int flags) {
+ ensureValidDirection(direction);
+ int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+ int delta = 0;
+ for (int i = 0; i < mMasterVolumeRamp.length; i += 2) {
+ int testVolume = mMasterVolumeRamp[i];
+ int testDelta = mMasterVolumeRamp[i + 1];
+ if (direction == AudioManager.ADJUST_RAISE) {
+ if (volume >= testVolume) {
+ delta = testDelta;
+ } else {
+ break;
+ }
+ } else if (direction == AudioManager.ADJUST_LOWER) {
+ if (volume - testDelta >= testVolume) {
+ delta = -testDelta;
+ } else {
+ break;
+ }
+ }
+ }
+// Log.d(TAG, "adjustMasterVolume volume: " + volume + " delta: " + delta + " direction: " + direction);
+ setMasterVolume(volume + delta, flags);
+ }
+
/** @see AudioManager#setStreamVolume(int, int, int) */
public void setStreamVolume(int streamType, int index, int flags) {
ensureValidStreamType(streamType);
@@ -657,6 +699,27 @@
mContext.sendBroadcast(intent);
}
+ // UI update and Broadcast Intent
+ private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
+ mVolumePanel.postMasterVolumeChanged(flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
+ mContext.sendBroadcast(intent);
+ }
+
+ // UI update and Broadcast Intent
+ private void sendMasterMuteUpdate(boolean muted, int flags) {
+ mVolumePanel.postMasterMuteChanged(flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ mContext.sendStickyBroadcast(intent);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
+
/**
* Sets the stream state's index, and posts a message to set system volume.
* This will not call out to the UI. Assumes a valid stream type.
@@ -683,7 +746,7 @@
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
- SENDMSG_REPLACE,
+ SENDMSG_QUEUE,
PERSIST_LAST_AUDIBLE,
device,
streamState,
@@ -695,7 +758,7 @@
// to persist).
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
- SENDMSG_NOOP,
+ SENDMSG_QUEUE,
device,
0,
streamState,
@@ -725,6 +788,19 @@
return (mStreamStates[streamType].muteCount() != 0);
}
+ /** @see AudioManager#setMasterMute(boolean, IBinder) */
+ public void setMasterMute(boolean state, IBinder cb) {
+ if (state != AudioSystem.getMasterMute()) {
+ AudioSystem.setMasterMute(state);
+ sendMasterMuteUpdate(state, AudioManager.FLAG_SHOW_UI);
+ }
+ }
+
+ /** get master mute state. */
+ public boolean isMasterMute() {
+ return AudioSystem.getMasterMute();
+ }
+
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -732,12 +808,45 @@
return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10;
}
+ public int getMasterVolume() {
+ if (isMasterMute()) return 0;
+ return getLastAudibleMasterVolume();
+ }
+
+ public void setMasterVolume(int volume, int flags) {
+ if (volume < 0) {
+ volume = 0;
+ } else if (volume > MAX_MASTER_VOLUME) {
+ volume = MAX_MASTER_VOLUME;
+ }
+ doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
+ }
+
+ private void doSetMasterVolume(float volume, int flags) {
+ // don't allow changing master volume when muted
+ if (!AudioSystem.getMasterMute()) {
+ int oldVolume = getMasterVolume();
+ AudioSystem.setMasterVolume(volume);
+
+ int newVolume = getMasterVolume();
+ if (newVolume != oldVolume) {
+ // Post a persist master volume msg
+ sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
+ Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
+ sendMasterVolumeUpdate(flags, oldVolume, newVolume);
+ }
+ }
+ }
+
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
ensureValidStreamType(streamType);
return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
+ public int getMasterMaxVolume() {
+ return MAX_MASTER_VOLUME;
+ }
/** Get last audible volume before stream was muted. */
public int getLastAudibleStreamVolume(int streamType) {
@@ -746,6 +855,11 @@
return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10;
}
+ /** Get last audible master volume before it was muted. */
+ public int getLastAudibleMasterVolume() {
+ return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+ }
+
/** @see AudioManager#getRingerMode() */
public int getRingerMode() {
synchronized(mSettingsLock) {
@@ -816,6 +930,16 @@
}
}
+ private void restoreMasterVolume() {
+ if (mUseMasterVolume) {
+ float volume = Settings.System.getFloat(mContentResolver,
+ Settings.System.VOLUME_MASTER, -1.0f);
+ if (volume >= 0.0f) {
+ AudioSystem.setMasterVolume(volume);
+ }
+ }
+ }
+
/** @see AudioManager#shouldVibrate(int) */
public boolean shouldVibrate(int vibrateType) {
@@ -2084,7 +2208,7 @@
}
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
- SENDMSG_NOOP,
+ SENDMSG_QUEUE,
0,
0,
VolumeStreamState.this, 0);
@@ -2128,7 +2252,7 @@
}
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
- SENDMSG_NOOP,
+ SENDMSG_QUEUE,
0,
0,
VolumeStreamState.this, 0);
@@ -2226,7 +2350,7 @@
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
- SENDMSG_REPLACE,
+ SENDMSG_QUEUE,
PERSIST_CURRENT|PERSIST_LAST_AUDIBLE,
device,
streamState,
@@ -2355,6 +2479,11 @@
persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
break;
+ case MSG_PERSIST_MASTER_VOLUME:
+ Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER,
+ (float)msg.arg1 / (float)1000.0);
+ break;
+
case MSG_PERSIST_RINGER_MODE:
// note that the value persisted is the current ringer mode, not the
// value of ringer mode as of the time the request was made to persist
@@ -2415,6 +2544,9 @@
// Restore ringer mode
setRingerModeInt(getRingerMode(), false);
+ // Restore master volume
+ restoreMasterVolume();
+
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
break;
@@ -2839,6 +2971,11 @@
adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.A2DP);
}
+
+ if (mUseMasterVolume) {
+ // Send sticky broadcast for initial master mute state
+ sendMasterMuteUpdate(false, 0);
+ }
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// a package is being removed, not replaced
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 3080497..d354cdb 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -318,5 +318,9 @@
public static native int initStreamVolume(int stream, int indexMin, int indexMax);
public static native int setStreamVolumeIndex(int stream, int index, int device);
public static native int getStreamVolumeIndex(int stream, int device);
+ public static native int setMasterVolume(float value);
+ public static native float getMasterVolume();
+ public static native int setMasterMute(boolean mute);
+ public static native boolean getMasterMute();
public static native int getDevicesForStream(int stream);
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5294d36..17d8e4d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -30,10 +30,14 @@
void adjustVolume(int direction, int flags);
void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
-
+
void adjustStreamVolume(int streamType, int direction, int flags);
-
+
+ void adjustMasterVolume(int direction, int flags);
+
void setStreamVolume(int streamType, int index, int flags);
+
+ void setMasterVolume(int index, int flags);
void setStreamSolo(int streamType, boolean state, IBinder cb);
@@ -41,12 +45,22 @@
boolean isStreamMute(int streamType);
+ void setMasterMute(boolean state, IBinder cb);
+
+ boolean isMasterMute();
+
int getStreamVolume(int streamType);
-
+
+ int getMasterVolume();
+
int getStreamMaxVolume(int streamType);
+
+ int getMasterMaxVolume();
int getLastAudibleStreamVolume(int streamType);
+ int getLastAudibleMasterVolume();
+
void setRingerMode(int ringerMode);
int getRingerMode();
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index e92c710..7fcbffa 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -34,6 +34,8 @@
public class MediaInserter {
private final HashMap<Uri, List<ContentValues>> mRowMap =
new HashMap<Uri, List<ContentValues>>();
+ private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
+ new HashMap<Uri, List<ContentValues>>();
private IContentProvider mProvider;
private int mBufferSizePerUri;
@@ -44,26 +46,45 @@
}
public void insert(Uri tableUri, ContentValues values) throws RemoteException {
- List<ContentValues> list = mRowMap.get(tableUri);
+ insert(tableUri, values, false);
+ }
+
+ public void insertwithPriority(Uri tableUri, ContentValues values) throws RemoteException {
+ insert(tableUri, values, true);
+ }
+
+ private void insert(Uri tableUri, ContentValues values, boolean priority) throws RemoteException {
+ HashMap<Uri, List<ContentValues>> rowmap = priority ? mPriorityRowMap : mRowMap;
+ List<ContentValues> list = rowmap.get(tableUri);
if (list == null) {
list = new ArrayList<ContentValues>();
- mRowMap.put(tableUri, list);
+ rowmap.put(tableUri, list);
}
list.add(new ContentValues(values));
if (list.size() >= mBufferSizePerUri) {
- flush(tableUri);
+ flushAllPriority();
+ flush(tableUri, list);
}
}
public void flushAll() throws RemoteException {
+ flushAllPriority();
for (Uri tableUri : mRowMap.keySet()){
- flush(tableUri);
+ List<ContentValues> list = mRowMap.get(tableUri);
+ flush(tableUri, list);
}
mRowMap.clear();
}
- private void flush(Uri tableUri) throws RemoteException {
- List<ContentValues> list = mRowMap.get(tableUri);
+ private void flushAllPriority() throws RemoteException {
+ for (Uri tableUri : mPriorityRowMap.keySet()){
+ List<ContentValues> list = mPriorityRowMap.get(tableUri);
+ flush(tableUri, list);
+ }
+ mPriorityRowMap.clear();
+ }
+
+ private void flush(Uri tableUri, List<ContentValues> list) throws RemoteException {
if (!list.isEmpty()) {
ContentValues[] valuesArray = new ContentValues[list.size()];
valuesArray = list.toArray(valuesArray);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 69ca58b..52d31c7 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -59,6 +59,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.Locale;
/**
@@ -374,7 +375,7 @@
// hashes file path to FileCacheEntry.
// path should be lower case if mCaseInsensitivePaths is true
- private HashMap<String, FileCacheEntry> mFileCache;
+ private LinkedHashMap<String, FileCacheEntry> mFileCache;
private ArrayList<FileCacheEntry> mPlayLists;
@@ -922,16 +923,15 @@
}
}
- // new file, insert it
- // We insert directories immediately to ensure they are in the database
- // before the files they contain.
- // Otherwise we can get duplicate directory entries in the database
- // if one of the media FileInserters is flushed before the files table FileInserter
- // Also, we immediately insert the file if the rowId of the inserted file is
- // needed.
- if (inserter == null || needToSetSettings ||
- entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
+ // New file, insert it.
+ // Directories need to be inserted before the files they contain, so they
+ // get priority when bulk inserting.
+ // If the rowId of the inserted file is needed, it gets inserted immediately,
+ // bypassing the bulk inserter.
+ if (inserter == null || needToSetSettings) {
result = mMediaProvider.insert(tableUri, values);
+ } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
+ inserter.insertwithPriority(tableUri, values);
} else {
inserter.insert(tableUri, values);
}
@@ -1029,7 +1029,7 @@
String[] selectionArgs = null;
if (mFileCache == null) {
- mFileCache = new HashMap<String, FileCacheEntry>();
+ mFileCache = new LinkedHashMap<String, FileCacheEntry>();
} else {
mFileCache.clear();
}
@@ -1151,7 +1151,8 @@
}
static class MediaBulkDeleter {
- StringBuilder idList = new StringBuilder();
+ StringBuilder whereClause = new StringBuilder();
+ ArrayList<String> whereArgs = new ArrayList<String>(100);
IContentProvider mProvider;
Uri mBaseUri;
@@ -1161,19 +1162,26 @@
}
public void delete(long id) throws RemoteException {
- if (idList.length() != 0) {
- idList.append(",");
+ if (whereClause.length() != 0) {
+ whereClause.append(",");
}
- idList.append(id);
- if (idList.length() > 1024) {
+ whereClause.append("?");
+ whereArgs.add("" + id);
+ if (whereArgs.size() > 100) {
flush();
}
}
public void flush() throws RemoteException {
- int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
- idList.toString() + ")", null);
- //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
- idList.setLength(0);
+ int size = whereArgs.size();
+ if (size > 0) {
+ String [] foo = new String [size];
+ foo = whereArgs.toArray(foo);
+ int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
+ whereClause.toString() + ")", foo);
+ //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
+ whereClause.setLength(0);
+ whereArgs.clear();
+ }
}
}
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index bcf7b89..91d0add 100755
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -84,6 +84,7 @@
// to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
private static final int NATIVE_EVENT_PCM_CAPTURE = 0;
private static final int NATIVE_EVENT_FFT_CAPTURE = 1;
+ private static final int NATIVE_EVENT_SERVER_DIED = 2;
// Error codes:
/**
@@ -147,6 +148,10 @@
* PCM and FFT capture listener registered by client
*/
private OnDataCaptureListener mCaptureListener = null;
+ /**
+ * Server Died listener registered by client
+ */
+ private OnServerDiedListener mServerDiedListener = null;
// accessed by native methods
private int mNativeVisualizer;
@@ -396,6 +401,9 @@
public interface OnDataCaptureListener {
/**
* Method called when a new waveform capture is available.
+ * <p>Data in the waveform buffer is valid only within the scope of the callback.
+ * Applications which needs access to the waveform data after returning from the callback
+ * should make a copy of the data instead of holding a reference.
* @param visualizer Visualizer object on which the listener is registered.
* @param waveform array of bytes containing the waveform representation.
* @param samplingRate sampling rate of the audio visualized.
@@ -404,6 +412,9 @@
/**
* Method called when a new frequency capture is available.
+ * <p>Data in the fft buffer is valid only within the scope of the callback.
+ * Applications which needs access to the fft data after returning from the callback
+ * should make a copy of the data instead of holding a reference.
* @param visualizer Visualizer object on which the listener is registered.
* @param fft array of bytes containing the frequency representation.
* @param samplingRate sampling rate of the audio visualized.
@@ -452,6 +463,43 @@
}
/**
+ * @hide
+ *
+ * The OnServerDiedListener interface defines a method called by the Visualizer to indicate that
+ * the connection to the native media server has been broken and that the Visualizer object will
+ * need to be released and re-created.
+ * The client application can implement this interface and register the listener with the
+ * {@link #setServerDiedListener(OnServerDiedListener)} method.
+ */
+ public interface OnServerDiedListener {
+ /**
+ * @hide
+ *
+ * Method called when the native media server has died.
+ * <p>If the native media server encounters a fatal error and needs to restart, the binder
+ * connection from the {@link #Visualizer} to the media server will be broken. Data capture
+ * callbacks will stop happening, and client initiated calls to the {@link #Visualizer}
+ * instance will fail with the error code {@link #DEAD_OBJECT}. To restore functionality,
+ * clients should {@link #release()} their old visualizer and create a new instance.
+ */
+ void onServerDied();
+ }
+
+ /**
+ * @hide
+ *
+ * Registers an OnServerDiedListener interface.
+ * <p>Call this method with a null listener to stop receiving server death notifications.
+ * @return {@link #SUCCESS} in case of success,
+ */
+ public int setServerDiedListener(OnServerDiedListener listener) {
+ synchronized (mListenerLock) {
+ mServerDiedListener = listener;
+ }
+ return SUCCESS;
+ }
+
+ /**
* Helper class to handle the forwarding of native events to the appropriate listeners
*/
private class NativeEventHandler extends Handler
@@ -463,11 +511,7 @@
mVisualizer = v;
}
- @Override
- public void handleMessage(Message msg) {
- if (mVisualizer == null) {
- return;
- }
+ private void handleCaptureMessage(Message msg) {
OnDataCaptureListener l = null;
synchronized (mListenerLock) {
l = mVisualizer.mCaptureListener;
@@ -476,6 +520,7 @@
if (l != null) {
byte[] data = (byte[])msg.obj;
int samplingRate = msg.arg1;
+
switch(msg.what) {
case NATIVE_EVENT_PCM_CAPTURE:
l.onWaveFormDataCapture(mVisualizer, data, samplingRate);
@@ -484,11 +529,41 @@
l.onFftDataCapture(mVisualizer, data, samplingRate);
break;
default:
- Log.e(TAG,"Unknown native event: "+msg.what);
+ Log.e(TAG,"Unknown native event in handleCaptureMessge: "+msg.what);
break;
}
}
}
+
+ private void handleServerDiedMessage(Message msg) {
+ OnServerDiedListener l = null;
+ synchronized (mListenerLock) {
+ l = mVisualizer.mServerDiedListener;
+ }
+
+ if (l != null)
+ l.onServerDied();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mVisualizer == null) {
+ return;
+ }
+
+ switch(msg.what) {
+ case NATIVE_EVENT_PCM_CAPTURE:
+ case NATIVE_EVENT_FFT_CAPTURE:
+ handleCaptureMessage(msg);
+ break;
+ case NATIVE_EVENT_SERVER_DIED:
+ handleServerDiedMessage(msg);
+ break;
+ default:
+ Log.e(TAG,"Unknown native event: "+msg.what);
+ break;
+ }
+ }
}
//---------------------------------------------------------
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index ecd4d07..f015afb 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -23,6 +23,7 @@
#include <nativehelper/jni.h>
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <utils/threads.h>
#include "media/Visualizer.h"
using namespace android;
@@ -38,6 +39,7 @@
#define NATIVE_EVENT_PCM_CAPTURE 0
#define NATIVE_EVENT_FFT_CAPTURE 1
+#define NATIVE_EVENT_SERVER_DIED 2
// ----------------------------------------------------------------------------
static const char* const kClassPathName = "android/media/audiofx/Visualizer";
@@ -54,6 +56,43 @@
struct visualizer_callback_cookie {
jclass visualizer_class; // Visualizer class
jobject visualizer_ref; // Visualizer object instance
+
+ // Lazily allocated arrays used to hold callback data provided to java
+ // applications. These arrays are allocated during the first callback and
+ // reallocated when the size of the callback data changes. Allocating on
+ // demand and saving the arrays means that applications cannot safely hold a
+ // reference to the provided data (they need to make a copy if they want to
+ // hold onto outside of the callback scope), but it avoids GC thrash caused
+ // by constantly allocating and releasing arrays to hold callback data.
+ Mutex callback_data_lock;
+ jbyteArray waveform_data;
+ jbyteArray fft_data;
+
+ visualizer_callback_cookie() {
+ waveform_data = NULL;
+ fft_data = NULL;
+ }
+
+ ~visualizer_callback_cookie() {
+ cleanupBuffers();
+ }
+
+ void cleanupBuffers() {
+ AutoMutex lock(&callback_data_lock);
+ if (waveform_data || fft_data) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ if (waveform_data) {
+ env->DeleteGlobalRef(waveform_data);
+ waveform_data = NULL;
+ }
+
+ if (fft_data) {
+ env->DeleteGlobalRef(fft_data);
+ fft_data = NULL;
+ }
+ }
+ }
};
// ----------------------------------------------------------------------------
@@ -66,7 +105,6 @@
~visualizerJniStorage() {
}
-
};
@@ -93,6 +131,26 @@
// ----------------------------------------------------------------------------
+static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
+ if (NULL != *array) {
+ uint32_t len = env->GetArrayLength(*array);
+ if (len == size)
+ return;
+
+ env->DeleteGlobalRef(*array);
+ *array = NULL;
+ }
+
+ jbyteArray localRef = env->NewByteArray(size);
+ if (NULL != localRef) {
+ // Promote to global ref.
+ *array = (jbyteArray)env->NewGlobalRef(localRef);
+
+ // Release our (now pointless) local ref.
+ env->DeleteLocalRef(localRef);
+ }
+}
+
static void captureCallback(void* user,
uint32_t waveformSize,
uint8_t *waveform,
@@ -106,6 +164,7 @@
visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
+ AutoMutex lock(&callbackInfo->callback_data_lock);
ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
callbackInfo,
@@ -118,7 +177,11 @@
}
if (waveformSize != 0 && waveform != NULL) {
- jbyteArray jArray = env->NewByteArray(waveformSize);
+ jbyteArray jArray;
+
+ ensureArraySize(env, &callbackInfo->waveform_data, waveformSize);
+ jArray = callbackInfo->waveform_data;
+
if (jArray != NULL) {
jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
memcpy(nArray, waveform, waveformSize);
@@ -131,12 +194,15 @@
samplingrate,
0,
jArray);
- env->DeleteLocalRef(jArray);
}
}
if (fftSize != 0 && fft != NULL) {
- jbyteArray jArray = env->NewByteArray(fftSize);
+ jbyteArray jArray;
+
+ ensureArraySize(env, &callbackInfo->fft_data, fftSize);
+ jArray = callbackInfo->fft_data;
+
if (jArray != NULL) {
jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
memcpy(nArray, fft, fftSize);
@@ -149,7 +215,6 @@
samplingrate,
0,
jArray);
- env->DeleteLocalRef(jArray);
}
}
@@ -220,6 +285,23 @@
}
+static void android_media_visualizer_effect_callback(int32_t event,
+ void *user,
+ void *info) {
+ if ((event == AudioEffect::EVENT_ERROR) &&
+ (*((status_t*)info) == DEAD_OBJECT)) {
+ visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user;
+ visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->CallStaticVoidMethod(
+ callbackInfo->visualizer_class,
+ fields.midPostNativeEvent,
+ callbackInfo->visualizer_ref,
+ NATIVE_EVENT_SERVER_DIED,
+ 0, 0, 0);
+ }
+}
static jint
android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
@@ -255,8 +337,8 @@
// create the native Visualizer object
lpVisualizer = new Visualizer(0,
- NULL,
- NULL,
+ android_media_visualizer_effect_callback,
+ lpJniStorage,
sessionId);
if (lpVisualizer == NULL) {
ALOGE("Error creating Visualizer");
@@ -345,7 +427,17 @@
return VISUALIZER_ERROR_NO_INIT;
}
- return translateError(lpVisualizer->setEnabled(enabled));
+ jint retVal = translateError(lpVisualizer->setEnabled(enabled));
+
+ if (!enabled) {
+ visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
+ thiz, fields.fidJniData);
+
+ if (NULL != lpJniStorage)
+ lpJniStorage->mCallbackData.cleanupBuffers();
+ }
+
+ return retVal;
}
static jboolean
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index e44dc7c..b17ae45 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -57,6 +57,7 @@
libaudioflinger \
libbinder \
libstagefright \
+ libstagefright_foundation \
libstagefright_omx \
libgui \
libvideoeditorplayer
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 0d51def..ceb87db 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -623,7 +623,7 @@
newTrack->setVolume(leftVolume, rightVolume);
newTrack->setLoop(0, frameCount, loop);
- // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored.
+ // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
mToggle = toggle;
mAudioTrack = newTrack;
mPos = 0;
@@ -840,7 +840,7 @@
void SoundChannel::setRate(float rate)
{
Mutex::Autolock lock(&mLock);
- if (mAudioTrack != 0 && mSample.get() != 0) {
+ if (mAudioTrack != NULL && mSample != 0) {
uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
mAudioTrack->setSampleRate(sampleRate);
mRate = rate;
@@ -852,7 +852,8 @@
{
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
- if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume);
+ if (mAudioTrack != NULL)
+ mAudioTrack->setVolume(leftVolume, rightVolume);
}
void SoundChannel::setVolume(float leftVolume, float rightVolume)
@@ -864,7 +865,7 @@
void SoundChannel::setLoop(int loop)
{
Mutex::Autolock lock(&mLock);
- if (mAudioTrack != 0 && mSample.get() != 0) {
+ if (mAudioTrack != NULL && mSample != 0) {
uint32_t loopEnd = mSample->size()/mNumChannels/
((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
mAudioTrack->setLoop(0, loopEnd, loop);
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 6b11c28..002b045 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -116,7 +116,7 @@
class SoundChannel : public SoundEvent {
public:
enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
- SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1),
+ SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
mPos(0), mToggle(0), mAutoPaused(false) {}
~SoundChannel();
void init(SoundPool* soundPool);
diff --git a/media/libaah_rtp/Android.mk b/media/libaah_rtp/Android.mk
new file mode 100644
index 0000000..54fd9ec
--- /dev/null
+++ b/media/libaah_rtp/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+#
+# libaah_rtp
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaah_rtp
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ aah_decoder_pump.cpp \
+ aah_rx_player.cpp \
+ aah_rx_player_core.cpp \
+ aah_rx_player_ring_buffer.cpp \
+ aah_rx_player_substream.cpp \
+ aah_tx_packet.cpp \
+ aah_tx_player.cpp \
+ aah_tx_sender.cpp \
+ pipe_event.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/include \
+ frameworks/base/include/media/stagefright/openmax \
+ frameworks/base/media \
+ frameworks/base/media/libstagefright
+
+LOCAL_SHARED_LIBRARIES := \
+ libcommon_time_client \
+ libbinder \
+ libmedia \
+ libstagefright \
+ libstagefright_foundation \
+ libutils
+
+LOCAL_LDLIBS := \
+ -lpthread
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libaah_rtp/aah_decoder_pump.cpp b/media/libaah_rtp/aah_decoder_pump.cpp
new file mode 100644
index 0000000..72fe43b
--- /dev/null
+++ b/media/libaah_rtp/aah_decoder_pump.cpp
@@ -0,0 +1,520 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <poll.h>
+#include <pthread.h>
+
+#include <common_time/cc_helper.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
+
+#include "aah_decoder_pump.h"
+
+namespace android {
+
+static const long long kLongDecodeErrorThreshold = 1000000ll;
+static const uint32_t kMaxLongErrorsBeforeFatal = 3;
+static const uint32_t kMaxErrorsBeforeFatal = 60;
+
+AAH_DecoderPump::AAH_DecoderPump(OMXClient& omx)
+ : omx_(omx)
+ , thread_status_(OK)
+ , renderer_(NULL)
+ , last_queued_pts_valid_(false)
+ , last_queued_pts_(0)
+ , last_ts_transform_valid_(false)
+ , last_volume_(0xFF) {
+ thread_ = new ThreadWrapper(this);
+}
+
+AAH_DecoderPump::~AAH_DecoderPump() {
+ shutdown();
+}
+
+status_t AAH_DecoderPump::initCheck() {
+ if (thread_ == NULL) {
+ ALOGE("Failed to allocate thread");
+ return NO_MEMORY;
+ }
+
+ return OK;
+}
+
+status_t AAH_DecoderPump::queueForDecode(MediaBuffer* buf) {
+ if (NULL == buf) {
+ return BAD_VALUE;
+ }
+
+ if (OK != thread_status_) {
+ return thread_status_;
+ }
+
+ { // Explicit scope for AutoMutex pattern.
+ AutoMutex lock(&thread_lock_);
+ in_queue_.push_back(buf);
+ }
+
+ thread_cond_.signal();
+
+ return OK;
+}
+
+void AAH_DecoderPump::queueToRenderer(MediaBuffer* decoded_sample) {
+ Mutex::Autolock lock(&render_lock_);
+ sp<MetaData> meta;
+ int64_t ts;
+ status_t res;
+
+ // Fetch the metadata and make sure the sample has a timestamp. We
+ // cannot render samples which are missing PTSs.
+ meta = decoded_sample->meta_data();
+ if ((meta == NULL) || (!meta->findInt64(kKeyTime, &ts))) {
+ ALOGV("Decoded sample missing timestamp, cannot render.");
+ CHECK(false);
+ } else {
+ // If we currently are not holding on to a renderer, go ahead and
+ // make one now.
+ if (NULL == renderer_) {
+ renderer_ = new TimedAudioTrack();
+ if (NULL != renderer_) {
+ int frameCount;
+ AudioTrack::getMinFrameCount(&frameCount,
+ AUDIO_STREAM_DEFAULT,
+ static_cast<int>(format_sample_rate_));
+ int ch_format = (format_channels_ == 1)
+ ? AUDIO_CHANNEL_OUT_MONO
+ : AUDIO_CHANNEL_OUT_STEREO;
+
+ res = renderer_->set(AUDIO_STREAM_DEFAULT,
+ format_sample_rate_,
+ AUDIO_FORMAT_PCM_16_BIT,
+ ch_format,
+ frameCount);
+ if (res != OK) {
+ ALOGE("Failed to setup audio renderer. (res = %d)", res);
+ delete renderer_;
+ renderer_ = NULL;
+ } else {
+ CHECK(last_ts_transform_valid_);
+
+ res = renderer_->setMediaTimeTransform(
+ last_ts_transform_, TimedAudioTrack::COMMON_TIME);
+ if (res != NO_ERROR) {
+ ALOGE("Failed to set media time transform on AudioTrack"
+ " (res = %d)", res);
+ delete renderer_;
+ renderer_ = NULL;
+ } else {
+ float volume = static_cast<float>(last_volume_)
+ / 255.0f;
+ if (renderer_->setVolume(volume, volume) != OK) {
+ ALOGW("%s: setVolume failed", __FUNCTION__);
+ }
+
+ renderer_->start();
+ }
+ }
+ } else {
+ ALOGE("Failed to allocate AudioTrack to use as a renderer.");
+ }
+ }
+
+ if (NULL != renderer_) {
+ uint8_t* decoded_data =
+ reinterpret_cast<uint8_t*>(decoded_sample->data());
+ uint32_t decoded_amt = decoded_sample->range_length();
+ decoded_data += decoded_sample->range_offset();
+
+ sp<IMemory> pcm_payload;
+ res = renderer_->allocateTimedBuffer(decoded_amt, &pcm_payload);
+ if (res != OK) {
+ ALOGE("Failed to allocate %d byte audio track buffer."
+ " (res = %d)", decoded_amt, res);
+ } else {
+ memcpy(pcm_payload->pointer(), decoded_data, decoded_amt);
+
+ res = renderer_->queueTimedBuffer(pcm_payload, ts);
+ if (res != OK) {
+ ALOGE("Failed to queue %d byte audio track buffer with media"
+ " PTS %lld. (res = %d)", decoded_amt, ts, res);
+ } else {
+ last_queued_pts_valid_ = true;
+ last_queued_pts_ = ts;
+ }
+ }
+
+ } else {
+ ALOGE("No renderer, dropping audio payload.");
+ }
+ }
+}
+
+void AAH_DecoderPump::stopAndCleanupRenderer() {
+ if (NULL == renderer_) {
+ return;
+ }
+
+ renderer_->stop();
+ delete renderer_;
+ renderer_ = NULL;
+}
+
+void AAH_DecoderPump::setRenderTSTransform(const LinearTransform& trans) {
+ Mutex::Autolock lock(&render_lock_);
+
+ if (last_ts_transform_valid_ && !memcmp(&trans,
+ &last_ts_transform_,
+ sizeof(trans))) {
+ return;
+ }
+
+ last_ts_transform_ = trans;
+ last_ts_transform_valid_ = true;
+
+ if (NULL != renderer_) {
+ status_t res = renderer_->setMediaTimeTransform(
+ last_ts_transform_, TimedAudioTrack::COMMON_TIME);
+ if (res != NO_ERROR) {
+ ALOGE("Failed to set media time transform on AudioTrack"
+ " (res = %d)", res);
+ }
+ }
+}
+
+void AAH_DecoderPump::setRenderVolume(uint8_t volume) {
+ Mutex::Autolock lock(&render_lock_);
+
+ if (volume == last_volume_) {
+ return;
+ }
+
+ last_volume_ = volume;
+ if (renderer_ != NULL) {
+ float volume = static_cast<float>(last_volume_) / 255.0f;
+ if (renderer_->setVolume(volume, volume) != OK) {
+ ALOGW("%s: setVolume failed", __FUNCTION__);
+ }
+ }
+}
+
+// isAboutToUnderflow is something of a hack used to figure out when it might be
+// time to give up on trying to fill in a gap in the RTP sequence and simply
+// move on with a discontinuity. If we had perfect knowledge of when we were
+// going to underflow, it would not be a hack, but unfortunately we do not.
+// Right now, we just take the PTS of the last sample queued, and check to see
+// if its presentation time is within kAboutToUnderflowThreshold from now. If
+// it is, then we say that we are about to underflow. This decision is based on
+// two (possibly invalid) assumptions.
+//
+// 1) The transmitter is leading the clock by more than
+// kAboutToUnderflowThreshold.
+// 2) The delta between the PTS of the last sample queued and the next sample
+// is less than the transmitter's clock lead amount.
+//
+// Right now, the default transmitter lead time is 1 second, which is a pretty
+// large number and greater than the 50mSec that kAboutToUnderflowThreshold is
+// currently set to. This should satisfy assumption #1 for now, but changes to
+// the transmitter clock lead time could effect this.
+//
+// For non-sparse streams with a homogeneous sample rate (the vast majority of
+// streams in the world), the delta between any two adjacent PTSs will always be
+// the homogeneous sample period. It is very uncommon to see a sample period
+// greater than the 1 second clock lead we are currently using, and you
+// certainly will not see it in an MP3 file which should satisfy assumption #2.
+// Sparse audio streams (where no audio is transmitted for long periods of
+// silence) and extremely low framerate video stream (like an MPEG-2 slideshow
+// or the video stream for a pay TV audio channel) are examples of streams which
+// might violate assumption #2.
+bool AAH_DecoderPump::isAboutToUnderflow(int64_t threshold) {
+ Mutex::Autolock lock(&render_lock_);
+
+ // If we have never queued anything to the decoder, we really don't know if
+ // we are going to underflow or not.
+ if (!last_queued_pts_valid_ || !last_ts_transform_valid_) {
+ return false;
+ }
+
+ // Don't have access to Common Time? If so, then things are Very Bad
+ // elsewhere in the system; it pretty much does not matter what we do here.
+ // Since we cannot really tell if we are about to underflow or not, its
+ // probably best to assume that we are not and proceed accordingly.
+ int64_t tt_now;
+ if (OK != cc_helper_.getCommonTime(&tt_now)) {
+ return false;
+ }
+
+ // Transform from media time to common time.
+ int64_t last_queued_pts_tt;
+ if (!last_ts_transform_.doForwardTransform(last_queued_pts_,
+ &last_queued_pts_tt)) {
+ return false;
+ }
+
+ // Check to see if we are underflowing.
+ return ((tt_now + threshold - last_queued_pts_tt) > 0);
+}
+
+void* AAH_DecoderPump::workThread() {
+ // No need to lock when accessing decoder_ from the thread. The
+ // implementation of init and shutdown ensure that other threads never touch
+ // decoder_ while the work thread is running.
+ CHECK(decoder_ != NULL);
+ CHECK(format_ != NULL);
+
+ // Start the decoder and note its result code. If something goes horribly
+ // wrong, callers of queueForDecode and getOutput will be able to detect
+ // that the thread encountered a fatal error and shut down by examining
+ // thread_status_.
+ thread_status_ = decoder_->start(format_.get());
+ if (OK != thread_status_) {
+ ALOGE("AAH_DecoderPump's work thread failed to start decoder (res = %d)",
+ thread_status_);
+ return NULL;
+ }
+
+ DurationTimer decode_timer;
+ uint32_t consecutive_long_errors = 0;
+ uint32_t consecutive_errors = 0;
+
+ while (!thread_->exitPending()) {
+ status_t res;
+ MediaBuffer* bufOut = NULL;
+
+ decode_timer.start();
+ res = decoder_->read(&bufOut);
+ decode_timer.stop();
+
+ if (res == INFO_FORMAT_CHANGED) {
+ // Format has changed. Destroy our current renderer so that a new
+ // one can be created during queueToRenderer with the proper format.
+ //
+ // TODO : In order to transition seamlessly, we should change this
+ // to put the old renderer in a queue to play out completely before
+ // we destroy it. We can still create a new renderer, the timed
+ // nature of the renderer should ensure a seamless splice.
+ stopAndCleanupRenderer();
+ res = OK;
+ }
+
+ // Try to be a little nuanced in our handling of actual decode errors.
+ // Errors could happen because of minor stream corruption or because of
+ // transient resource limitations. In these cases, we would rather drop
+ // a little bit of output and ride out the unpleasantness then throw up
+ // our hands and abort everything.
+ //
+ // OTOH - When things are really bad (like we have a non-transient
+ // resource or bookkeeping issue, or the stream being fed to us is just
+ // complete and total garbage) we really want to terminate playback and
+ // raise an error condition all the way up to the application level so
+ // they can deal with it.
+ //
+ // Unfortunately, the error codes returned by the decoder can be a
+ // little non-specific. For example, if an OMXCodec times out
+ // attempting to obtain an output buffer, the error we get back is a
+ // generic -1. Try to distinguish between this resource timeout error
+ // and ES corruption error by timing how long the decode operation
+ // takes. Maintain accounting for both errors and "long errors". If we
+ // get more than a certain number consecutive errors of either type,
+ // consider it fatal and shutdown (which will cause the error to
+ // propagate all of the way up to the application level). The threshold
+ // for "long errors" is deliberately much lower than that of normal
+ // decode errors, both because of how long they take to happen and
+ // because they generally indicate resource limitation errors which are
+ // unlikely to go away in pathologically bad cases (in contrast to
+ // stream corruption errors which might happen 20 times in a row and
+ // then be suddenly OK again)
+ if (res != OK) {
+ consecutive_errors++;
+ if (decode_timer.durationUsecs() >= kLongDecodeErrorThreshold)
+ consecutive_long_errors++;
+
+ CHECK(NULL == bufOut);
+
+ ALOGW("%s: Failed to decode data (res = %d)",
+ __PRETTY_FUNCTION__, res);
+
+ if ((consecutive_errors >= kMaxErrorsBeforeFatal) ||
+ (consecutive_long_errors >= kMaxLongErrorsBeforeFatal)) {
+ ALOGE("%s: Maximum decode error threshold has been reached."
+ " There have been %d consecutive decode errors, and %d"
+ " consecutive decode operations which resulted in errors"
+ " and took more than %lld uSec to process. The last"
+ " decode operation took %lld uSec.",
+ __PRETTY_FUNCTION__,
+ consecutive_errors, consecutive_long_errors,
+ kLongDecodeErrorThreshold, decode_timer.durationUsecs());
+ thread_status_ = res;
+ break;
+ }
+
+ continue;
+ }
+
+ if (NULL == bufOut) {
+ ALOGW("%s: Successful decode, but no buffer produced",
+ __PRETTY_FUNCTION__);
+ continue;
+ }
+
+ // Successful decode (with actual output produced). Clear the error
+ // counters.
+ consecutive_errors = 0;
+ consecutive_long_errors = 0;
+
+ queueToRenderer(bufOut);
+ bufOut->release();
+ }
+
+ decoder_->stop();
+ stopAndCleanupRenderer();
+
+ return NULL;
+}
+
+status_t AAH_DecoderPump::init(const sp<MetaData>& params) {
+ Mutex::Autolock lock(&init_lock_);
+
+ if (decoder_ != NULL) {
+ // already inited
+ return OK;
+ }
+
+ if (params == NULL) {
+ return BAD_VALUE;
+ }
+
+ if (!params->findInt32(kKeyChannelCount, &format_channels_)) {
+ return BAD_VALUE;
+ }
+
+ if (!params->findInt32(kKeySampleRate, &format_sample_rate_)) {
+ return BAD_VALUE;
+ }
+
+ CHECK(OK == thread_status_);
+ CHECK(decoder_ == NULL);
+
+ status_t ret_val = UNKNOWN_ERROR;
+
+ // Cache the format and attempt to create the decoder.
+ format_ = params;
+ decoder_ = OMXCodec::Create(
+ omx_.interface(), // IOMX Handle
+ format_, // Metadata for substream (indicates codec)
+ false, // Make a decoder, not an encoder
+ sp<MediaSource>(this)); // We will be the source for this codec.
+
+ if (decoder_ == NULL) {
+ ALOGE("Failed to allocate decoder in %s", __PRETTY_FUNCTION__);
+ goto bailout;
+ }
+
+ // Fire up the pump thread. It will take care of starting and stopping the
+ // decoder.
+ ret_val = thread_->run("aah_decode_pump", ANDROID_PRIORITY_AUDIO);
+ if (OK != ret_val) {
+ ALOGE("Failed to start work thread in %s (res = %d)",
+ __PRETTY_FUNCTION__, ret_val);
+ goto bailout;
+ }
+
+bailout:
+ if (OK != ret_val) {
+ decoder_ = NULL;
+ format_ = NULL;
+ }
+
+ return OK;
+}
+
+status_t AAH_DecoderPump::shutdown() {
+ Mutex::Autolock lock(&init_lock_);
+ return shutdown_l();
+}
+
+status_t AAH_DecoderPump::shutdown_l() {
+ thread_->requestExit();
+ thread_cond_.signal();
+ thread_->requestExitAndWait();
+
+ for (MBQueue::iterator iter = in_queue_.begin();
+ iter != in_queue_.end();
+ ++iter) {
+ (*iter)->release();
+ }
+ in_queue_.clear();
+
+ last_queued_pts_valid_ = false;
+ last_ts_transform_valid_ = false;
+ last_volume_ = 0xFF;
+ thread_status_ = OK;
+
+ decoder_ = NULL;
+ format_ = NULL;
+
+ return OK;
+}
+
+status_t AAH_DecoderPump::read(MediaBuffer **buffer,
+ const ReadOptions *options) {
+ if (!buffer) {
+ return BAD_VALUE;
+ }
+
+ *buffer = NULL;
+
+ // While its not time to shut down, and we have no data to process, wait.
+ AutoMutex lock(&thread_lock_);
+ while (!thread_->exitPending() && in_queue_.empty())
+ thread_cond_.wait(thread_lock_);
+
+ // At this point, if its not time to shutdown then we must have something to
+ // process. Go ahead and pop the front of the queue for processing.
+ if (!thread_->exitPending()) {
+ CHECK(!in_queue_.empty());
+
+ *buffer = *(in_queue_.begin());
+ in_queue_.erase(in_queue_.begin());
+ }
+
+ // If we managed to get a buffer, then everything must be OK. If not, then
+ // we must be shutting down.
+ return (NULL == *buffer) ? INVALID_OPERATION : OK;
+}
+
+AAH_DecoderPump::ThreadWrapper::ThreadWrapper(AAH_DecoderPump* owner)
+ : Thread(false /* canCallJava*/ )
+ , owner_(owner) {
+}
+
+bool AAH_DecoderPump::ThreadWrapper::threadLoop() {
+ CHECK(NULL != owner_);
+ owner_->workThread();
+ return false;
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_decoder_pump.h b/media/libaah_rtp/aah_decoder_pump.h
new file mode 100644
index 0000000..f5a6529
--- /dev/null
+++ b/media/libaah_rtp/aah_decoder_pump.h
@@ -0,0 +1,107 @@
+/*
+ * 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 __DECODER_PUMP_H__
+#define __DECODER_PUMP_H__
+
+#include <pthread.h>
+
+#include <common_time/cc_helper.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/LinearTransform.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MetaData;
+class OMXClient;
+class TimedAudioTrack;
+
+class AAH_DecoderPump : public MediaSource {
+ public:
+ explicit AAH_DecoderPump(OMXClient& omx);
+ status_t initCheck();
+
+ status_t queueForDecode(MediaBuffer* buf);
+
+ status_t init(const sp<MetaData>& params);
+ status_t shutdown();
+
+ void setRenderTSTransform(const LinearTransform& trans);
+ void setRenderVolume(uint8_t volume);
+ bool isAboutToUnderflow(int64_t threshold);
+ bool getStatus() const { return thread_status_; }
+
+ // MediaSource methods
+ virtual status_t start(MetaData *params) { return OK; }
+ virtual sp<MetaData> getFormat() { return format_; }
+ virtual status_t stop() { return OK; }
+ virtual status_t read(MediaBuffer **buffer,
+ const ReadOptions *options);
+
+ protected:
+ virtual ~AAH_DecoderPump();
+
+ private:
+ class ThreadWrapper : public Thread {
+ public:
+ friend class AAH_DecoderPump;
+ explicit ThreadWrapper(AAH_DecoderPump* owner);
+
+ private:
+ virtual bool threadLoop();
+ AAH_DecoderPump* owner_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
+ };
+
+ void* workThread();
+ virtual status_t shutdown_l();
+ void queueToRenderer(MediaBuffer* decoded_sample);
+ void stopAndCleanupRenderer();
+
+ sp<MetaData> format_;
+ int32_t format_channels_;
+ int32_t format_sample_rate_;
+
+ sp<MediaSource> decoder_;
+ OMXClient& omx_;
+ Mutex init_lock_;
+
+ sp<ThreadWrapper> thread_;
+ Condition thread_cond_;
+ Mutex thread_lock_;
+ status_t thread_status_;
+
+ Mutex render_lock_;
+ TimedAudioTrack* renderer_;
+ bool last_queued_pts_valid_;
+ int64_t last_queued_pts_;
+ bool last_ts_transform_valid_;
+ LinearTransform last_ts_transform_;
+ uint8_t last_volume_;
+ CCHelper cc_helper_;
+
+ // protected by the thread_lock_
+ typedef List<MediaBuffer*> MBQueue;
+ MBQueue in_queue_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AAH_DecoderPump);
+};
+
+} // namespace android
+#endif // __DECODER_PUMP_H__
diff --git a/media/libaah_rtp/aah_rx_player.cpp b/media/libaah_rtp/aah_rx_player.cpp
new file mode 100644
index 0000000..9dd79fd
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+
+#include <binder/IServiceManager.h>
+#include <media/MediaPlayerInterface.h>
+#include <utils/Log.h>
+
+#include "aah_rx_player.h"
+
+namespace android {
+
+const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10;
+
+sp<MediaPlayerBase> createAAH_RXPlayer() {
+ sp<MediaPlayerBase> ret = new AAH_RXPlayer();
+ return ret;
+}
+
+AAH_RXPlayer::AAH_RXPlayer()
+ : ring_buffer_(kRTPRingBufferSize)
+ , substreams_(NULL) {
+ thread_wrapper_ = new ThreadWrapper(*this);
+
+ is_playing_ = false;
+ multicast_joined_ = false;
+ transmitter_known_ = false;
+ current_epoch_known_ = false;
+ data_source_set_ = false;
+ sock_fd_ = -1;
+
+ substreams_.setCapacity(4);
+
+ memset(&listen_addr_, 0, sizeof(listen_addr_));
+ memset(&transmitter_addr_, 0, sizeof(transmitter_addr_));
+
+ fetchAudioFlinger();
+}
+
+AAH_RXPlayer::~AAH_RXPlayer() {
+ reset_l();
+ CHECK(substreams_.size() == 0);
+ omx_.disconnect();
+}
+
+status_t AAH_RXPlayer::initCheck() {
+ if (thread_wrapper_ == NULL) {
+ ALOGE("Failed to allocate thread wrapper!");
+ return NO_MEMORY;
+ }
+
+ if (!ring_buffer_.initCheck()) {
+ ALOGE("Failed to allocate reassembly ring buffer!");
+ return NO_MEMORY;
+ }
+
+ // Check for the presense of the common time service by attempting to query
+ // for CommonTime's frequency. If we get an error back, we cannot talk to
+ // the service at all and should abort now.
+ status_t res;
+ uint64_t freq;
+ res = cc_helper_.getCommonFreq(&freq);
+ if (OK != res) {
+ ALOGE("Failed to connect to common time service!");
+ return res;
+ }
+
+ return omx_.connect();
+}
+
+status_t AAH_RXPlayer::setDataSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers) {
+ AutoMutex api_lock(&api_lock_);
+ uint32_t a, b, c, d;
+ uint16_t port;
+
+ if (data_source_set_) {
+ return INVALID_OPERATION;
+ }
+
+ if (NULL == url) {
+ return BAD_VALUE;
+ }
+
+ if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) {
+ ALOGE("Failed to parse URL \"%s\"", url);
+ return BAD_VALUE;
+ }
+
+ if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) {
+ ALOGE("Bad multicast address \"%s\"", url);
+ return BAD_VALUE;
+ }
+
+ ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port);
+
+ a = (a << 24) | (b << 16) | (c << 8) | d;
+
+ memset(&listen_addr_, 0, sizeof(listen_addr_));
+ listen_addr_.sin_family = AF_INET;
+ listen_addr_.sin_port = htons(port);
+ listen_addr_.sin_addr.s_addr = htonl(a);
+ data_source_set_ = true;
+
+ return OK;
+}
+
+status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+ return INVALID_OPERATION;
+}
+
+status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) {
+ return OK;
+}
+
+status_t AAH_RXPlayer::setVideoSurfaceTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ return OK;
+}
+
+status_t AAH_RXPlayer::prepare() {
+ return OK;
+}
+
+status_t AAH_RXPlayer::prepareAsync() {
+ sendEvent(MEDIA_PREPARED);
+ return OK;
+}
+
+status_t AAH_RXPlayer::start() {
+ AutoMutex api_lock(&api_lock_);
+
+ if (is_playing_) {
+ return OK;
+ }
+
+ status_t res = startWorkThread();
+ is_playing_ = (res == OK);
+ return res;
+}
+
+status_t AAH_RXPlayer::stop() {
+ return pause();
+}
+
+status_t AAH_RXPlayer::pause() {
+ AutoMutex api_lock(&api_lock_);
+ stopWorkThread();
+ CHECK(sock_fd_ < 0);
+ is_playing_ = false;
+ return OK;
+}
+
+bool AAH_RXPlayer::isPlaying() {
+ AutoMutex api_lock(&api_lock_);
+ return is_playing_;
+}
+
+status_t AAH_RXPlayer::seekTo(int msec) {
+ sendEvent(MEDIA_SEEK_COMPLETE);
+ return OK;
+}
+
+status_t AAH_RXPlayer::getCurrentPosition(int *msec) {
+ if (NULL != msec) {
+ *msec = 0;
+ }
+ return OK;
+}
+
+status_t AAH_RXPlayer::getDuration(int *msec) {
+ if (NULL != msec) {
+ *msec = 1;
+ }
+ return OK;
+}
+
+status_t AAH_RXPlayer::reset() {
+ AutoMutex api_lock(&api_lock_);
+ reset_l();
+ return OK;
+}
+
+void AAH_RXPlayer::reset_l() {
+ stopWorkThread();
+ CHECK(sock_fd_ < 0);
+ CHECK(!multicast_joined_);
+ is_playing_ = false;
+ data_source_set_ = false;
+ transmitter_known_ = false;
+ memset(&listen_addr_, 0, sizeof(listen_addr_));
+}
+
+status_t AAH_RXPlayer::setLooping(int loop) {
+ return OK;
+}
+
+player_type AAH_RXPlayer::playerType() {
+ return AAH_RX_PLAYER;
+}
+
+status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) {
+ if (!reply) {
+ return BAD_VALUE;
+ }
+
+ int32_t magic;
+ status_t err = request.readInt32(&magic);
+ if (err != OK) {
+ reply->writeInt32(err);
+ return OK;
+ }
+
+ if (magic != 0x12345) {
+ reply->writeInt32(BAD_VALUE);
+ return OK;
+ }
+
+ int32_t methodID;
+ err = request.readInt32(&methodID);
+ if (err != OK) {
+ reply->writeInt32(err);
+ return OK;
+ }
+
+ switch (methodID) {
+ // Get Volume
+ case INVOKE_GET_MASTER_VOLUME: {
+ if (audio_flinger_ != NULL) {
+ reply->writeInt32(OK);
+ reply->writeFloat(audio_flinger_->masterVolume());
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
+ }
+ } break;
+
+ // Set Volume
+ case INVOKE_SET_MASTER_VOLUME: {
+ float targetVol = request.readFloat();
+ reply->writeInt32(audio_flinger_->setMasterVolume(targetVol));
+ } break;
+
+ default: return BAD_VALUE;
+ }
+
+ return OK;
+}
+
+void AAH_RXPlayer::fetchAudioFlinger() {
+ if (audio_flinger_ == NULL) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ binder = sm->getService(String16("media.audio_flinger"));
+
+ if (binder == NULL) {
+ ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger."
+ " Master volume control will not be possible.");
+ }
+
+ audio_flinger_ = interface_cast<IAudioFlinger>(binder);
+ }
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h
new file mode 100644
index 0000000..7a1b6e3
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player.h
@@ -0,0 +1,313 @@
+/*
+ * 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 __AAH_RX_PLAYER_H__
+#define __AAH_RX_PLAYER_H__
+
+#include <common_time/cc_helper.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <netinet/in.h>
+#include <utils/KeyedVector.h>
+#include <utils/LinearTransform.h>
+#include <utils/threads.h>
+
+#include "aah_decoder_pump.h"
+#include "pipe_event.h"
+
+namespace android {
+
+class AAH_RXPlayer : public MediaPlayerInterface {
+ public:
+ AAH_RXPlayer();
+
+ virtual status_t initCheck();
+ virtual status_t setDataSource(const char *url,
+ const KeyedVector<String8, String8>*
+ headers);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setVideoSurface(const sp<Surface>& surface);
+ virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>&
+ surfaceTexture);
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t seekTo(int msec);
+ virtual status_t getCurrentPosition(int *msec);
+ virtual status_t getDuration(int *msec);
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType();
+ virtual status_t setParameter(int key, const Parcel &request);
+ virtual status_t getParameter(int key, Parcel *reply);
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+
+ protected:
+ virtual ~AAH_RXPlayer();
+
+ private:
+ class ThreadWrapper : public Thread {
+ public:
+ friend class AAH_RXPlayer;
+ explicit ThreadWrapper(AAH_RXPlayer& player)
+ : Thread(false /* canCallJava */ )
+ , player_(player) { }
+
+ virtual bool threadLoop() { return player_.threadLoop(); }
+
+ private:
+ AAH_RXPlayer& player_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
+ };
+
+#pragma pack(push, 1)
+ // PacketBuffers are structures used by the RX ring buffer. The ring buffer
+ // is a ring of pointers to PacketBuffer structures which act as variable
+ // length byte arrays and hold the contents of received UDP packets. Rather
+ // than make this a structure which hold a length and a pointer to another
+ // allocated structure (which would require two allocations), this struct
+ // uses a structure overlay pattern where allocation for the byte array
+ // consists of allocating (arrayLen + sizeof(ssize_t)) bytes of data from
+ // whatever pool/heap the packet buffer pulls from, and then overlaying the
+ // packed PacketBuffer structure on top of the allocation. The one-byte
+ // array at the end of the structure serves as an offset to the the data
+ // portion of the allocation; packet buffers are never allocated on the
+ // stack or using the new operator. Instead, the static allocate-byte-array
+ // and destroy methods handle the allocate and overlay pattern. They also
+ // allow for a potential future optimization where instead of just
+ // allocating blocks from the process global heap and overlaying, the
+ // allocator is replaced with a different implementation (private heap,
+ // free-list, circular buffer, etc) which reduces potential heap
+ // fragmentation issues which might arise from the frequent allocation and
+ // destruction of the received UDP traffic.
+ struct PacketBuffer {
+ ssize_t length_;
+ uint8_t data_[1];
+
+ // TODO : consider changing this to be some form of ring buffer or free
+ // pool system instead of just using the heap in order to avoid heap
+ // fragmentation.
+ static PacketBuffer* allocate(ssize_t length);
+ static void destroy(PacketBuffer* pb);
+
+ private:
+ // Force people to use allocate/destroy instead of new/delete.
+ PacketBuffer() { }
+ ~PacketBuffer() { }
+ };
+
+ struct RetransRequest {
+ uint32_t magic_;
+ uint32_t mcast_ip_;
+ uint16_t mcast_port_;
+ uint16_t start_seq_;
+ uint16_t end_seq_;
+ };
+#pragma pack(pop)
+
+ enum GapStatus {
+ kGS_NoGap = 0,
+ kGS_NormalGap,
+ kGS_FastStartGap,
+ };
+
+ struct SeqNoGap {
+ uint16_t start_seq_;
+ uint16_t end_seq_;
+ };
+
+ class RXRingBuffer {
+ public:
+ explicit RXRingBuffer(uint32_t capacity);
+ ~RXRingBuffer();
+
+ bool initCheck() const { return (ring_ != NULL); }
+ void reset();
+
+ // Push a packet buffer with a given sequence number into the ring
+ // buffer. pushBuffer will always consume the buffer pushed to it,
+ // either destroying it because it was a duplicate or overflow, or
+ // holding on to it in the ring. Callers should not hold any references
+ // to PacketBuffers after they have been pushed to the ring. Returns
+ // false in the case of a serious error (such as ring overflow).
+ // Callers should consider resetting the pipeline entirely in the event
+ // of a serious error.
+ bool pushBuffer(PacketBuffer* buf, uint16_t seq);
+
+ // Fetch the next buffer in the RTP sequence. Returns NULL if there is
+ // no buffer to fetch. If a non-NULL PacketBuffer is returned,
+ // is_discon will be set to indicate whether or not this PacketBuffer is
+ // discontiuous with any previously returned packet buffers. Packet
+ // buffers returned by fetchBuffer are the caller's responsibility; they
+ // must be certain to destroy the buffers when they are done.
+ PacketBuffer* fetchBuffer(bool* is_discon);
+
+ // Returns true and fills out the gap structure if the read pointer of
+ // the ring buffer is currently pointing to a gap which would stall a
+ // fetchBuffer operation. Returns false if the read pointer is not
+ // pointing to a gap in the sequence currently.
+ GapStatus fetchCurrentGap(SeqNoGap* gap);
+
+ // Causes the read pointer to skip over any portion of a gap indicated
+ // by nak. If nak is NULL, any gap currently blocking the read pointer
+ // will be completely skipped. If any portion of a gap is skipped, the
+ // next successful read from fetch buffer will indicate a discontinuity.
+ void processNAK(const SeqNoGap* nak = NULL);
+
+ // Compute the number of milliseconds until the inactivity timer for
+ // this RTP stream. Returns -1 if there is no active timeout, or 0 if
+ // the system has already timed out.
+ int computeInactivityTimeout();
+
+ private:
+ Mutex lock_;
+ PacketBuffer** ring_;
+ uint32_t capacity_;
+ uint32_t rd_;
+ uint32_t wr_;
+
+ uint16_t rd_seq_;
+ bool rd_seq_known_;
+ bool waiting_for_fast_start_;
+ bool fetched_first_packet_;
+
+ uint64_t rtp_activity_timeout_;
+ bool rtp_activity_timeout_valid_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RXRingBuffer);
+ };
+
+ class Substream : public virtual RefBase {
+ public:
+ Substream(uint32_t ssrc, OMXClient& omx);
+
+ void cleanupBufferInProgress();
+ void shutdown();
+ void processPayloadStart(uint8_t* buf,
+ uint32_t amt,
+ int32_t ts_lower);
+ void processPayloadCont (uint8_t* buf,
+ uint32_t amt);
+ void processTSTransform(const LinearTransform& trans);
+
+ bool isAboutToUnderflow();
+ uint32_t getSSRC() const { return ssrc_; }
+ uint16_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; }
+ status_t getStatus() const { return status_; }
+
+ protected:
+ virtual ~Substream() {
+ shutdown();
+ }
+
+ private:
+ void cleanupDecoder();
+ bool shouldAbort(const char* log_tag);
+ void processCompletedBuffer();
+ bool setupSubstreamType(uint8_t substream_type,
+ uint8_t codec_type);
+
+ uint32_t ssrc_;
+ bool waiting_for_rap_;
+ status_t status_;
+
+ bool substream_details_known_;
+ uint8_t substream_type_;
+ uint8_t codec_type_;
+ sp<MetaData> substream_meta_;
+
+ MediaBuffer* buffer_in_progress_;
+ uint32_t expected_buffer_size_;
+ uint32_t buffer_filled_;
+
+ sp<AAH_DecoderPump> decoder_;
+
+ static int64_t kAboutToUnderflowThreshold;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Substream);
+ };
+
+ typedef DefaultKeyedVector< uint32_t, sp<Substream> > SubstreamVec;
+
+ status_t startWorkThread();
+ void stopWorkThread();
+ virtual bool threadLoop();
+ bool setupSocket();
+ void cleanupSocket();
+ void resetPipeline();
+ void reset_l();
+ bool processRX(PacketBuffer* pb);
+ void processRingBuffer();
+ void processCommandPacket(PacketBuffer* pb);
+ bool processGaps();
+ int computeNextGapRetransmitTimeout();
+ void fetchAudioFlinger();
+
+ PipeEvent wakeup_work_thread_evt_;
+ sp<ThreadWrapper> thread_wrapper_;
+ Mutex api_lock_;
+ bool is_playing_;
+ bool data_source_set_;
+
+ struct sockaddr_in listen_addr_;
+ int sock_fd_;
+ bool multicast_joined_;
+
+ struct sockaddr_in transmitter_addr_;
+ bool transmitter_known_;
+
+ uint32_t current_epoch_;
+ bool current_epoch_known_;
+
+ SeqNoGap current_gap_;
+ GapStatus current_gap_status_;
+ uint64_t next_retrans_req_time_;
+
+ RXRingBuffer ring_buffer_;
+ SubstreamVec substreams_;
+ OMXClient omx_;
+ CCHelper cc_helper_;
+
+ // Connection to audio flinger used to hack a path to setMasterVolume.
+ sp<IAudioFlinger> audio_flinger_;
+
+ static const uint32_t kRTPRingBufferSize;
+ static const uint32_t kRetransRequestMagic;
+ static const uint32_t kFastStartRequestMagic;
+ static const uint32_t kRetransNAKMagic;
+ static const uint32_t kGapRerequestTimeoutUSec;
+ static const uint32_t kFastStartTimeoutUSec;
+ static const uint32_t kRTPActivityTimeoutUSec;
+
+ static const uint32_t INVOKE_GET_MASTER_VOLUME = 3;
+ static const uint32_t INVOKE_SET_MASTER_VOLUME = 4;
+
+ static uint64_t monotonicUSecNow();
+
+ DISALLOW_EVIL_CONSTRUCTORS(AAH_RXPlayer);
+};
+
+} // namespace android
+
+#endif // __AAH_RX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_rx_player_core.cpp b/media/libaah_rtp/aah_rx_player_core.cpp
new file mode 100644
index 0000000..d2b3386
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player_core.cpp
@@ -0,0 +1,807 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <utils/misc.h>
+
+#include <media/stagefright/Utils.h>
+
+#include "aah_rx_player.h"
+#include "aah_tx_packet.h"
+
+namespace android {
+
+const uint32_t AAH_RXPlayer::kRetransRequestMagic =
+ FOURCC('T','r','e','q');
+const uint32_t AAH_RXPlayer::kRetransNAKMagic =
+ FOURCC('T','n','a','k');
+const uint32_t AAH_RXPlayer::kFastStartRequestMagic =
+ FOURCC('T','f','s','t');
+const uint32_t AAH_RXPlayer::kGapRerequestTimeoutUSec = 75000;
+const uint32_t AAH_RXPlayer::kFastStartTimeoutUSec = 800000;
+const uint32_t AAH_RXPlayer::kRTPActivityTimeoutUSec = 10000000;
+
+static inline int16_t fetchInt16(uint8_t* data) {
+ return static_cast<int16_t>(U16_AT(data));
+}
+
+static inline int32_t fetchInt32(uint8_t* data) {
+ return static_cast<int32_t>(U32_AT(data));
+}
+
+static inline int64_t fetchInt64(uint8_t* data) {
+ return static_cast<int64_t>(U64_AT(data));
+}
+
+uint64_t AAH_RXPlayer::monotonicUSecNow() {
+ struct timespec now;
+ int res = clock_gettime(CLOCK_MONOTONIC, &now);
+ CHECK(res >= 0);
+
+ uint64_t ret = static_cast<uint64_t>(now.tv_sec) * 1000000;
+ ret += now.tv_nsec / 1000;
+
+ return ret;
+}
+
+status_t AAH_RXPlayer::startWorkThread() {
+ status_t res;
+ stopWorkThread();
+ res = thread_wrapper_->run("TRX_Player", PRIORITY_AUDIO);
+
+ if (res != OK) {
+ ALOGE("Failed to start work thread (res = %d)", res);
+ }
+
+ return res;
+}
+
+void AAH_RXPlayer::stopWorkThread() {
+ thread_wrapper_->requestExit(); // set the exit pending flag
+ wakeup_work_thread_evt_.setEvent();
+
+ status_t res;
+ res = thread_wrapper_->requestExitAndWait(); // block until thread exit.
+ if (res != OK) {
+ ALOGE("Failed to stop work thread (res = %d)", res);
+ }
+
+ wakeup_work_thread_evt_.clearPendingEvents();
+}
+
+void AAH_RXPlayer::cleanupSocket() {
+ if (sock_fd_ >= 0) {
+ if (multicast_joined_) {
+ int res;
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = listen_addr_.sin_addr;
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ res = setsockopt(sock_fd_,
+ IPPROTO_IP,
+ IP_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq));
+ if (res < 0) {
+ ALOGW("Failed to leave multicast group. (%d, %d)", res, errno);
+ }
+ multicast_joined_ = false;
+ }
+
+ close(sock_fd_);
+ sock_fd_ = -1;
+ }
+
+ resetPipeline();
+}
+
+void AAH_RXPlayer::resetPipeline() {
+ ring_buffer_.reset();
+
+ // Explicitly shudown all of the active substreams, then call clear out the
+ // collection. Failure to clear out a substream can result in its decoder
+ // holding a reference to itself and therefor not going away when the
+ // collection is cleared.
+ for (size_t i = 0; i < substreams_.size(); ++i)
+ substreams_.valueAt(i)->shutdown();
+
+ substreams_.clear();
+
+ current_gap_status_ = kGS_NoGap;
+}
+
+bool AAH_RXPlayer::setupSocket() {
+ long flags;
+ int res, buf_size;
+ socklen_t opt_size;
+
+ cleanupSocket();
+ CHECK(sock_fd_ < 0);
+
+ // Make the socket
+ sock_fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock_fd_ < 0) {
+ ALOGE("Failed to create listen socket (errno %d)", errno);
+ goto bailout;
+ }
+
+ // Set non-blocking operation
+ flags = fcntl(sock_fd_, F_GETFL);
+ res = fcntl(sock_fd_, F_SETFL, flags | O_NONBLOCK);
+ if (res < 0) {
+ ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
+ sock_fd_, errno);
+ goto bailout;
+ }
+
+ // Bind to our port
+ struct sockaddr_in bind_addr;
+ memset(&bind_addr, 0, sizeof(bind_addr));
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ bind_addr.sin_port = listen_addr_.sin_port;
+ res = bind(sock_fd_,
+ reinterpret_cast<const sockaddr*>(&bind_addr),
+ sizeof(bind_addr));
+ if (res < 0) {
+ uint32_t a = ntohl(bind_addr.sin_addr.s_addr);
+ uint16_t p = ntohs(bind_addr.sin_port);
+ ALOGE("Failed to bind socket (%d) to %d.%d.%d.%d:%hd. (errno %d)",
+ sock_fd_,
+ (a >> 24) & 0xFF,
+ (a >> 16) & 0xFF,
+ (a >> 8) & 0xFF,
+ (a ) & 0xFF,
+ p,
+ errno);
+
+ goto bailout;
+ }
+
+ buf_size = 1 << 16; // 64k
+ res = setsockopt(sock_fd_,
+ SOL_SOCKET, SO_RCVBUF,
+ &buf_size, sizeof(buf_size));
+ if (res < 0) {
+ ALOGW("Failed to increase socket buffer size to %d. (errno %d)",
+ buf_size, errno);
+ }
+
+ buf_size = 0;
+ opt_size = sizeof(buf_size);
+ res = getsockopt(sock_fd_,
+ SOL_SOCKET, SO_RCVBUF,
+ &buf_size, &opt_size);
+ if (res < 0) {
+ ALOGW("Failed to fetch socket buffer size. (errno %d)", errno);
+ } else {
+ ALOGI("RX socket buffer size is now %d bytes", buf_size);
+ }
+
+ if (listen_addr_.sin_addr.s_addr) {
+ // Join the multicast group and we should be good to go.
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = listen_addr_.sin_addr;
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ res = setsockopt(sock_fd_,
+ IPPROTO_IP,
+ IP_ADD_MEMBERSHIP,
+ &mreq, sizeof(mreq));
+ if (res < 0) {
+ ALOGE("Failed to join multicast group. (errno %d)", errno);
+ goto bailout;
+ }
+ multicast_joined_ = true;
+ }
+
+ return true;
+
+bailout:
+ cleanupSocket();
+ return false;
+}
+
+bool AAH_RXPlayer::threadLoop() {
+ struct pollfd poll_fds[2];
+ bool process_more_right_now = false;
+
+ if (!setupSocket()) {
+ sendEvent(MEDIA_ERROR);
+ goto bailout;
+ }
+
+ while (!thread_wrapper_->exitPending()) {
+ // Step 1: Wait until there is something to do.
+ int gap_timeout = computeNextGapRetransmitTimeout();
+ int ring_timeout = ring_buffer_.computeInactivityTimeout();
+ int timeout = -1;
+
+ if (!ring_timeout) {
+ ALOGW("RTP inactivity timeout reached, resetting pipeline.");
+ resetPipeline();
+ timeout = gap_timeout;
+ } else {
+ if (gap_timeout < 0) {
+ timeout = ring_timeout;
+ } else if (ring_timeout < 0) {
+ timeout = gap_timeout;
+ } else {
+ timeout = (gap_timeout < ring_timeout) ? gap_timeout
+ : ring_timeout;
+ }
+ }
+
+ if ((0 != timeout) && (!process_more_right_now)) {
+ // Set up the events to wait on. Start with the wakeup pipe.
+ memset(&poll_fds, 0, sizeof(poll_fds));
+ poll_fds[0].fd = wakeup_work_thread_evt_.getWakeupHandle();
+ poll_fds[0].events = POLLIN;
+
+ // Add the RX socket.
+ poll_fds[1].fd = sock_fd_;
+ poll_fds[1].events = POLLIN;
+
+ // Wait for something interesing to happen.
+ int poll_res = poll(poll_fds, NELEM(poll_fds), timeout);
+ if (poll_res < 0) {
+ ALOGE("Fatal error (%d,%d) while waiting on events",
+ poll_res, errno);
+ sendEvent(MEDIA_ERROR);
+ goto bailout;
+ }
+ }
+
+ if (thread_wrapper_->exitPending()) {
+ break;
+ }
+
+ wakeup_work_thread_evt_.clearPendingEvents();
+ process_more_right_now = false;
+
+ // Step 2: Do we have data waiting in the socket? If so, drain the
+ // socket moving valid RTP information into the ring buffer to be
+ // processed.
+ if (poll_fds[1].revents) {
+ struct sockaddr_in from;
+ socklen_t from_len;
+
+ ssize_t res = 0;
+ while (!thread_wrapper_->exitPending()) {
+ // Check the size of any pending packet.
+ res = recv(sock_fd_, NULL, 0, MSG_PEEK | MSG_TRUNC);
+
+ // Error?
+ if (res < 0) {
+ // If the error is anything other than would block,
+ // something has gone very wrong.
+ if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
+ ALOGE("Fatal socket error during recvfrom (%d, %d)",
+ (int)res, errno);
+ goto bailout;
+ }
+
+ // Socket is out of data, just break out of processing and
+ // wait for more.
+ break;
+ }
+
+ // Allocate a payload.
+ PacketBuffer* pb = PacketBuffer::allocate(res);
+ if (NULL == pb) {
+ ALOGE("Fatal error, failed to allocate packet buffer of"
+ " length %u", static_cast<uint32_t>(res));
+ goto bailout;
+ }
+
+ // Fetch the data.
+ from_len = sizeof(from);
+ res = recvfrom(sock_fd_, pb->data_, pb->length_, 0,
+ reinterpret_cast<struct sockaddr*>(&from),
+ &from_len);
+ if (res != pb->length_) {
+ ALOGE("Fatal error, fetched packet length (%d) does not"
+ " match peeked packet length (%u). This should never"
+ " happen. (errno = %d)",
+ static_cast<int>(res),
+ static_cast<uint32_t>(pb->length_),
+ errno);
+ }
+
+ bool drop_packet = false;
+ if (transmitter_known_) {
+ if (from.sin_addr.s_addr !=
+ transmitter_addr_.sin_addr.s_addr) {
+ uint32_t a = ntohl(from.sin_addr.s_addr);
+ uint16_t p = ntohs(from.sin_port);
+ ALOGV("Dropping packet from unknown transmitter"
+ " %u.%u.%u.%u:%hu",
+ ((a >> 24) & 0xFF),
+ ((a >> 16) & 0xFF),
+ ((a >> 8) & 0xFF),
+ ( a & 0xFF),
+ p);
+
+ drop_packet = true;
+ } else {
+ transmitter_addr_.sin_port = from.sin_port;
+ }
+ } else {
+ memcpy(&transmitter_addr_, &from, sizeof(from));
+ transmitter_known_ = true;
+ }
+
+ if (!drop_packet) {
+ bool serious_error = !processRX(pb);
+
+ if (serious_error) {
+ // Something went "seriously wrong". Currently, the
+ // only trigger for this should be a ring buffer
+ // overflow. The current failsafe behavior for when
+ // something goes seriously wrong is to just reset the
+ // pipeline. The system should behave as if this
+ // AAH_RXPlayer was just set up for the first time.
+ ALOGE("Something just went seriously wrong with the"
+ " pipeline. Resetting.");
+ resetPipeline();
+ }
+ } else {
+ PacketBuffer::destroy(pb);
+ }
+ }
+ }
+
+ // Step 3: Process any data we mave have accumulated in the ring buffer
+ // so far.
+ if (!thread_wrapper_->exitPending()) {
+ processRingBuffer();
+ }
+
+ // Step 4: At this point in time, the ring buffer should either be
+ // empty, or stalled in front of a gap caused by some dropped packets.
+ // Check on the current gap situation and deal with it in an appropriate
+ // fashion. If processGaps returns true, it means that it has given up
+ // on a gap and that we should try to process some more data
+ // immediately.
+ if (!thread_wrapper_->exitPending()) {
+ process_more_right_now = processGaps();
+ }
+
+ // Step 5: Check for fatal errors. If any of our substreams has
+ // encountered a fatal, unrecoverable, error, then propagate the error
+ // up to user level and shut down.
+ for (size_t i = 0; i < substreams_.size(); ++i) {
+ status_t status;
+ CHECK(substreams_.valueAt(i) != NULL);
+
+ status = substreams_.valueAt(i)->getStatus();
+ if (OK != status) {
+ ALOGE("Substream index %d has encountered an unrecoverable"
+ " error (%d). Signalling application level and shutting"
+ " down.", i, status);
+ sendEvent(MEDIA_ERROR);
+ goto bailout;
+ }
+ }
+ }
+
+bailout:
+ cleanupSocket();
+ return false;
+}
+
+bool AAH_RXPlayer::processRX(PacketBuffer* pb) {
+ CHECK(NULL != pb);
+
+ uint8_t* data = pb->data_;
+ ssize_t amt = pb->length_;
+ uint32_t nak_magic;
+ uint16_t seq_no;
+ uint32_t epoch;
+
+ // Every packet either starts with an RTP header which is at least 12 bytes
+ // long or is a retry NAK which is 14 bytes long. If there are fewer than
+ // 12 bytes here, this cannot be a proper RTP packet.
+ if (amt < 12) {
+ ALOGV("Dropping packet, too short to contain RTP header (%u bytes)",
+ static_cast<uint32_t>(amt));
+ goto drop_packet;
+ }
+
+ // Check to see if this is the special case of a NAK packet.
+ nak_magic = ntohl(*(reinterpret_cast<uint32_t*>(data)));
+ if (nak_magic == kRetransNAKMagic) {
+ // Looks like a NAK packet; make sure its long enough.
+
+ if (amt < static_cast<ssize_t>(sizeof(RetransRequest))) {
+ ALOGV("Dropping packet, too short to contain NAK payload (%u bytes)",
+ static_cast<uint32_t>(amt));
+ goto drop_packet;
+ }
+
+ SeqNoGap gap;
+ RetransRequest* rtr = reinterpret_cast<RetransRequest*>(data);
+ gap.start_seq_ = ntohs(rtr->start_seq_);
+ gap.end_seq_ = ntohs(rtr->end_seq_);
+
+ ALOGV("Process NAK for gap at [%hu, %hu]", gap.start_seq_, gap.end_seq_);
+ ring_buffer_.processNAK(&gap);
+
+ return true;
+ }
+
+ // According to the TRTP spec, version should be 2, padding should be 0,
+ // extension should be 0 and CSRCCnt should be 0. If any of these tests
+ // fail, we chuck the packet.
+ if (data[0] != 0x80) {
+ ALOGV("Dropping packet, bad V/P/X/CSRCCnt field (0x%02x)",
+ data[0]);
+ goto drop_packet;
+ }
+
+ // Check the payload type. For TRTP, it should always be 100.
+ if ((data[1] & 0x7F) != 100) {
+ ALOGV("Dropping packet, bad payload type. (%u)",
+ data[1] & 0x7F);
+ goto drop_packet;
+ }
+
+ // Check whether the transmitter has begun a new epoch.
+ epoch = (U32_AT(data + 8) >> 10) & 0x3FFFFF;
+ if (current_epoch_known_) {
+ if (epoch != current_epoch_) {
+ ALOGV("%s: new epoch %u", __PRETTY_FUNCTION__, epoch);
+ current_epoch_ = epoch;
+ resetPipeline();
+ }
+ } else {
+ current_epoch_ = epoch;
+ current_epoch_known_ = true;
+ }
+
+ // Extract the sequence number and hand the packet off to the ring buffer
+ // for dropped packet detection and later processing.
+ seq_no = U16_AT(data + 2);
+ return ring_buffer_.pushBuffer(pb, seq_no);
+
+drop_packet:
+ PacketBuffer::destroy(pb);
+ return true;
+}
+
+void AAH_RXPlayer::processRingBuffer() {
+ PacketBuffer* pb;
+ bool is_discon;
+ sp<Substream> substream;
+ LinearTransform trans;
+ bool foundTrans = false;
+
+ while (NULL != (pb = ring_buffer_.fetchBuffer(&is_discon))) {
+ if (is_discon) {
+ // Abort all partially assembled payloads.
+ for (size_t i = 0; i < substreams_.size(); ++i) {
+ CHECK(substreams_.valueAt(i) != NULL);
+ substreams_.valueAt(i)->cleanupBufferInProgress();
+ }
+ }
+
+ uint8_t* data = pb->data_;
+ ssize_t amt = pb->length_;
+
+ // Should not have any non-RTP packets in the ring buffer. RTP packets
+ // must be at least 12 bytes long.
+ CHECK(amt >= 12);
+
+ // Extract the marker bit and the SSRC field.
+ bool marker = (data[1] & 0x80) != 0;
+ uint32_t ssrc = U32_AT(data + 8);
+
+ // Is this the start of a new TRTP payload? If so, the marker bit
+ // should be set and there are some things we should be checking for.
+ if (marker) {
+ // TRTP headers need to have at least a byte for version, a byte for
+ // payload type and flags, and 4 bytes for length.
+ if (amt < 18) {
+ ALOGV("Dropping packet, too short to contain TRTP header"
+ " (%u bytes)", static_cast<uint32_t>(amt));
+ goto process_next_packet;
+ }
+
+ // Check the TRTP version and extract the payload type/flags.
+ uint8_t trtp_version = data[12];
+ uint8_t payload_type = (data[13] >> 4) & 0xF;
+ uint8_t trtp_flags = data[13] & 0xF;
+
+ if (1 != trtp_version) {
+ ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
+ goto process_next_packet;
+ }
+
+ // Is there a timestamp transformation present on this packet? If
+ // so, extract it and pass it to the appropriate substreams.
+ if (trtp_flags & 0x02) {
+ ssize_t offset = 18 + ((trtp_flags & 0x01) ? 4 : 0);
+ if (amt < (offset + 24)) {
+ ALOGV("Dropping packet, too short to contain TRTP Timestamp"
+ " Transformation (%u bytes)",
+ static_cast<uint32_t>(amt));
+ goto process_next_packet;
+ }
+
+ trans.a_zero = fetchInt64(data + offset);
+ trans.b_zero = fetchInt64(data + offset + 16);
+ trans.a_to_b_numer = static_cast<int32_t>(
+ fetchInt32 (data + offset + 8));
+ trans.a_to_b_denom = U32_AT(data + offset + 12);
+ foundTrans = true;
+
+ uint32_t program_id = (ssrc >> 5) & 0x1F;
+ for (size_t i = 0; i < substreams_.size(); ++i) {
+ sp<Substream> iter = substreams_.valueAt(i);
+ CHECK(iter != NULL);
+
+ if (iter->getProgramID() == program_id) {
+ iter->processTSTransform(trans);
+ }
+ }
+ }
+
+ // Is this a command packet? If so, its not necessarily associate
+ // with one particular substream. Just give it to the command
+ // packet handler and then move on.
+ if (4 == payload_type) {
+ processCommandPacket(pb);
+ goto process_next_packet;
+ }
+ }
+
+ // If we got to here, then we are a normal packet. Find (or allocate)
+ // the substream we belong to and send the packet off to be processed.
+ substream = substreams_.valueFor(ssrc);
+ if (substream == NULL) {
+ substream = new Substream(ssrc, omx_);
+ if (substream == NULL) {
+ ALOGE("Failed to allocate substream for SSRC 0x%08x", ssrc);
+ goto process_next_packet;
+ }
+ substreams_.add(ssrc, substream);
+
+ if (foundTrans) {
+ substream->processTSTransform(trans);
+ }
+ }
+
+ CHECK(substream != NULL);
+
+ if (marker) {
+ // Start of a new TRTP payload for this substream. Extract the
+ // lower 32 bits of the timestamp and hand the buffer to the
+ // substream for processing.
+ uint32_t ts_lower = U32_AT(data + 4);
+ substream->processPayloadStart(data + 12, amt - 12, ts_lower);
+ } else {
+ // Continuation of an existing TRTP payload. Just hand it off to
+ // the substream for processing.
+ substream->processPayloadCont(data + 12, amt - 12);
+ }
+
+process_next_packet:
+ PacketBuffer::destroy(pb);
+ } // end of main processing while loop.
+}
+
+void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {
+ CHECK(NULL != pb);
+
+ uint8_t* data = pb->data_;
+ ssize_t amt = pb->length_;
+
+ // verify that this packet meets the minimum length of a command packet
+ if (amt < 20) {
+ return;
+ }
+
+ uint8_t trtp_version = data[12];
+ uint8_t trtp_flags = data[13] & 0xF;
+
+ if (1 != trtp_version) {
+ ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
+ return;
+ }
+
+ // calculate the start of the command payload
+ ssize_t offset = 18;
+ if (trtp_flags & 0x01) {
+ // timestamp is present (4 bytes)
+ offset += 4;
+ }
+ if (trtp_flags & 0x02) {
+ // transform is present (24 bytes)
+ offset += 24;
+ }
+
+ // the packet must contain 2 bytes of command payload beyond the TRTP header
+ if (amt < offset + 2) {
+ return;
+ }
+
+ uint16_t command_id = U16_AT(data + offset);
+
+ switch (command_id) {
+ case TRTPControlPacket::kCommandNop:
+ break;
+
+ case TRTPControlPacket::kCommandEOS:
+ case TRTPControlPacket::kCommandFlush: {
+ uint16_t program_id = (U32_AT(data + 8) >> 5) & 0x1F;
+ ALOGI("*** %s flushing program_id=%d",
+ __PRETTY_FUNCTION__, program_id);
+
+ Vector<uint32_t> substreams_to_remove;
+ for (size_t i = 0; i < substreams_.size(); ++i) {
+ sp<Substream> iter = substreams_.valueAt(i);
+ if (iter->getProgramID() == program_id) {
+ iter->shutdown();
+ substreams_to_remove.add(iter->getSSRC());
+ }
+ }
+
+ for (size_t i = 0; i < substreams_to_remove.size(); ++i) {
+ substreams_.removeItem(substreams_to_remove[i]);
+ }
+ } break;
+ }
+}
+
+bool AAH_RXPlayer::processGaps() {
+ // Deal with the current gap situation. Specifically...
+ //
+ // 1) If a new gap has shown up, send a retransmit request to the
+ // transmitter.
+ // 2) If a gap we were working on has had a packet in the middle or at
+ // the end filled in, send another retransmit request for the begining
+ // portion of the gap. TRTP was designed for LANs where packet
+ // re-ordering is very unlikely; so see the middle or end of a gap
+ // filled in before the begining is an almost certain indication that
+ // a retransmission packet was also dropped.
+ // 3) If we have been working on a gap for a while and it still has not
+ // been filled in, send another retransmit request.
+ // 4) If the are no more gaps in the ring, clear the current_gap_status_
+ // flag to indicate that all is well again.
+
+ // Start by fetching the active gap status.
+ SeqNoGap gap;
+ bool send_retransmit_request = false;
+ bool ret_val = false;
+ GapStatus gap_status;
+ if (kGS_NoGap != (gap_status = ring_buffer_.fetchCurrentGap(&gap))) {
+ // Note: checking for a change in the end sequence number should cover
+ // moving on to an entirely new gap for case #1 as well as resending the
+ // begining of a gap range for case #2.
+ send_retransmit_request = (kGS_NoGap == current_gap_status_) ||
+ (current_gap_.end_seq_ != gap.end_seq_);
+
+ // If this is the same gap we have been working on, and it has timed
+ // out, then check to see if our substreams are about to underflow. If
+ // so, instead of sending another retransmit request, just give up on
+ // this gap and move on.
+ if (!send_retransmit_request &&
+ (kGS_NoGap != current_gap_status_) &&
+ (0 == computeNextGapRetransmitTimeout())) {
+
+ // If out current gap is the fast-start gap, don't bother to skip it
+ // because substreams look like the are about to underflow.
+ if ((kGS_FastStartGap != gap_status) ||
+ (current_gap_.end_seq_ != gap.end_seq_)) {
+ for (size_t i = 0; i < substreams_.size(); ++i) {
+ if (substreams_.valueAt(i)->isAboutToUnderflow()) {
+ ALOGV("About to underflow, giving up on gap [%hu, %hu]",
+ gap.start_seq_, gap.end_seq_);
+ ring_buffer_.processNAK();
+ current_gap_status_ = kGS_NoGap;
+ return true;
+ }
+ }
+ }
+
+ // Looks like no one is about to underflow. Just go ahead and send
+ // the request.
+ send_retransmit_request = true;
+ }
+ } else {
+ current_gap_status_ = kGS_NoGap;
+ }
+
+ if (send_retransmit_request) {
+ // If we have been working on a fast start, and it is still not filled
+ // in, even after the extended retransmit time out, give up and skip it.
+ // The system should fall back into its normal slow-start behavior.
+ if ((kGS_FastStartGap == current_gap_status_) &&
+ (current_gap_.end_seq_ == gap.end_seq_)) {
+ ALOGV("Fast start is taking forever; giving up.");
+ ring_buffer_.processNAK();
+ current_gap_status_ = kGS_NoGap;
+ return true;
+ }
+
+ // Send the request.
+ RetransRequest req;
+ uint32_t magic = (kGS_FastStartGap == gap_status)
+ ? kFastStartRequestMagic
+ : kRetransRequestMagic;
+ req.magic_ = htonl(magic);
+ req.mcast_ip_ = listen_addr_.sin_addr.s_addr;
+ req.mcast_port_ = listen_addr_.sin_port;
+ req.start_seq_ = htons(gap.start_seq_);
+ req.end_seq_ = htons(gap.end_seq_);
+
+ {
+ uint32_t a = ntohl(transmitter_addr_.sin_addr.s_addr);
+ uint16_t p = ntohs(transmitter_addr_.sin_port);
+ ALOGV("Sending to transmitter %u.%u.%u.%u:%hu",
+ ((a >> 24) & 0xFF),
+ ((a >> 16) & 0xFF),
+ ((a >> 8) & 0xFF),
+ ( a & 0xFF),
+ p);
+ }
+
+ int res = sendto(sock_fd_, &req, sizeof(req), 0,
+ reinterpret_cast<struct sockaddr*>(&transmitter_addr_),
+ sizeof(transmitter_addr_));
+ if (res < 0) {
+ ALOGE("Error when sending retransmit request (%d)", errno);
+ } else {
+ ALOGV("%s request for range [%hu, %hu] sent",
+ (kGS_FastStartGap == gap_status) ? "Fast Start" : "Retransmit",
+ gap.start_seq_, gap.end_seq_);
+ }
+
+ // Update the current gap info.
+ current_gap_ = gap;
+ current_gap_status_ = gap_status;
+ next_retrans_req_time_ = monotonicUSecNow() +
+ ((kGS_FastStartGap == current_gap_status_)
+ ? kFastStartTimeoutUSec
+ : kGapRerequestTimeoutUSec);
+ }
+
+ return false;
+}
+
+// Compute when its time to send the next gap retransmission in milliseconds.
+// Returns < 0 for an infinite timeout (no gap) and 0 if its time to retransmit
+// right now.
+int AAH_RXPlayer::computeNextGapRetransmitTimeout() {
+ if (kGS_NoGap == current_gap_status_) {
+ return -1;
+ }
+
+ int64_t timeout_delta = next_retrans_req_time_ - monotonicUSecNow();
+
+ timeout_delta /= 1000;
+ if (timeout_delta <= 0) {
+ return 0;
+ }
+
+ return static_cast<uint32_t>(timeout_delta);
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
new file mode 100644
index 0000000..0d8b31f
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "aah_rx_player.h"
+
+namespace android {
+
+AAH_RXPlayer::RXRingBuffer::RXRingBuffer(uint32_t capacity) {
+ capacity_ = capacity;
+ rd_ = wr_ = 0;
+ ring_ = new PacketBuffer*[capacity];
+ memset(ring_, 0, sizeof(PacketBuffer*) * capacity);
+ reset();
+}
+
+AAH_RXPlayer::RXRingBuffer::~RXRingBuffer() {
+ reset();
+ delete[] ring_;
+}
+
+void AAH_RXPlayer::RXRingBuffer::reset() {
+ AutoMutex lock(&lock_);
+
+ if (NULL != ring_) {
+ while (rd_ != wr_) {
+ CHECK(rd_ < capacity_);
+ if (NULL != ring_[rd_]) {
+ PacketBuffer::destroy(ring_[rd_]);
+ ring_[rd_] = NULL;
+ }
+ rd_ = (rd_ + 1) % capacity_;
+ }
+ }
+
+ rd_ = wr_ = 0;
+ rd_seq_known_ = false;
+ waiting_for_fast_start_ = true;
+ fetched_first_packet_ = false;
+ rtp_activity_timeout_valid_ = false;
+}
+
+bool AAH_RXPlayer::RXRingBuffer::pushBuffer(PacketBuffer* buf,
+ uint16_t seq) {
+ AutoMutex lock(&lock_);
+ CHECK(NULL != ring_);
+ CHECK(NULL != buf);
+
+ rtp_activity_timeout_valid_ = true;
+ rtp_activity_timeout_ = monotonicUSecNow() + kRTPActivityTimeoutUSec;
+
+ // If the ring buffer is totally reset (we have never received a single
+ // payload) then we don't know the rd sequence number and this should be
+ // simple. We just store the payload, advance the wr pointer and record the
+ // initial sequence number.
+ if (!rd_seq_known_) {
+ CHECK(rd_ == wr_);
+ CHECK(NULL == ring_[wr_]);
+ CHECK(wr_ < capacity_);
+
+ ring_[wr_] = buf;
+ wr_ = (wr_ + 1) % capacity_;
+ rd_seq_ = seq;
+ rd_seq_known_ = true;
+ return true;
+ }
+
+ // Compute the seqence number of this payload and of the write pointer,
+ // normalized around the read pointer. IOW - transform the payload seq no
+ // and the wr pointer seq no into a space where the rd pointer seq no is
+ // zero. This will define 4 cases we can consider...
+ //
+ // 1) norm_seq == norm_wr_seq
+ // This payload is contiguous with the last. All is good.
+ //
+ // 2) ((norm_seq < norm_wr_seq) && (norm_seq >= norm_rd_seq)
+ // aka ((norm_seq < norm_wr_seq) && (norm_seq >= 0)
+ // This payload is in the past, in the unprocessed region of the ring
+ // buffer. It is probably a retransmit intended to fill in a dropped
+ // payload; it may be a duplicate.
+ //
+ // 3) ((norm_seq - norm_wr_seq) & 0x8000) != 0
+ // This payload is in the past compared to the write pointer (or so very
+ // far in the future that it has wrapped the seq no space), but not in
+ // the unprocessed region of the ring buffer. This could be a duplicate
+ // retransmit; we just drop these payloads unless we are waiting for our
+ // first fast start packet. If we are waiting for fast start, than this
+ // packet is probably the first packet of the fast start retransmission.
+ // If it will fit in the buffer, back up the read pointer to its position
+ // and clear the fast start flag, otherwise just drop it.
+ //
+ // 4) ((norm_seq - norm_wr_seq) & 0x8000) == 0
+ // This payload which is ahead of the next write pointer. This indicates
+ // that we have missed some payloads and need to request a retransmit.
+ // If norm_seq >= (capacity - 1), then the gap is so large that it would
+ // overflow the ring buffer and we should probably start to panic.
+
+ uint16_t norm_wr_seq = ((wr_ + capacity_ - rd_) % capacity_);
+ uint16_t norm_seq = seq - rd_seq_;
+
+ // Check for overflow first.
+ if ((!(norm_seq & 0x8000)) && (norm_seq >= (capacity_ - 1))) {
+ ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu], seq = %hu",
+ capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq);
+ PacketBuffer::destroy(buf);
+ return false;
+ }
+
+ // Check for case #1
+ if (norm_seq == norm_wr_seq) {
+ CHECK(wr_ < capacity_);
+ CHECK(NULL == ring_[wr_]);
+
+ ring_[wr_] = buf;
+ wr_ = (wr_ + 1) % capacity_;
+
+ CHECK(wr_ != rd_);
+ return true;
+ }
+
+ // Check case #2
+ uint32_t ring_pos = (rd_ + norm_seq) % capacity_;
+ if ((norm_seq < norm_wr_seq) && (!(norm_seq & 0x8000))) {
+ // Do we already have a payload for this slot? If so, then this looks
+ // like a duplicate retransmit. Just ignore it.
+ if (NULL != ring_[ring_pos]) {
+ ALOGD("RXed duplicate retransmit, seq = %hu", seq);
+ PacketBuffer::destroy(buf);
+ } else {
+ // Looks like we were missing this payload. Go ahead and store it.
+ ring_[ring_pos] = buf;
+ }
+
+ return true;
+ }
+
+ // Check case #3
+ if ((norm_seq - norm_wr_seq) & 0x8000) {
+ if (!waiting_for_fast_start_) {
+ ALOGD("RXed duplicate retransmit from before rd pointer, seq = %hu",
+ seq);
+ PacketBuffer::destroy(buf);
+ } else {
+ // Looks like a fast start fill-in. Go ahead and store it, assuming
+ // that we can fit it in the buffer.
+ uint32_t implied_ring_size = static_cast<uint32_t>(norm_wr_seq)
+ + (rd_seq_ - seq);
+
+ if (implied_ring_size >= (capacity_ - 1)) {
+ ALOGD("RXed what looks like a fast start packet (seq = %hu),"
+ " but packet is too far in the past to fit into the ring"
+ " buffer. Dropping.", seq);
+ PacketBuffer::destroy(buf);
+ } else {
+ ring_pos = (rd_ + capacity_ + seq - rd_seq_) % capacity_;
+ rd_seq_ = seq;
+ rd_ = ring_pos;
+ waiting_for_fast_start_ = false;
+
+ CHECK(ring_pos < capacity_);
+ CHECK(NULL == ring_[ring_pos]);
+ ring_[ring_pos] = buf;
+ }
+
+ }
+ return true;
+ }
+
+ // Must be in case #4 with no overflow. This packet fits in the current
+ // ring buffer, but is discontiuguous. Advance the write pointer leaving a
+ // gap behind.
+ uint32_t gap_len = (ring_pos + capacity_ - wr_) % capacity_;
+ ALOGD("Drop detected; %u packets, seq_range [%hu, %hu]",
+ gap_len,
+ rd_seq_ + norm_wr_seq,
+ rd_seq_ + norm_wr_seq + gap_len - 1);
+
+ CHECK(NULL == ring_[ring_pos]);
+ ring_[ring_pos] = buf;
+ wr_ = (ring_pos + 1) % capacity_;
+ CHECK(wr_ != rd_);
+
+ return true;
+}
+
+AAH_RXPlayer::PacketBuffer*
+AAH_RXPlayer::RXRingBuffer::fetchBuffer(bool* is_discon) {
+ AutoMutex lock(&lock_);
+ CHECK(NULL != ring_);
+ CHECK(NULL != is_discon);
+
+ // If the read seqence number is not known, then this ring buffer has not
+ // received a packet since being reset and there cannot be any packets to
+ // return. If we are still waiting for the first fast start packet to show
+ // up, we don't want to let any buffer be consumed yet because we expect to
+ // see a packet before the initial read sequence number show up shortly.
+ if (!rd_seq_known_ || waiting_for_fast_start_) {
+ *is_discon = false;
+ return NULL;
+ }
+
+ PacketBuffer* ret = NULL;
+ *is_discon = !fetched_first_packet_;
+
+ while ((rd_ != wr_) && (NULL == ret)) {
+ CHECK(rd_ < capacity_);
+
+ // If we hit a gap, stall and do not advance the read pointer. Let the
+ // higher level code deal with requesting retries and/or deciding to
+ // skip the current gap.
+ ret = ring_[rd_];
+ if (NULL == ret) {
+ break;
+ }
+
+ ring_[rd_] = NULL;
+ rd_ = (rd_ + 1) % capacity_;
+ ++rd_seq_;
+ }
+
+ if (NULL != ret) {
+ fetched_first_packet_ = true;
+ }
+
+ return ret;
+}
+
+AAH_RXPlayer::GapStatus
+AAH_RXPlayer::RXRingBuffer::fetchCurrentGap(SeqNoGap* gap) {
+ AutoMutex lock(&lock_);
+ CHECK(NULL != ring_);
+ CHECK(NULL != gap);
+
+ // If the read seqence number is not known, then this ring buffer has not
+ // received a packet since being reset and there cannot be any gaps.
+ if (!rd_seq_known_) {
+ return kGS_NoGap;
+ }
+
+ // If we are waiting for fast start, then the current gap is a fast start
+ // gap and it includes all packets before the read sequence number.
+ if (waiting_for_fast_start_) {
+ gap->start_seq_ =
+ gap->end_seq_ = rd_seq_ - 1;
+ return kGS_FastStartGap;
+ }
+
+ // If rd == wr, then the buffer is empty and there cannot be any gaps.
+ if (rd_ == wr_) {
+ return kGS_NoGap;
+ }
+
+ // If rd_ is currently pointing at an unprocessed packet, then there is no
+ // current gap.
+ CHECK(rd_ < capacity_);
+ if (NULL != ring_[rd_]) {
+ return kGS_NoGap;
+ }
+
+ // Looks like there must be a gap here. The start of the gap is the current
+ // rd sequence number, all we need to do now is determine its length in
+ // order to compute the end sequence number.
+ gap->start_seq_ = rd_seq_;
+ uint16_t end = rd_seq_;
+ uint32_t tmp = (rd_ + 1) % capacity_;
+ while ((tmp != wr_) && (NULL == ring_[tmp])) {
+ ++end;
+ tmp = (tmp + 1) % capacity_;
+ }
+ gap->end_seq_ = end;
+
+ return kGS_NormalGap;
+}
+
+void AAH_RXPlayer::RXRingBuffer::processNAK(const SeqNoGap* nak) {
+ AutoMutex lock(&lock_);
+ CHECK(NULL != ring_);
+
+ // If we were waiting for our first fast start fill-in packet, and we
+ // received a NAK, then apparantly we are not getting our fast start. Just
+ // clear the waiting flag and go back to normal behavior.
+ if (waiting_for_fast_start_) {
+ waiting_for_fast_start_ = false;
+ }
+
+ // If we have not received a packet since last reset, or there is no data in
+ // the ring, then there is nothing to skip.
+ if ((!rd_seq_known_) || (rd_ == wr_)) {
+ return;
+ }
+
+ // If rd_ is currently pointing at an unprocessed packet, then there is no
+ // gap to skip.
+ CHECK(rd_ < capacity_);
+ if (NULL != ring_[rd_]) {
+ return;
+ }
+
+ // Looks like there must be a gap here. Advance rd until we have passed
+ // over the portion of it indicated by nak (or all of the gap if nak is
+ // NULL). Then reset fetched_first_packet_ so that the next read will show
+ // up as being discontiguous.
+ uint16_t seq_after_gap = (NULL == nak) ? 0 : nak->end_seq_ + 1;
+ while ((rd_ != wr_) &&
+ (NULL == ring_[rd_]) &&
+ ((NULL == nak) || (seq_after_gap != rd_seq_))) {
+ rd_ = (rd_ + 1) % capacity_;
+ ++rd_seq_;
+ }
+ fetched_first_packet_ = false;
+}
+
+int AAH_RXPlayer::RXRingBuffer::computeInactivityTimeout() {
+ AutoMutex lock(&lock_);
+
+ if (!rtp_activity_timeout_valid_) {
+ return -1;
+ }
+
+ uint64_t now = monotonicUSecNow();
+ if (rtp_activity_timeout_ <= now) {
+ return 0;
+ }
+
+ return (rtp_activity_timeout_ - now) / 1000;
+}
+
+AAH_RXPlayer::PacketBuffer*
+AAH_RXPlayer::PacketBuffer::allocate(ssize_t length) {
+ if (length <= 0) {
+ return NULL;
+ }
+
+ uint32_t alloc_len = sizeof(PacketBuffer) + length;
+ PacketBuffer* ret = reinterpret_cast<PacketBuffer*>(
+ new uint8_t[alloc_len]);
+
+ if (NULL != ret) {
+ ret->length_ = length;
+ }
+
+ return ret;
+}
+
+void AAH_RXPlayer::PacketBuffer::destroy(PacketBuffer* pb) {
+ uint8_t* kill_me = reinterpret_cast<uint8_t*>(pb);
+ delete[] kill_me;
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp
new file mode 100644
index 0000000..1e4c784
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player_substream.cpp
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <include/avc_utils.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+
+#include "aah_rx_player.h"
+
+namespace android {
+
+int64_t AAH_RXPlayer::Substream::kAboutToUnderflowThreshold =
+ 50ull * 1000;
+
+AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
+ ssrc_ = ssrc;
+ substream_details_known_ = false;
+ buffer_in_progress_ = NULL;
+ status_ = OK;
+
+ decoder_ = new AAH_DecoderPump(omx);
+ if (decoder_ == NULL) {
+ ALOGE("%s failed to allocate decoder pump!", __PRETTY_FUNCTION__);
+ }
+ if (OK != decoder_->initCheck()) {
+ ALOGE("%s failed to initialize decoder pump!", __PRETTY_FUNCTION__);
+ }
+
+ // cleanupBufferInProgress will reset most of the internal state variables.
+ // Just need to make sure that buffer_in_progress_ is NULL before calling.
+ cleanupBufferInProgress();
+}
+
+
+void AAH_RXPlayer::Substream::shutdown() {
+ substream_meta_ = NULL;
+ status_ = OK;
+ cleanupBufferInProgress();
+ cleanupDecoder();
+}
+
+void AAH_RXPlayer::Substream::cleanupBufferInProgress() {
+ if (NULL != buffer_in_progress_) {
+ buffer_in_progress_->release();
+ buffer_in_progress_ = NULL;
+ }
+
+ expected_buffer_size_ = 0;
+ buffer_filled_ = 0;
+ waiting_for_rap_ = true;
+}
+
+void AAH_RXPlayer::Substream::cleanupDecoder() {
+ if (decoder_ != NULL) {
+ decoder_->shutdown();
+ }
+}
+
+bool AAH_RXPlayer::Substream::shouldAbort(const char* log_tag) {
+ // If we have already encountered a fatal error, do nothing. We are just
+ // waiting for our owner to shut us down now.
+ if (OK != status_) {
+ ALOGV("Skipping %s, substream has encountered fatal error (%d).",
+ log_tag, status_);
+ return true;
+ }
+
+ return false;
+}
+
+void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
+ uint32_t amt,
+ int32_t ts_lower) {
+ uint32_t min_length = 6;
+
+ if (shouldAbort(__PRETTY_FUNCTION__)) {
+ return;
+ }
+
+ // Do we have a buffer in progress already? If so, abort the buffer. In
+ // theory, this should never happen. If there were a discontinutity in the
+ // stream, the discon in the seq_nos at the RTP level should have already
+ // triggered a cleanup of the buffer in progress. To see a problem at this
+ // level is an indication either of a bug in the transmitter, or some form
+ // of terrible corruption/tampering on the wire.
+ if (NULL != buffer_in_progress_) {
+ ALOGE("processPayloadStart is aborting payload already in progress.");
+ cleanupBufferInProgress();
+ }
+
+ // Parse enough of the header to know where we stand. Since this is a
+ // payload start, it should begin with a TRTP header which has to be at
+ // least 6 bytes long.
+ if (amt < min_length) {
+ ALOGV("Discarding payload too short to contain TRTP header (len = %u)",
+ amt);
+ return;
+ }
+
+ // Check the TRTP version number.
+ if (0x01 != buf[0]) {
+ ALOGV("Unexpected TRTP version (%u) in header. Expected %u.",
+ buf[0], 1);
+ return;
+ }
+
+ // Extract the substream type field and make sure its one we understand (and
+ // one that does not conflict with any previously received substream type.
+ uint8_t header_type = (buf[1] >> 4) & 0xF;
+ switch (header_type) {
+ case 0x01:
+ // Audio, yay! Just break. We understand audio payloads.
+ break;
+ case 0x02:
+ ALOGV("RXed packet with unhandled TRTP header type (Video).");
+ return;
+ case 0x03:
+ ALOGV("RXed packet with unhandled TRTP header type (Subpicture).");
+ return;
+ case 0x04:
+ ALOGV("RXed packet with unhandled TRTP header type (Control).");
+ return;
+ default:
+ ALOGV("RXed packet with unhandled TRTP header type (%u).",
+ header_type);
+ return;
+ }
+
+ if (substream_details_known_ && (header_type != substream_type_)) {
+ ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does not"
+ " match previously received header type (%u)",
+ ssrc_, header_type, substream_type_);
+ return;
+ }
+
+ // Check the flags to see if there is another 32 bits of timestamp present.
+ uint32_t trtp_header_len = 6;
+ bool ts_valid = buf[1] & 0x1;
+ if (ts_valid) {
+ min_length += 4;
+ trtp_header_len += 4;
+ if (amt < min_length) {
+ ALOGV("Discarding payload too short to contain TRTP timestamp"
+ " (len = %u)", amt);
+ return;
+ }
+ }
+
+ // Extract the TRTP length field and sanity check it.
+ uint32_t trtp_len;
+ trtp_len = (static_cast<uint32_t>(buf[2]) << 24) |
+ (static_cast<uint32_t>(buf[3]) << 16) |
+ (static_cast<uint32_t>(buf[4]) << 8) |
+ static_cast<uint32_t>(buf[5]);
+ if (trtp_len < min_length) {
+ ALOGV("TRTP length (%u) is too short to be valid. Must be at least %u"
+ " bytes.", trtp_len, min_length);
+ return;
+ }
+
+ // Extract the rest of the timestamp field if valid.
+ int64_t ts = 0;
+ uint32_t parse_offset = 6;
+ if (ts_valid) {
+ ts = (static_cast<int64_t>(buf[parse_offset ]) << 56) |
+ (static_cast<int64_t>(buf[parse_offset + 1]) << 48) |
+ (static_cast<int64_t>(buf[parse_offset + 2]) << 40) |
+ (static_cast<int64_t>(buf[parse_offset + 3]) << 32);
+ ts |= ts_lower;
+ parse_offset += 4;
+ }
+
+ // Check the flags to see if there is another 24 bytes of timestamp
+ // transformation present.
+ if (buf[1] & 0x2) {
+ min_length += 24;
+ parse_offset += 24;
+ trtp_header_len += 24;
+ if (amt < min_length) {
+ ALOGV("Discarding payload too short to contain TRTP timestamp"
+ " transformation (len = %u)", amt);
+ return;
+ }
+ }
+
+ // TODO : break the parsing into individual parsers for the different
+ // payload types (audio, video, etc).
+ //
+ // At this point in time, we know that this is audio. Go ahead and parse
+ // the basic header, check the codec type, and find the payload portion of
+ // the packet.
+ min_length += 3;
+ if (trtp_len < min_length) {
+ ALOGV("TRTP length (%u) is too short to be a valid audio payload. Must"
+ " be at least %u bytes.", trtp_len, min_length);
+ return;
+ }
+
+ if (amt < min_length) {
+ ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
+ " entire TRTP header. TRTP does not currently support fragmenting"
+ " TRTP headers across RTP payloads", amt);
+ return;
+ }
+
+ uint8_t codec_type = buf[parse_offset ];
+ uint8_t flags = buf[parse_offset + 1];
+ uint8_t volume = buf[parse_offset + 2];
+ parse_offset += 3;
+ trtp_header_len += 3;
+
+ if (!setupSubstreamType(header_type, codec_type)) {
+ return;
+ }
+
+ if (decoder_ != NULL) {
+ decoder_->setRenderVolume(volume);
+ }
+
+ // TODO : move all of the constant flag and offset definitions for TRTP up
+ // into some sort of common header file.
+ if (waiting_for_rap_ && !(flags & 0x08)) {
+ ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP.");
+ return;
+ }
+
+ if (flags & 0x10) {
+ ALOGV("Dropping TRTP Audio Payload with aux codec data present (only"
+ " handle MP3 right now, and it has no aux data)");
+ return;
+ }
+
+ // OK - everything left is just payload. Compute the payload size, start
+ // the buffer in progress and pack as much payload as we can into it. If
+ // the payload is finished once we are done, go ahead and send the payload
+ // to the decoder.
+ expected_buffer_size_ = trtp_len - trtp_header_len;
+ if (!expected_buffer_size_) {
+ ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
+ return;
+ }
+
+ CHECK(amt >= trtp_header_len);
+ uint32_t todo = amt - trtp_header_len;
+ if (expected_buffer_size_ < todo) {
+ ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
+ " dropping payload.", todo, expected_buffer_size_);
+ return;
+ }
+
+ buffer_filled_ = 0;
+ buffer_in_progress_ = new MediaBuffer(expected_buffer_size_);
+ if ((NULL == buffer_in_progress_) ||
+ (NULL == buffer_in_progress_->data())) {
+ ALOGV("Failed to allocate MediaBuffer of length %u",
+ expected_buffer_size_);
+ cleanupBufferInProgress();
+ return;
+ }
+
+ sp<MetaData> meta = buffer_in_progress_->meta_data();
+ if (meta == NULL) {
+ ALOGV("Missing metadata structure in allocated MediaBuffer; dropping"
+ " payload");
+ cleanupBufferInProgress();
+ return;
+ }
+
+ // TODO : set this based on the codec type indicated in the TRTP stream.
+ // Right now, we only support MP3, so the choice is obvious.
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ if (ts_valid) {
+ meta->setInt64(kKeyTime, ts);
+ }
+
+ if (amt > 0) {
+ uint8_t* tgt =
+ reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
+ memcpy(tgt + buffer_filled_, buf + trtp_header_len, todo);
+ buffer_filled_ += amt;
+ }
+
+ if (buffer_filled_ >= expected_buffer_size_) {
+ processCompletedBuffer();
+ }
+}
+
+void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
+ uint32_t amt) {
+ if (shouldAbort(__PRETTY_FUNCTION__)) {
+ return;
+ }
+
+ if (NULL == buffer_in_progress_) {
+ ALOGV("TRTP Receiver skipping payload continuation; no buffer currently"
+ " in progress.");
+ return;
+ }
+
+ CHECK(buffer_filled_ < expected_buffer_size_);
+ uint32_t buffer_left = expected_buffer_size_ - buffer_filled_;
+ if (amt > buffer_left) {
+ ALOGV("Extra data (%u > %u) present in continued TRTP Audio Payload;"
+ " dropping payload.", amt, buffer_left);
+ cleanupBufferInProgress();
+ return;
+ }
+
+ if (amt > 0) {
+ uint8_t* tgt =
+ reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
+ memcpy(tgt + buffer_filled_, buf, amt);
+ buffer_filled_ += amt;
+ }
+
+ if (buffer_filled_ >= expected_buffer_size_) {
+ processCompletedBuffer();
+ }
+}
+
+void AAH_RXPlayer::Substream::processCompletedBuffer() {
+ const uint8_t* buffer_data = NULL;
+ int sample_rate;
+ int channel_count;
+ size_t frame_size;
+ status_t res;
+
+ CHECK(NULL != buffer_in_progress_);
+
+ if (decoder_ == NULL) {
+ ALOGV("Dropping complete buffer, no decoder pump allocated");
+ goto bailout;
+ }
+
+ buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
+ if (buffer_in_progress_->size() < 4) {
+ ALOGV("MP3 payload too short to contain header, dropping payload.");
+ goto bailout;
+ }
+
+ // Extract the channel count and the sample rate from the MP3 header. The
+ // stagefright MP3 requires that these be delivered before decoing can
+ // begin.
+ if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
+ &frame_size,
+ &sample_rate,
+ &channel_count,
+ NULL,
+ NULL)) {
+ ALOGV("Failed to parse MP3 header in payload, droping payload.");
+ goto bailout;
+ }
+
+
+ // Make sure that our substream metadata is set up properly. If there has
+ // been a format change, be sure to reset the underlying decoder. In
+ // stagefright, it seems like the only way to do this is to destroy and
+ // recreate the decoder.
+ if (substream_meta_ == NULL) {
+ substream_meta_ = new MetaData();
+
+ if (substream_meta_ == NULL) {
+ ALOGE("Failed to allocate MetaData structure for substream");
+ goto bailout;
+ }
+
+ substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ substream_meta_->setInt32 (kKeyChannelCount, channel_count);
+ substream_meta_->setInt32 (kKeySampleRate, sample_rate);
+ } else {
+ int32_t prev_sample_rate;
+ int32_t prev_channel_count;
+ substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate);
+ substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
+
+ if ((prev_channel_count != channel_count) ||
+ (prev_sample_rate != sample_rate)) {
+ ALOGW("Format change detected, forcing decoder reset.");
+ cleanupDecoder();
+
+ substream_meta_->setInt32(kKeyChannelCount, channel_count);
+ substream_meta_->setInt32(kKeySampleRate, sample_rate);
+ }
+ }
+
+ // If our decoder has not be set up, do so now.
+ res = decoder_->init(substream_meta_);
+ if (OK != res) {
+ ALOGE("Failed to init decoder (res = %d)", res);
+ cleanupDecoder();
+ substream_meta_ = NULL;
+ goto bailout;
+ }
+
+ // Queue the payload for decode.
+ res = decoder_->queueForDecode(buffer_in_progress_);
+
+ if (res != OK) {
+ ALOGD("Failed to queue payload for decode, resetting decoder pump!"
+ " (res = %d)", res);
+ status_ = res;
+ cleanupDecoder();
+ cleanupBufferInProgress();
+ }
+
+ // NULL out buffer_in_progress before calling the cleanup helper.
+ //
+ // MediaBuffers use something of a hybrid ref-counting pattern which prevent
+ // the AAH_DecoderPump's input queue from adding their own reference to the
+ // MediaBuffer. MediaBuffers start life with a reference count of 0, as
+ // well as an observer which starts as NULL. Before being given an
+ // observer, the ref count cannot be allowed to become non-zero as it will
+ // cause calls to release() to assert. Basically, before a MediaBuffer has
+ // an observer, they behave like non-ref counted obects where release()
+ // serves the roll of delete. After a MediaBuffer has an observer, they
+ // become more like ref counted objects where add ref and release can be
+ // used, and when the ref count hits zero, the MediaBuffer is handed off to
+ // the observer.
+ //
+ // Given all of this, when we give the buffer to the decoder pump to wait in
+ // the to-be-processed queue, the decoder cannot add a ref to the buffer as
+ // it would in a traditional ref counting system. Instead it needs to
+ // "steal" the non-existent ref. In the case of queue failure, we need to
+ // make certain to release this non-existent reference so that the buffer is
+ // cleaned up during the cleanupBufferInProgress helper. In the case of a
+ // successful queue operation, we need to make certain that the
+ // cleanupBufferInProgress helper does not release the buffer since it needs
+ // to remain alive in the queue. We acomplish this by NULLing out the
+ // buffer pointer before calling the cleanup helper.
+ buffer_in_progress_ = NULL;
+
+bailout:
+ cleanupBufferInProgress();
+}
+
+
+void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
+ if (decoder_ != NULL) {
+ decoder_->setRenderTSTransform(trans);
+ }
+}
+
+bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
+ if (decoder_ == NULL) {
+ return false;
+ }
+
+ return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
+}
+
+bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
+ uint8_t codec_type) {
+ // Sanity check the codec type. Right now we only support MP3. Also check
+ // for conflicts with previously delivered codec types.
+ if (substream_details_known_ && (codec_type != codec_type_)) {
+ ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does not"
+ " match previously received codec type (%u)",
+ ssrc_, codec_type, codec_type_);
+ return false;
+ }
+
+ if (codec_type != 0x03) {
+ ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported codec"
+ " type (%u)", ssrc_, codec_type);
+ return false;
+ }
+
+ if (!substream_details_known_) {
+ substream_type_ = substream_type;
+ codec_type_ = codec_type;
+ substream_details_known_ = true;
+ }
+
+ return true;
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.cpp b/media/libaah_rtp/aah_tx_packet.cpp
new file mode 100644
index 0000000..3f6e0e9
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_packet.cpp
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <string.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include "aah_tx_packet.h"
+
+namespace android {
+
+const int TRTPPacket::kRTPHeaderLen;
+const uint32_t TRTPPacket::kTRTPEpochMask;
+
+TRTPPacket::~TRTPPacket() {
+ delete mPacket;
+}
+
+/*** TRTP packet properties ***/
+
+void TRTPPacket::setSeqNumber(uint16_t val) {
+ mSeqNumber = val;
+
+ if (mIsPacked) {
+ const int kTRTPSeqNumberOffset = 2;
+ uint16_t* buf = reinterpret_cast<uint16_t*>(
+ mPacket + kTRTPSeqNumberOffset);
+ *buf = htons(mSeqNumber);
+ }
+}
+
+uint16_t TRTPPacket::getSeqNumber() const {
+ return mSeqNumber;
+}
+
+void TRTPPacket::setPTS(int64_t val) {
+ CHECK(!mIsPacked);
+ mPTS = val;
+ mPTSValid = true;
+}
+
+int64_t TRTPPacket::getPTS() const {
+ return mPTS;
+}
+
+void TRTPPacket::setEpoch(uint32_t val) {
+ mEpoch = val;
+
+ if (mIsPacked) {
+ const int kTRTPEpochOffset = 8;
+ uint32_t* buf = reinterpret_cast<uint32_t*>(
+ mPacket + kTRTPEpochOffset);
+ uint32_t val = ntohl(*buf);
+ val &= ~(kTRTPEpochMask << kTRTPEpochShift);
+ val |= (mEpoch & kTRTPEpochMask) << kTRTPEpochShift;
+ *buf = htonl(val);
+ }
+}
+
+void TRTPPacket::setProgramID(uint16_t val) {
+ CHECK(!mIsPacked);
+ mProgramID = val;
+}
+
+void TRTPPacket::setSubstreamID(uint16_t val) {
+ CHECK(!mIsPacked);
+ mSubstreamID = val;
+}
+
+
+void TRTPPacket::setClockTransform(const LinearTransform& trans) {
+ CHECK(!mIsPacked);
+ mClockTranform = trans;
+ mClockTranformValid = true;
+}
+
+uint8_t* TRTPPacket::getPacket() const {
+ CHECK(mIsPacked);
+ return mPacket;
+}
+
+int TRTPPacket::getPacketLen() const {
+ CHECK(mIsPacked);
+ return mPacketLen;
+}
+
+void TRTPPacket::setExpireTime(nsecs_t val) {
+ CHECK(!mIsPacked);
+ mExpireTime = val;
+}
+
+nsecs_t TRTPPacket::getExpireTime() const {
+ return mExpireTime;
+}
+
+/*** TRTP audio packet properties ***/
+
+void TRTPAudioPacket::setCodecType(TRTPAudioCodecType val) {
+ CHECK(!mIsPacked);
+ mCodecType = val;
+}
+
+void TRTPAudioPacket::setRandomAccessPoint(bool val) {
+ CHECK(!mIsPacked);
+ mRandomAccessPoint = val;
+}
+
+void TRTPAudioPacket::setDropable(bool val) {
+ CHECK(!mIsPacked);
+ mDropable = val;
+}
+
+void TRTPAudioPacket::setDiscontinuity(bool val) {
+ CHECK(!mIsPacked);
+ mDiscontinuity = val;
+}
+
+void TRTPAudioPacket::setEndOfStream(bool val) {
+ CHECK(!mIsPacked);
+ mEndOfStream = val;
+}
+
+void TRTPAudioPacket::setVolume(uint8_t val) {
+ CHECK(!mIsPacked);
+ mVolume = val;
+}
+
+void TRTPAudioPacket::setAccessUnitData(void* data, int len) {
+ CHECK(!mIsPacked);
+ mAccessUnitData = data;
+ mAccessUnitLen = len;
+}
+
+/*** TRTP control packet properties ***/
+
+void TRTPControlPacket::setCommandID(TRTPCommandID val) {
+ CHECK(!mIsPacked);
+ mCommandID = val;
+}
+
+/*** TRTP packet serializers ***/
+
+void TRTPPacket::writeU8(uint8_t*& buf, uint8_t val) {
+ *buf = val;
+ buf++;
+}
+
+void TRTPPacket::writeU16(uint8_t*& buf, uint16_t val) {
+ *reinterpret_cast<uint16_t*>(buf) = htons(val);
+ buf += 2;
+}
+
+void TRTPPacket::writeU32(uint8_t*& buf, uint32_t val) {
+ *reinterpret_cast<uint32_t*>(buf) = htonl(val);
+ buf += 4;
+}
+
+void TRTPPacket::writeU64(uint8_t*& buf, uint64_t val) {
+ buf[0] = static_cast<uint8_t>(val >> 56);
+ buf[1] = static_cast<uint8_t>(val >> 48);
+ buf[2] = static_cast<uint8_t>(val >> 40);
+ buf[3] = static_cast<uint8_t>(val >> 32);
+ buf[4] = static_cast<uint8_t>(val >> 24);
+ buf[5] = static_cast<uint8_t>(val >> 16);
+ buf[6] = static_cast<uint8_t>(val >> 8);
+ buf[7] = static_cast<uint8_t>(val);
+ buf += 8;
+}
+
+void TRTPPacket::writeTRTPHeader(uint8_t*& buf,
+ bool isFirstFragment,
+ int totalPacketLen) {
+ // RTP header
+ writeU8(buf,
+ ((mVersion & 0x03) << 6) |
+ (static_cast<int>(mPadding) << 5) |
+ (static_cast<int>(mExtension) << 4) |
+ (mCsrcCount & 0x0F));
+ writeU8(buf,
+ (static_cast<int>(isFirstFragment) << 7) |
+ (mPayloadType & 0x7F));
+ writeU16(buf, mSeqNumber);
+ if (isFirstFragment && mPTSValid) {
+ writeU32(buf, mPTS & 0xFFFFFFFF);
+ } else {
+ writeU32(buf, 0);
+ }
+ writeU32(buf,
+ ((mEpoch & kTRTPEpochMask) << kTRTPEpochShift) |
+ ((mProgramID & 0x1F) << 5) |
+ (mSubstreamID & 0x1F));
+
+ // TRTP header
+ writeU8(buf, mTRTPVersion);
+ writeU8(buf,
+ ((mTRTPHeaderType & 0x0F) << 4) |
+ (mClockTranformValid ? 0x02 : 0x00) |
+ (mPTSValid ? 0x01 : 0x00));
+ writeU32(buf, totalPacketLen - kRTPHeaderLen);
+ if (mPTSValid) {
+ writeU32(buf, mPTS >> 32);
+ }
+
+ if (mClockTranformValid) {
+ writeU64(buf, mClockTranform.a_zero);
+ writeU32(buf, mClockTranform.a_to_b_numer);
+ writeU32(buf, mClockTranform.a_to_b_denom);
+ writeU64(buf, mClockTranform.b_zero);
+ }
+}
+
+bool TRTPAudioPacket::pack() {
+ if (mIsPacked) {
+ return false;
+ }
+
+ int packetLen = kRTPHeaderLen +
+ mAccessUnitLen +
+ TRTPHeaderLen();
+
+ // TODO : support multiple fragments
+ const int kMaxUDPPayloadLen = 65507;
+ if (packetLen > kMaxUDPPayloadLen) {
+ return false;
+ }
+
+ mPacket = new uint8_t[packetLen];
+ if (!mPacket) {
+ return false;
+ }
+
+ mPacketLen = packetLen;
+
+ uint8_t* cur = mPacket;
+
+ writeTRTPHeader(cur, true, packetLen);
+ writeU8(cur, mCodecType);
+ writeU8(cur,
+ (static_cast<int>(mRandomAccessPoint) << 3) |
+ (static_cast<int>(mDropable) << 2) |
+ (static_cast<int>(mDiscontinuity) << 1) |
+ (static_cast<int>(mEndOfStream)));
+ writeU8(cur, mVolume);
+
+ memcpy(cur, mAccessUnitData, mAccessUnitLen);
+
+ mIsPacked = true;
+ return true;
+}
+
+int TRTPPacket::TRTPHeaderLen() const {
+ // 6 bytes for version, payload type, flags and length. An additional 4 if
+ // there are upper timestamp bits present and another 24 if there is a clock
+ // transformation present.
+ return 6 +
+ (mClockTranformValid ? 24 : 0) +
+ (mPTSValid ? 4 : 0);
+}
+
+int TRTPAudioPacket::TRTPHeaderLen() const {
+ // TRTPPacket::TRTPHeaderLen() for the base TRTPHeader. 3 bytes for audio's
+ // codec type, flags and volume field. Another 5 bytes if the codec type is
+ // PCM and we are sending sample rate/channel count. as well as however long
+ // the aux data (if present) is.
+
+ int pcmParamLength;
+ switch(mCodecType) {
+ case kCodecPCMBigEndian:
+ case kCodecPCMLittleEndian:
+ pcmParamLength = 5;
+ break;
+
+ default:
+ pcmParamLength = 0;
+ break;
+ }
+
+
+ // TODO : properly compute aux data length. Currently, nothing
+ // uses aux data, so its length is always 0.
+ int auxDataLength = 0;
+ return TRTPPacket::TRTPHeaderLen() +
+ 3 +
+ auxDataLength +
+ pcmParamLength;
+}
+
+bool TRTPControlPacket::pack() {
+ if (mIsPacked) {
+ return false;
+ }
+
+ // command packets contain a 2-byte command ID
+ int packetLen = kRTPHeaderLen +
+ TRTPHeaderLen() +
+ 2;
+
+ mPacket = new uint8_t[packetLen];
+ if (!mPacket) {
+ return false;
+ }
+
+ mPacketLen = packetLen;
+
+ uint8_t* cur = mPacket;
+
+ writeTRTPHeader(cur, true, packetLen);
+ writeU16(cur, mCommandID);
+
+ mIsPacked = true;
+ return true;
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.h b/media/libaah_rtp/aah_tx_packet.h
new file mode 100644
index 0000000..833803e
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_packet.h
@@ -0,0 +1,191 @@
+/*
+ * 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 __AAH_TX_PACKET_H__
+#define __AAH_TX_PACKET_H__
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/LinearTransform.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+class TRTPPacket : public RefBase {
+ protected:
+ enum TRTPHeaderType {
+ kHeaderTypeAudio = 1,
+ kHeaderTypeVideo = 2,
+ kHeaderTypeSubpicture = 3,
+ kHeaderTypeControl = 4,
+ };
+
+ TRTPPacket(TRTPHeaderType headerType)
+ : mIsPacked(false)
+ , mVersion(2)
+ , mPadding(false)
+ , mExtension(false)
+ , mCsrcCount(0)
+ , mPayloadType(100)
+ , mSeqNumber(0)
+ , mPTSValid(false)
+ , mPTS(0)
+ , mEpoch(0)
+ , mProgramID(0)
+ , mSubstreamID(0)
+ , mClockTranformValid(false)
+ , mTRTPVersion(1)
+ , mTRTPLength(0)
+ , mTRTPHeaderType(headerType)
+ , mPacket(NULL)
+ , mPacketLen(0) { }
+
+ public:
+ virtual ~TRTPPacket();
+
+ void setSeqNumber(uint16_t val);
+ uint16_t getSeqNumber() const;
+
+ void setPTS(int64_t val);
+ int64_t getPTS() const;
+
+ void setEpoch(uint32_t val);
+ void setProgramID(uint16_t val);
+ void setSubstreamID(uint16_t val);
+ void setClockTransform(const LinearTransform& trans);
+
+ uint8_t* getPacket() const;
+ int getPacketLen() const;
+
+ void setExpireTime(nsecs_t val);
+ nsecs_t getExpireTime() const;
+
+ virtual bool pack() = 0;
+
+ // mask for the number of bits in a TRTP epoch
+ static const uint32_t kTRTPEpochMask = (1 << 22) - 1;
+ static const int kTRTPEpochShift = 10;
+
+ protected:
+ static const int kRTPHeaderLen = 12;
+ virtual int TRTPHeaderLen() const;
+
+ void writeTRTPHeader(uint8_t*& buf,
+ bool isFirstFragment,
+ int totalPacketLen);
+
+ void writeU8(uint8_t*& buf, uint8_t val);
+ void writeU16(uint8_t*& buf, uint16_t val);
+ void writeU32(uint8_t*& buf, uint32_t val);
+ void writeU64(uint8_t*& buf, uint64_t val);
+
+ bool mIsPacked;
+
+ uint8_t mVersion;
+ bool mPadding;
+ bool mExtension;
+ uint8_t mCsrcCount;
+ uint8_t mPayloadType;
+ uint16_t mSeqNumber;
+ bool mPTSValid;
+ int64_t mPTS;
+ uint32_t mEpoch;
+ uint16_t mProgramID;
+ uint16_t mSubstreamID;
+ LinearTransform mClockTranform;
+ bool mClockTranformValid;
+ uint8_t mTRTPVersion;
+ uint32_t mTRTPLength;
+ TRTPHeaderType mTRTPHeaderType;
+
+ uint8_t* mPacket;
+ int mPacketLen;
+
+ nsecs_t mExpireTime;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TRTPPacket);
+};
+
+class TRTPAudioPacket : public TRTPPacket {
+ public:
+ TRTPAudioPacket()
+ : TRTPPacket(kHeaderTypeAudio)
+ , mCodecType(kCodecInvalid)
+ , mRandomAccessPoint(false)
+ , mDropable(false)
+ , mDiscontinuity(false)
+ , mEndOfStream(false)
+ , mVolume(0)
+ , mAccessUnitData(NULL) { }
+
+ enum TRTPAudioCodecType {
+ kCodecInvalid = 0,
+ kCodecPCMBigEndian = 1,
+ kCodecPCMLittleEndian = 2,
+ kCodecMPEG1Audio = 3,
+ };
+
+ void setCodecType(TRTPAudioCodecType val);
+ void setRandomAccessPoint(bool val);
+ void setDropable(bool val);
+ void setDiscontinuity(bool val);
+ void setEndOfStream(bool val);
+ void setVolume(uint8_t val);
+ void setAccessUnitData(void* data, int len);
+
+ virtual bool pack();
+
+ protected:
+ virtual int TRTPHeaderLen() const;
+
+ private:
+ TRTPAudioCodecType mCodecType;
+ bool mRandomAccessPoint;
+ bool mDropable;
+ bool mDiscontinuity;
+ bool mEndOfStream;
+ uint8_t mVolume;
+ void* mAccessUnitData;
+ int mAccessUnitLen;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TRTPAudioPacket);
+};
+
+class TRTPControlPacket : public TRTPPacket {
+ public:
+ TRTPControlPacket()
+ : TRTPPacket(kHeaderTypeControl)
+ , mCommandID(kCommandNop) {}
+
+ enum TRTPCommandID {
+ kCommandNop = 1,
+ kCommandFlush = 2,
+ kCommandEOS = 3,
+ };
+
+ void setCommandID(TRTPCommandID val);
+
+ virtual bool pack();
+
+ private:
+ TRTPCommandID mCommandID;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TRTPControlPacket);
+};
+
+} // namespace android
+
+#endif // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp
new file mode 100644
index 0000000..a79a989
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_player.cpp
@@ -0,0 +1,1139 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <utils/Log.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <netdb.h>
+#include <netinet/ip.h>
+
+#include <common_time/cc_helper.h>
+#include <media/IMediaPlayer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/Timers.h>
+
+#include "aah_tx_packet.h"
+#include "aah_tx_player.h"
+
+namespace android {
+
+static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
+static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
+static const size_t kLowWaterMarkBytes = 40000;
+static const size_t kHighWaterMarkBytes = 200000;
+
+// When we start up, how much lead time should we put on the first access unit?
+static const int64_t kAAHStartupLeadTimeUs = 300000LL;
+
+// How much time do we attempt to lead the clock by in steady state?
+static const int64_t kAAHBufferTimeUs = 1000000LL;
+
+// how long do we keep data in our retransmit buffer after sending it.
+const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs =
+ kAAHBufferTimeUs * 1100;
+
+sp<MediaPlayerBase> createAAH_TXPlayer() {
+ sp<MediaPlayerBase> ret = new AAH_TXPlayer();
+ return ret;
+}
+
+template <typename T> static T clamp(T val, T min, T max) {
+ if (val < min) {
+ return min;
+ } else if (val > max) {
+ return max;
+ } else {
+ return val;
+ }
+}
+
+struct AAH_TXEvent : public TimedEventQueue::Event {
+ AAH_TXEvent(AAH_TXPlayer *player,
+ void (AAH_TXPlayer::*method)()) : mPlayer(player)
+ , mMethod(method) {}
+
+ protected:
+ virtual ~AAH_TXEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+ private:
+ AAH_TXPlayer *mPlayer;
+ void (AAH_TXPlayer::*mMethod)();
+
+ AAH_TXEvent(const AAH_TXEvent &);
+ AAH_TXEvent& operator=(const AAH_TXEvent &);
+};
+
+AAH_TXPlayer::AAH_TXPlayer()
+ : mQueueStarted(false)
+ , mFlags(0)
+ , mExtractorFlags(0) {
+ DataSource::RegisterDefaultSniffers();
+
+ mBufferingEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onBufferingUpdate);
+ mBufferingEventPending = false;
+
+ mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio);
+ mPumpAudioEventPending = false;
+
+ reset_l();
+}
+
+AAH_TXPlayer::~AAH_TXPlayer() {
+ if (mQueueStarted) {
+ mQueue.stop();
+ }
+
+ reset_l();
+}
+
+void AAH_TXPlayer::cancelPlayerEvents(bool keepBufferingGoing) {
+ if (!keepBufferingGoing) {
+ mQueue.cancelEvent(mBufferingEvent->eventID());
+ mBufferingEventPending = false;
+
+ mQueue.cancelEvent(mPumpAudioEvent->eventID());
+ mPumpAudioEventPending = false;
+ }
+}
+
+status_t AAH_TXPlayer::initCheck() {
+ // Check for the presense of the common time service by attempting to query
+ // for CommonTime's frequency. If we get an error back, we cannot talk to
+ // the service at all and should abort now.
+ status_t res;
+ uint64_t freq;
+ res = mCCHelper.getCommonFreq(&freq);
+ if (OK != res) {
+ ALOGE("Failed to connect to common time service! (res %d)", res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::setDataSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers) {
+ Mutex::Autolock autoLock(mLock);
+ return setDataSource_l(url, headers);
+}
+
+status_t AAH_TXPlayer::setDataSource_l(
+ const char *url,
+ const KeyedVector<String8, String8> *headers) {
+ reset_l();
+
+ // the URL must consist of "aahTX://" followed by the real URL of
+ // the data source
+ const char *kAAHPrefix = "aahTX://";
+ if (strncasecmp(url, kAAHPrefix, strlen(kAAHPrefix))) {
+ return INVALID_OPERATION;
+ }
+
+ mUri.setTo(url + strlen(kAAHPrefix));
+
+ if (headers) {
+ mUriHeaders = *headers;
+
+ ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
+ if (index >= 0) {
+ // Browser is in "incognito" mode, suppress logging URLs.
+
+ // This isn't something that should be passed to the server.
+ mUriHeaders.removeItemsAt(index);
+
+ mFlags |= INCOGNITO;
+ }
+ }
+
+ // The URL may optionally contain a "#" character followed by a Skyjam
+ // cookie. Ideally the cookie header should just be passed in the headers
+ // argument, but the Java API for supplying headers is apparently not yet
+ // exposed in the SDK used by application developers.
+ const char kSkyjamCookieDelimiter = '#';
+ char* skyjamCookie = strrchr(mUri.string(), kSkyjamCookieDelimiter);
+ if (skyjamCookie) {
+ skyjamCookie++;
+ mUriHeaders.add(String8("Cookie"), String8(skyjamCookie));
+ mUri = String8(mUri.string(), skyjamCookie - mUri.string());
+ }
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+ Mutex::Autolock autoLock(mLock);
+
+ reset_l();
+
+ sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
+
+ status_t err = dataSource->initCheck();
+
+ if (err != OK) {
+ return err;
+ }
+
+ mFileSource = dataSource;
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ return setDataSource_l(extractor);
+}
+
+status_t AAH_TXPlayer::setVideoSurface(const sp<Surface>& surface) {
+ return OK;
+}
+
+status_t AAH_TXPlayer::setVideoSurfaceTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ return OK;
+}
+
+status_t AAH_TXPlayer::prepare() {
+ return INVALID_OPERATION;
+}
+
+status_t AAH_TXPlayer::prepareAsync() {
+ Mutex::Autolock autoLock(mLock);
+
+ return prepareAsync_l();
+}
+
+status_t AAH_TXPlayer::prepareAsync_l() {
+ if (mFlags & PREPARING) {
+ return UNKNOWN_ERROR; // async prepare already pending
+ }
+
+ mAAH_Sender = AAH_TXSender::GetInstance();
+ if (mAAH_Sender == NULL) {
+ return NO_MEMORY;
+ }
+
+ if (!mQueueStarted) {
+ mQueue.start();
+ mQueueStarted = true;
+ }
+
+ mFlags |= PREPARING;
+ mAsyncPrepareEvent = new AAH_TXEvent(
+ this, &AAH_TXPlayer::onPrepareAsyncEvent);
+
+ mQueue.postEvent(mAsyncPrepareEvent);
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::finishSetDataSource_l() {
+ sp<DataSource> dataSource;
+
+ if (!strncasecmp("http://", mUri.string(), 7) ||
+ !strncasecmp("https://", mUri.string(), 8)) {
+
+ mConnectingDataSource = HTTPBase::Create(
+ (mFlags & INCOGNITO)
+ ? HTTPBase::kFlagIncognito
+ : 0);
+
+ mLock.unlock();
+ status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
+ mLock.lock();
+
+ if (err != OK) {
+ mConnectingDataSource.clear();
+
+ ALOGI("mConnectingDataSource->connect() returned %d", err);
+ return err;
+ }
+
+ mCachedSource = new NuCachedSource2(mConnectingDataSource);
+ mConnectingDataSource.clear();
+
+ dataSource = mCachedSource;
+
+ // We're going to prefill the cache before trying to instantiate
+ // the extractor below, as the latter is an operation that otherwise
+ // could block on the datasource for a significant amount of time.
+ // During that time we'd be unable to abort the preparation phase
+ // without this prefill.
+
+ mLock.unlock();
+
+ for (;;) {
+ status_t finalStatus;
+ size_t cachedDataRemaining =
+ mCachedSource->approxDataRemaining(&finalStatus);
+
+ if (finalStatus != OK ||
+ cachedDataRemaining >= kHighWaterMarkBytes ||
+ (mFlags & PREPARE_CANCELLED)) {
+ break;
+ }
+
+ usleep(200000);
+ }
+
+ mLock.lock();
+
+ if (mFlags & PREPARE_CANCELLED) {
+ ALOGI("Prepare cancelled while waiting for initial cache fill.");
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+ }
+
+ if (dataSource == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ return setDataSource_l(extractor);
+}
+
+status_t AAH_TXPlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+ // Attempt to approximate overall stream bitrate by summing all
+ // tracks' individual bitrates, if not all of them advertise bitrate,
+ // we have to fail.
+
+ int64_t totalBitRate = 0;
+
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+ int32_t bitrate;
+ if (!meta->findInt32(kKeyBitRate, &bitrate)) {
+ totalBitRate = -1;
+ break;
+ }
+
+ totalBitRate += bitrate;
+ }
+
+ mBitrate = totalBitRate;
+
+ ALOGV("mBitrate = %lld bits/sec", mBitrate);
+
+ bool haveAudio = false;
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strncasecmp(mime, "audio/", 6)) {
+ mAudioSource = extractor->getTrack(i);
+ CHECK(mAudioSource != NULL);
+ haveAudio = true;
+ break;
+ }
+ }
+
+ if (!haveAudio) {
+ return UNKNOWN_ERROR;
+ }
+
+ mExtractorFlags = extractor->flags();
+
+ return OK;
+}
+
+void AAH_TXPlayer::abortPrepare(status_t err) {
+ CHECK(err != OK);
+
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+
+ mPrepareResult = err;
+ mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
+ mPreparedCondition.broadcast();
+}
+
+void AAH_TXPlayer::onPrepareAsyncEvent() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mFlags & PREPARE_CANCELLED) {
+ ALOGI("prepare was cancelled before doing anything");
+ abortPrepare(UNKNOWN_ERROR);
+ return;
+ }
+
+ if (mUri.size() > 0) {
+ status_t err = finishSetDataSource_l();
+
+ if (err != OK) {
+ abortPrepare(err);
+ return;
+ }
+ }
+
+ mAudioSource->getFormat()->findInt64(kKeyDuration, &mDurationUs);
+
+ status_t err = mAudioSource->start();
+ if (err != OK) {
+ ALOGI("failed to start audio source, err=%d", err);
+ abortPrepare(err);
+ return;
+ }
+
+ mFlags |= PREPARING_CONNECTED;
+
+ if (mCachedSource != NULL) {
+ postBufferingEvent_l();
+ } else {
+ finishAsyncPrepare_l();
+ }
+}
+
+void AAH_TXPlayer::finishAsyncPrepare_l() {
+ notifyListener_l(MEDIA_PREPARED);
+
+ mPrepareResult = OK;
+ mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
+ mFlags |= PREPARED;
+ mPreparedCondition.broadcast();
+}
+
+status_t AAH_TXPlayer::start() {
+ Mutex::Autolock autoLock(mLock);
+
+ mFlags &= ~CACHE_UNDERRUN;
+
+ return play_l();
+}
+
+status_t AAH_TXPlayer::play_l() {
+ if (mFlags & PLAYING) {
+ return OK;
+ }
+
+ if (!(mFlags & PREPARED)) {
+ return INVALID_OPERATION;
+ }
+
+ {
+ Mutex::Autolock lock(mEndpointLock);
+ if (!mEndpointValid) {
+ return INVALID_OPERATION;
+ }
+ if (!mEndpointRegistered) {
+ mProgramID = mAAH_Sender->registerEndpoint(mEndpoint);
+ mEndpointRegistered = true;
+ }
+ }
+
+ mFlags |= PLAYING;
+
+ updateClockTransform_l(false);
+
+ postPumpAudioEvent_l(-1);
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::stop() {
+ status_t ret = pause();
+ sendEOS_l();
+ return ret;
+}
+
+status_t AAH_TXPlayer::pause() {
+ Mutex::Autolock autoLock(mLock);
+
+ mFlags &= ~CACHE_UNDERRUN;
+
+ return pause_l();
+}
+
+status_t AAH_TXPlayer::pause_l(bool doClockUpdate) {
+ if (!(mFlags & PLAYING)) {
+ return OK;
+ }
+
+ cancelPlayerEvents(true /* keepBufferingGoing */);
+
+ mFlags &= ~PLAYING;
+
+ if (doClockUpdate) {
+ updateClockTransform_l(true);
+ }
+
+ return OK;
+}
+
+void AAH_TXPlayer::updateClockTransform_l(bool pause) {
+ // record the new pause status so that onPumpAudio knows what rate to apply
+ // when it initializes the transform
+ mPlayRateIsPaused = pause;
+
+ // if we haven't yet established a valid clock transform, then we can't
+ // do anything here
+ if (!mCurrentClockTransformValid) {
+ return;
+ }
+
+ // sample the current common time
+ int64_t commonTimeNow;
+ if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
+ ALOGE("updateClockTransform_l get common time failed");
+ mCurrentClockTransformValid = false;
+ return;
+ }
+
+ // convert the current common time to media time using the old
+ // transform
+ int64_t mediaTimeNow;
+ if (!mCurrentClockTransform.doReverseTransform(
+ commonTimeNow, &mediaTimeNow)) {
+ ALOGE("updateClockTransform_l reverse transform failed");
+ mCurrentClockTransformValid = false;
+ return;
+ }
+
+ // calculate a new transform that preserves the old transform's
+ // result for the current time
+ mCurrentClockTransform.a_zero = mediaTimeNow;
+ mCurrentClockTransform.b_zero = commonTimeNow;
+ mCurrentClockTransform.a_to_b_numer = 1;
+ mCurrentClockTransform.a_to_b_denom = pause ? 0 : 1;
+
+ // send a packet announcing the new transform
+ sp<TRTPControlPacket> packet = new TRTPControlPacket();
+ packet->setClockTransform(mCurrentClockTransform);
+ packet->setCommandID(TRTPControlPacket::kCommandNop);
+ queuePacketToSender_l(packet);
+}
+
+void AAH_TXPlayer::sendEOS_l() {
+ sp<TRTPControlPacket> packet = new TRTPControlPacket();
+ packet->setCommandID(TRTPControlPacket::kCommandEOS);
+ queuePacketToSender_l(packet);
+}
+
+bool AAH_TXPlayer::isPlaying() {
+ return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
+}
+
+status_t AAH_TXPlayer::seekTo(int msec) {
+ if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+ Mutex::Autolock autoLock(mLock);
+ return seekTo_l(static_cast<int64_t>(msec) * 1000);
+ }
+
+ notifyListener_l(MEDIA_SEEK_COMPLETE);
+ return OK;
+}
+
+status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) {
+ mIsSeeking = true;
+ mSeekTimeUs = timeUs;
+
+ mCurrentClockTransformValid = false;
+ mLastQueuedMediaTimePTSValid = false;
+
+ // send a flush command packet
+ sp<TRTPControlPacket> packet = new TRTPControlPacket();
+ packet->setCommandID(TRTPControlPacket::kCommandFlush);
+ queuePacketToSender_l(packet);
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::getCurrentPosition(int *msec) {
+ if (!msec) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mLock);
+
+ int position;
+
+ if (mIsSeeking) {
+ position = mSeekTimeUs / 1000;
+ } else if (mCurrentClockTransformValid) {
+ // sample the current common time
+ int64_t commonTimeNow;
+ if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
+ ALOGE("getCurrentPosition get common time failed");
+ return INVALID_OPERATION;
+ }
+
+ int64_t mediaTimeNow;
+ if (!mCurrentClockTransform.doReverseTransform(commonTimeNow,
+ &mediaTimeNow)) {
+ ALOGE("getCurrentPosition reverse transform failed");
+ return INVALID_OPERATION;
+ }
+
+ position = static_cast<int>(mediaTimeNow / 1000);
+ } else {
+ position = 0;
+ }
+
+ int duration;
+ if (getDuration_l(&duration) == OK) {
+ *msec = clamp(position, 0, duration);
+ } else {
+ *msec = (position >= 0) ? position : 0;
+ }
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::getDuration(int* msec) {
+ if (!msec) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mLock);
+
+ return getDuration_l(msec);
+}
+
+status_t AAH_TXPlayer::getDuration_l(int* msec) {
+ if (mDurationUs < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ *msec = (mDurationUs + 500) / 1000;
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::reset() {
+ Mutex::Autolock autoLock(mLock);
+ reset_l();
+ return OK;
+}
+
+void AAH_TXPlayer::reset_l() {
+ if (mFlags & PREPARING) {
+ mFlags |= PREPARE_CANCELLED;
+ if (mConnectingDataSource != NULL) {
+ ALOGI("interrupting the connection process");
+ mConnectingDataSource->disconnect();
+ }
+
+ if (mFlags & PREPARING_CONNECTED) {
+ // We are basically done preparing, we're just buffering
+ // enough data to start playback, we can safely interrupt that.
+ finishAsyncPrepare_l();
+ }
+ }
+
+ while (mFlags & PREPARING) {
+ mPreparedCondition.wait(mLock);
+ }
+
+ cancelPlayerEvents();
+
+ sendEOS_l();
+
+ mCachedSource.clear();
+
+ if (mAudioSource != NULL) {
+ mAudioSource->stop();
+ }
+ mAudioSource.clear();
+
+ mFlags = 0;
+ mExtractorFlags = 0;
+
+ mDurationUs = -1;
+ mIsSeeking = false;
+ mSeekTimeUs = 0;
+
+ mUri.setTo("");
+ mUriHeaders.clear();
+
+ mFileSource.clear();
+
+ mBitrate = -1;
+
+ {
+ Mutex::Autolock lock(mEndpointLock);
+ if (mAAH_Sender != NULL && mEndpointRegistered) {
+ mAAH_Sender->unregisterEndpoint(mEndpoint);
+ }
+ mEndpointRegistered = false;
+ mEndpointValid = false;
+ }
+
+ mProgramID = 0;
+
+ mAAH_Sender.clear();
+ mLastQueuedMediaTimePTSValid = false;
+ mCurrentClockTransformValid = false;
+ mPlayRateIsPaused = false;
+
+ mTRTPVolume = 255;
+}
+
+status_t AAH_TXPlayer::setLooping(int loop) {
+ return OK;
+}
+
+player_type AAH_TXPlayer::playerType() {
+ return AAH_TX_PLAYER;
+}
+
+status_t AAH_TXPlayer::setParameter(int key, const Parcel &request) {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_TXPlayer::getParameter(int key, Parcel *reply) {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) {
+ if (!reply) {
+ return BAD_VALUE;
+ }
+
+ int32_t methodID;
+ status_t err = request.readInt32(&methodID);
+ if (err != android::OK) {
+ return err;
+ }
+
+ switch (methodID) {
+ case kInvokeSetAAHDstIPPort:
+ case kInvokeSetAAHConfigBlob: {
+ if (mEndpointValid) {
+ return INVALID_OPERATION;
+ }
+
+ String8 addr;
+ uint16_t port;
+
+ if (methodID == kInvokeSetAAHDstIPPort) {
+ addr = String8(request.readString16());
+
+ int32_t port32;
+ err = request.readInt32(&port32);
+ if (err != android::OK) {
+ return err;
+ }
+ port = static_cast<uint16_t>(port32);
+ } else {
+ String8 blob(request.readString16());
+
+ char addr_buf[101];
+ if (sscanf(blob.string(), "V1:%100s %" SCNu16,
+ addr_buf, &port) != 2) {
+ return BAD_VALUE;
+ }
+ if (addr.setTo(addr_buf) != OK) {
+ return NO_MEMORY;
+ }
+ }
+
+ struct hostent* ent = gethostbyname(addr.string());
+ if (ent == NULL) {
+ return ERROR_UNKNOWN_HOST;
+ }
+ if (!(ent->h_addrtype == AF_INET && ent->h_length == 4)) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mEndpointLock);
+ mEndpoint = AAH_TXSender::Endpoint(
+ reinterpret_cast<struct in_addr*>(ent->h_addr)->s_addr,
+ port);
+ mEndpointValid = true;
+ return OK;
+ };
+
+ default:
+ return INVALID_OPERATION;
+ }
+}
+
+status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids,
+ Parcel* records) {
+ using media::Metadata;
+
+ Metadata metadata(records);
+
+ metadata.appendBool(Metadata::kPauseAvailable, true);
+ metadata.appendBool(Metadata::kSeekBackwardAvailable, false);
+ metadata.appendBool(Metadata::kSeekForwardAvailable, false);
+ metadata.appendBool(Metadata::kSeekAvailable, false);
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::setVolume(float leftVolume, float rightVolume) {
+ if (leftVolume != rightVolume) {
+ ALOGE("%s does not support per channel volume: %f, %f",
+ __PRETTY_FUNCTION__, leftVolume, rightVolume);
+ }
+
+ float volume = clamp(leftVolume, 0.0f, 1.0f);
+
+ Mutex::Autolock lock(mLock);
+ mTRTPVolume = static_cast<uint8_t>((leftVolume * 255.0) + 0.5);
+
+ return OK;
+}
+
+status_t AAH_TXPlayer::setAudioStreamType(audio_stream_type_t streamType) {
+ return OK;
+}
+
+void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) {
+ sendEvent(msg, ext1, ext2);
+}
+
+bool AAH_TXPlayer::getBitrate_l(int64_t *bitrate) {
+ off64_t size;
+ if (mDurationUs >= 0 &&
+ mCachedSource != NULL &&
+ mCachedSource->getSize(&size) == OK) {
+ *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
+ return true;
+ }
+
+ if (mBitrate >= 0) {
+ *bitrate = mBitrate;
+ return true;
+ }
+
+ *bitrate = 0;
+
+ return false;
+}
+
+// Returns true iff cached duration is available/applicable.
+bool AAH_TXPlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
+ int64_t bitrate;
+
+ if (mCachedSource != NULL && getBitrate_l(&bitrate)) {
+ status_t finalStatus;
+ size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
+ &finalStatus);
+ *durationUs = cachedDataRemaining * 8000000ll / bitrate;
+ *eos = (finalStatus != OK);
+ return true;
+ }
+
+ return false;
+}
+
+void AAH_TXPlayer::ensureCacheIsFetching_l() {
+ if (mCachedSource != NULL) {
+ mCachedSource->resumeFetchingIfNecessary();
+ }
+}
+
+void AAH_TXPlayer::postBufferingEvent_l() {
+ if (mBufferingEventPending) {
+ return;
+ }
+ mBufferingEventPending = true;
+ mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
+}
+
+void AAH_TXPlayer::postPumpAudioEvent_l(int64_t delayUs) {
+ if (mPumpAudioEventPending) {
+ return;
+ }
+ mPumpAudioEventPending = true;
+ mQueue.postEventWithDelay(mPumpAudioEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void AAH_TXPlayer::onBufferingUpdate() {
+ Mutex::Autolock autoLock(mLock);
+ if (!mBufferingEventPending) {
+ return;
+ }
+ mBufferingEventPending = false;
+
+ if (mCachedSource != NULL) {
+ status_t finalStatus;
+ size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
+ &finalStatus);
+ bool eos = (finalStatus != OK);
+
+ if (eos) {
+ if (finalStatus == ERROR_END_OF_STREAM) {
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+ }
+ if (mFlags & PREPARING) {
+ ALOGV("cache has reached EOS, prepare is done.");
+ finishAsyncPrepare_l();
+ }
+ } else {
+ int64_t bitrate;
+ if (getBitrate_l(&bitrate)) {
+ size_t cachedSize = mCachedSource->cachedSize();
+ int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
+
+ int percentage = (100.0 * (double) cachedDurationUs)
+ / mDurationUs;
+ if (percentage > 100) {
+ percentage = 100;
+ }
+
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+ } else {
+ // We don't know the bitrate of the stream, use absolute size
+ // limits to maintain the cache.
+
+ if ((mFlags & PLAYING) &&
+ !eos &&
+ (cachedDataRemaining < kLowWaterMarkBytes)) {
+ ALOGI("cache is running low (< %d) , pausing.",
+ kLowWaterMarkBytes);
+ mFlags |= CACHE_UNDERRUN;
+ pause_l();
+ ensureCacheIsFetching_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+ } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
+ if (mFlags & CACHE_UNDERRUN) {
+ ALOGI("cache has filled up (> %d), resuming.",
+ kHighWaterMarkBytes);
+ mFlags &= ~CACHE_UNDERRUN;
+ play_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+ } else if (mFlags & PREPARING) {
+ ALOGV("cache has filled up (> %d), prepare is done",
+ kHighWaterMarkBytes);
+ finishAsyncPrepare_l();
+ }
+ }
+ }
+ }
+ }
+
+ int64_t cachedDurationUs;
+ bool eos;
+ if (getCachedDuration_l(&cachedDurationUs, &eos)) {
+ ALOGV("cachedDurationUs = %.2f secs, eos=%d",
+ cachedDurationUs / 1E6, eos);
+
+ if ((mFlags & PLAYING) &&
+ !eos &&
+ (cachedDurationUs < kLowWaterMarkUs)) {
+ ALOGI("cache is running low (%.2f secs) , pausing.",
+ cachedDurationUs / 1E6);
+ mFlags |= CACHE_UNDERRUN;
+ pause_l();
+ ensureCacheIsFetching_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+ } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
+ if (mFlags & CACHE_UNDERRUN) {
+ ALOGI("cache has filled up (%.2f secs), resuming.",
+ cachedDurationUs / 1E6);
+ mFlags &= ~CACHE_UNDERRUN;
+ play_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+ } else if (mFlags & PREPARING) {
+ ALOGV("cache has filled up (%.2f secs), prepare is done",
+ cachedDurationUs / 1E6);
+ finishAsyncPrepare_l();
+ }
+ }
+ }
+
+ postBufferingEvent_l();
+}
+
+void AAH_TXPlayer::onPumpAudio() {
+ while (true) {
+ Mutex::Autolock autoLock(mLock);
+ // If this flag is clear, its because someone has externally canceled
+ // this pump operation (probably because we a resetting/shutting down).
+ // Get out immediately, do not reschedule ourselves.
+ if (!mPumpAudioEventPending) {
+ return;
+ }
+
+ // Start by checking if there is still work to be doing. If we have
+ // never queued a payload (so we don't know what the last queued PTS is)
+ // or we have never established a MediaTime->CommonTime transformation,
+ // then we have work to do (one time through this loop should establish
+ // both). Otherwise, we want to keep a fixed amt of presentation time
+ // worth of data buffered. If we cannot get common time (service is
+ // unavailable, or common time is undefined)) then we don't have a lot
+ // of good options here. For now, signal an error up to the app level
+ // and shut down the transmission pump.
+ int64_t commonTimeNow;
+ if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
+ // Failed to get common time; either the service is down or common
+ // time is not synced. Raise an error and shutdown the player.
+ ALOGE("*** Cannot pump audio, unable to fetch common time."
+ " Shutting down.");
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, UNKNOWN_ERROR);
+ mPumpAudioEventPending = false;
+ break;
+ }
+
+ if (mCurrentClockTransformValid && mLastQueuedMediaTimePTSValid) {
+ int64_t mediaTimeNow;
+ bool conversionResult = mCurrentClockTransform.doReverseTransform(
+ commonTimeNow,
+ &mediaTimeNow);
+ CHECK(conversionResult);
+
+ if ((mediaTimeNow +
+ kAAHBufferTimeUs -
+ mLastQueuedMediaTimePTS) <= 0) {
+ break;
+ }
+ }
+
+ MediaSource::ReadOptions options;
+ if (mIsSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+ }
+
+ MediaBuffer* mediaBuffer;
+ status_t err = mAudioSource->read(&mediaBuffer, &options);
+ if (err != NO_ERROR) {
+ if (err == ERROR_END_OF_STREAM) {
+ ALOGI("*** %s reached end of stream", __PRETTY_FUNCTION__);
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+ notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
+ pause_l(false);
+ sendEOS_l();
+ } else {
+ ALOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err);
+ }
+ return;
+ }
+
+ if (mIsSeeking) {
+ mIsSeeking = false;
+ notifyListener_l(MEDIA_SEEK_COMPLETE);
+ }
+
+ uint8_t* data = (static_cast<uint8_t*>(mediaBuffer->data()) +
+ mediaBuffer->range_offset());
+ ALOGV("*** %s got media buffer data=[%02hhx %02hhx %02hhx %02hhx]"
+ " offset=%d length=%d", __PRETTY_FUNCTION__,
+ data[0], data[1], data[2], data[3],
+ mediaBuffer->range_offset(), mediaBuffer->range_length());
+
+ int64_t mediaTimeUs;
+ CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &mediaTimeUs));
+ ALOGV("*** timeUs=%lld", mediaTimeUs);
+
+ if (!mCurrentClockTransformValid) {
+ if (OK == mCCHelper.getCommonTime(&commonTimeNow)) {
+ mCurrentClockTransform.a_zero = mediaTimeUs;
+ mCurrentClockTransform.b_zero = commonTimeNow +
+ kAAHStartupLeadTimeUs;
+ mCurrentClockTransform.a_to_b_numer = 1;
+ mCurrentClockTransform.a_to_b_denom = mPlayRateIsPaused ? 0 : 1;
+ mCurrentClockTransformValid = true;
+ } else {
+ // Failed to get common time; either the service is down or
+ // common time is not synced. Raise an error and shutdown the
+ // player.
+ ALOGE("*** Cannot begin transmission, unable to fetch common"
+ " time. Dropping sample with pts=%lld", mediaTimeUs);
+ notifyListener_l(MEDIA_ERROR,
+ MEDIA_ERROR_UNKNOWN,
+ UNKNOWN_ERROR);
+ mPumpAudioEventPending = false;
+ break;
+ }
+ }
+
+ ALOGV("*** transmitting packet with pts=%lld", mediaTimeUs);
+
+ sp<TRTPAudioPacket> packet = new TRTPAudioPacket();
+ packet->setPTS(mediaTimeUs);
+ packet->setSubstreamID(1);
+
+ packet->setCodecType(TRTPAudioPacket::kCodecMPEG1Audio);
+ packet->setVolume(mTRTPVolume);
+ // TODO : introduce a throttle for this so we can control the
+ // frequency with which transforms get sent.
+ packet->setClockTransform(mCurrentClockTransform);
+ packet->setAccessUnitData(data, mediaBuffer->range_length());
+ packet->setRandomAccessPoint(true);
+
+ queuePacketToSender_l(packet);
+ mediaBuffer->release();
+
+ mLastQueuedMediaTimePTSValid = true;
+ mLastQueuedMediaTimePTS = mediaTimeUs;
+ }
+
+ { // Explicit scope for the autolock pattern.
+ Mutex::Autolock autoLock(mLock);
+
+ // If someone externally has cleared this flag, its because we should be
+ // shutting down. Do not reschedule ourselves.
+ if (!mPumpAudioEventPending) {
+ return;
+ }
+
+ // Looks like no one canceled us explicitly. Clear our flag and post a
+ // new event to ourselves.
+ mPumpAudioEventPending = false;
+ postPumpAudioEvent_l(10000);
+ }
+}
+
+void AAH_TXPlayer::queuePacketToSender_l(const sp<TRTPPacket>& packet) {
+ if (mAAH_Sender == NULL) {
+ return;
+ }
+
+ sp<AMessage> message = new AMessage(AAH_TXSender::kWhatSendPacket,
+ mAAH_Sender->handlerID());
+
+ {
+ Mutex::Autolock lock(mEndpointLock);
+ if (!mEndpointValid) {
+ return;
+ }
+
+ message->setInt32(AAH_TXSender::kSendPacketIPAddr, mEndpoint.addr);
+ message->setInt32(AAH_TXSender::kSendPacketPort, mEndpoint.port);
+ }
+
+ packet->setProgramID(mProgramID);
+ packet->setExpireTime(systemTime() + kAAHRetryKeepAroundTimeNs);
+ packet->pack();
+
+ message->setObject(AAH_TXSender::kSendPacketTRTPPacket, packet);
+
+ message->post();
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h
new file mode 100644
index 0000000..64cf5dc1
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_player.h
@@ -0,0 +1,179 @@
+/*
+ * 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 __AAH_TX_PLAYER_H__
+#define __AAH_TX_PLAYER_H__
+
+#include <common_time/cc_helper.h>
+#include <libstagefright/include/HTTPBase.h>
+#include <libstagefright/include/NuCachedSource2.h>
+#include <libstagefright/include/TimedEventQueue.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/LinearTransform.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include "aah_tx_sender.h"
+
+namespace android {
+
+class AAH_TXPlayer : public MediaPlayerHWInterface {
+ public:
+ AAH_TXPlayer();
+
+ virtual status_t initCheck();
+ virtual status_t setDataSource(const char *url,
+ const KeyedVector<String8, String8>*
+ headers);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setVideoSurface(const sp<Surface>& surface);
+ virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>&
+ surfaceTexture);
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t seekTo(int msec);
+ virtual status_t getCurrentPosition(int *msec);
+ virtual status_t getDuration(int *msec);
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType();
+ virtual status_t setParameter(int key, const Parcel &request);
+ virtual status_t getParameter(int key, Parcel *reply);
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+ virtual status_t getMetadata(const media::Metadata::Filter& ids,
+ Parcel* records);
+ virtual status_t setVolume(float leftVolume, float rightVolume);
+ virtual status_t setAudioStreamType(audio_stream_type_t streamType);
+
+ // invoke method IDs
+ enum {
+ // set the IP address and port of the A@H receiver
+ kInvokeSetAAHDstIPPort = 1,
+
+ // set the destination IP address and port (and perhaps any additional
+ // parameters added in the future) packaged in one string
+ kInvokeSetAAHConfigBlob,
+ };
+
+ static const int64_t kAAHRetryKeepAroundTimeNs;
+
+ protected:
+ virtual ~AAH_TXPlayer();
+
+ private:
+ friend struct AwesomeEvent;
+
+ enum {
+ PLAYING = 1,
+ PREPARING = 8,
+ PREPARED = 16,
+ PREPARE_CANCELLED = 64,
+ CACHE_UNDERRUN = 128,
+
+ // We are basically done preparing but are currently buffering
+ // sufficient data to begin playback and finish the preparation
+ // phase for good.
+ PREPARING_CONNECTED = 2048,
+
+ INCOGNITO = 32768,
+ };
+
+ status_t setDataSource_l(const char *url,
+ const KeyedVector<String8, String8> *headers);
+ status_t setDataSource_l(const sp<MediaExtractor>& extractor);
+ status_t finishSetDataSource_l();
+ status_t prepareAsync_l();
+ void onPrepareAsyncEvent();
+ void finishAsyncPrepare_l();
+ void abortPrepare(status_t err);
+ status_t play_l();
+ status_t pause_l(bool doClockUpdate = true);
+ status_t seekTo_l(int64_t timeUs);
+ void updateClockTransform_l(bool pause);
+ void sendEOS_l();
+ void cancelPlayerEvents(bool keepBufferingGoing = false);
+ void reset_l();
+ void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
+ bool getBitrate_l(int64_t* bitrate);
+ status_t getDuration_l(int* msec);
+ bool getCachedDuration_l(int64_t* durationUs, bool* eos);
+ void ensureCacheIsFetching_l();
+ void postBufferingEvent_l();
+ void postPumpAudioEvent_l(int64_t delayUs);
+ void onBufferingUpdate();
+ void onPumpAudio();
+ void queuePacketToSender_l(const sp<TRTPPacket>& packet);
+
+ Mutex mLock;
+
+ TimedEventQueue mQueue;
+ bool mQueueStarted;
+
+ sp<TimedEventQueue::Event> mBufferingEvent;
+ bool mBufferingEventPending;
+
+ uint32_t mFlags;
+ uint32_t mExtractorFlags;
+
+ String8 mUri;
+ KeyedVector<String8, String8> mUriHeaders;
+
+ sp<DataSource> mFileSource;
+
+ sp<TimedEventQueue::Event> mAsyncPrepareEvent;
+ Condition mPreparedCondition;
+ status_t mPrepareResult;
+
+ bool mIsSeeking;
+ int64_t mSeekTimeUs;
+
+ sp<TimedEventQueue::Event> mPumpAudioEvent;
+ bool mPumpAudioEventPending;
+
+ sp<HTTPBase> mConnectingDataSource;
+ sp<NuCachedSource2> mCachedSource;
+
+ sp<MediaSource> mAudioSource;
+ int64_t mDurationUs;
+ int64_t mBitrate;
+
+ sp<AAH_TXSender> mAAH_Sender;
+ LinearTransform mCurrentClockTransform;
+ bool mCurrentClockTransformValid;
+ int64_t mLastQueuedMediaTimePTS;
+ bool mLastQueuedMediaTimePTSValid;
+ bool mPlayRateIsPaused;
+ CCHelper mCCHelper;
+
+ Mutex mEndpointLock;
+ AAH_TXSender::Endpoint mEndpoint;
+ bool mEndpointValid;
+ bool mEndpointRegistered;
+ uint16_t mProgramID;
+ uint8_t mTRTPVolume;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer);
+};
+
+} // namespace android
+
+#endif // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp
new file mode 100644
index 0000000..d991ea7
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_sender.cpp
@@ -0,0 +1,602 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <netinet/in.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <utils/misc.h>
+
+#include "aah_tx_player.h"
+#include "aah_tx_sender.h"
+
+namespace android {
+
+const char* AAH_TXSender::kSendPacketIPAddr = "ipaddr";
+const char* AAH_TXSender::kSendPacketPort = "port";
+const char* AAH_TXSender::kSendPacketTRTPPacket = "trtp";
+
+const int AAH_TXSender::kRetryTrimIntervalUs = 100000;
+const int AAH_TXSender::kHeartbeatIntervalUs = 1000000;
+const int AAH_TXSender::kRetryBufferCapacity = 100;
+const nsecs_t AAH_TXSender::kHeartbeatTimeout = 600ull * 1000000000ull;
+
+Mutex AAH_TXSender::sLock;
+wp<AAH_TXSender> AAH_TXSender::sInstance;
+uint32_t AAH_TXSender::sNextEpoch;
+bool AAH_TXSender::sNextEpochValid = false;
+
+AAH_TXSender::AAH_TXSender() : mSocket(-1) {
+ mLastSentPacketTime = systemTime();
+}
+
+sp<AAH_TXSender> AAH_TXSender::GetInstance() {
+ Mutex::Autolock autoLock(sLock);
+
+ sp<AAH_TXSender> sender = sInstance.promote();
+
+ if (sender == NULL) {
+ sender = new AAH_TXSender();
+ if (sender == NULL) {
+ return NULL;
+ }
+
+ sender->mLooper = new ALooper();
+ if (sender->mLooper == NULL) {
+ return NULL;
+ }
+
+ sender->mReflector = new AHandlerReflector<AAH_TXSender>(sender.get());
+ if (sender->mReflector == NULL) {
+ return NULL;
+ }
+
+ sender->mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sender->mSocket == -1) {
+ ALOGW("%s unable to create socket", __PRETTY_FUNCTION__);
+ return NULL;
+ }
+
+ struct sockaddr_in bind_addr;
+ memset(&bind_addr, 0, sizeof(bind_addr));
+ bind_addr.sin_family = AF_INET;
+ if (bind(sender->mSocket,
+ reinterpret_cast<const sockaddr*>(&bind_addr),
+ sizeof(bind_addr)) < 0) {
+ ALOGW("%s unable to bind socket (errno %d)",
+ __PRETTY_FUNCTION__, errno);
+ return NULL;
+ }
+
+ sender->mRetryReceiver = new RetryReceiver(sender.get());
+ if (sender->mRetryReceiver == NULL) {
+ return NULL;
+ }
+
+ sender->mLooper->setName("AAH_TXSender");
+ sender->mLooper->registerHandler(sender->mReflector);
+ sender->mLooper->start(false, false, PRIORITY_AUDIO);
+
+ if (sender->mRetryReceiver->run("AAH_TXSenderRetry", PRIORITY_AUDIO)
+ != OK) {
+ ALOGW("%s unable to start retry thread", __PRETTY_FUNCTION__);
+ return NULL;
+ }
+
+ sInstance = sender;
+ }
+
+ return sender;
+}
+
+AAH_TXSender::~AAH_TXSender() {
+ mLooper->stop();
+ mLooper->unregisterHandler(mReflector->id());
+
+ if (mRetryReceiver != NULL) {
+ mRetryReceiver->requestExit();
+ mRetryReceiver->mWakeupEvent.setEvent();
+ if (mRetryReceiver->requestExitAndWait() != OK) {
+ ALOGW("%s shutdown of retry receiver failed", __PRETTY_FUNCTION__);
+ }
+ mRetryReceiver->mSender = NULL;
+ mRetryReceiver.clear();
+ }
+
+ if (mSocket != -1) {
+ close(mSocket);
+ }
+}
+
+// Return the next epoch number usable for a newly instantiated endpoint.
+uint32_t AAH_TXSender::getNextEpoch() {
+ Mutex::Autolock autoLock(sLock);
+
+ if (sNextEpochValid) {
+ sNextEpoch = (sNextEpoch + 1) & TRTPPacket::kTRTPEpochMask;
+ } else {
+ sNextEpoch = ns2ms(systemTime()) & TRTPPacket::kTRTPEpochMask;
+ sNextEpochValid = true;
+ }
+
+ return sNextEpoch;
+}
+
+// Notify the sender that a player has started sending to this endpoint.
+// Returns a program ID for use by the calling player.
+uint16_t AAH_TXSender::registerEndpoint(const Endpoint& endpoint) {
+ Mutex::Autolock lock(mEndpointLock);
+
+ EndpointState* eps = mEndpointMap.valueFor(endpoint);
+ if (eps) {
+ eps->playerRefCount++;
+ } else {
+ eps = new EndpointState(getNextEpoch());
+ mEndpointMap.add(endpoint, eps);
+ }
+
+ // if this is the first registered endpoint, then send a message to start
+ // trimming retry buffers and a message to start sending heartbeats.
+ if (mEndpointMap.size() == 1) {
+ sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
+ handlerID());
+ trimMessage->post(kRetryTrimIntervalUs);
+
+ sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
+ handlerID());
+ heartbeatMessage->post(kHeartbeatIntervalUs);
+ }
+
+ eps->nextProgramID++;
+ return eps->nextProgramID;
+}
+
+// Notify the sender that a player has ceased sending to this endpoint.
+// An endpoint's state can not be deleted until all of the endpoint's
+// registered players have called unregisterEndpoint.
+void AAH_TXSender::unregisterEndpoint(const Endpoint& endpoint) {
+ Mutex::Autolock lock(mEndpointLock);
+
+ EndpointState* eps = mEndpointMap.valueFor(endpoint);
+ if (eps) {
+ eps->playerRefCount--;
+ CHECK(eps->playerRefCount >= 0);
+ }
+}
+
+void AAH_TXSender::onMessageReceived(const sp<AMessage>& msg) {
+ switch (msg->what()) {
+ case kWhatSendPacket:
+ onSendPacket(msg);
+ break;
+
+ case kWhatTrimRetryBuffers:
+ trimRetryBuffers();
+ break;
+
+ case kWhatSendHeartbeats:
+ sendHeartbeats();
+ break;
+
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
+void AAH_TXSender::onSendPacket(const sp<AMessage>& msg) {
+ sp<RefBase> obj;
+ CHECK(msg->findObject(kSendPacketTRTPPacket, &obj));
+ sp<TRTPPacket> packet = static_cast<TRTPPacket*>(obj.get());
+
+ uint32_t ipAddr;
+ CHECK(msg->findInt32(kSendPacketIPAddr,
+ reinterpret_cast<int32_t*>(&ipAddr)));
+
+ int32_t port32;
+ CHECK(msg->findInt32(kSendPacketPort, &port32));
+ uint16_t port = port32;
+
+ Mutex::Autolock lock(mEndpointLock);
+ doSendPacket_l(packet, Endpoint(ipAddr, port));
+ mLastSentPacketTime = systemTime();
+}
+
+void AAH_TXSender::doSendPacket_l(const sp<TRTPPacket>& packet,
+ const Endpoint& endpoint) {
+ EndpointState* eps = mEndpointMap.valueFor(endpoint);
+ if (!eps) {
+ // the endpoint state has disappeared, so the player that sent this
+ // packet must be dead.
+ return;
+ }
+
+ // assign the packet's sequence number
+ packet->setEpoch(eps->epoch);
+ packet->setSeqNumber(eps->trtpSeqNumber++);
+
+ // add the packet to the retry buffer
+ RetryBuffer& retry = eps->retry;
+ retry.push_back(packet);
+
+ // send the packet
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = endpoint.addr;
+ addr.sin_port = htons(endpoint.port);
+
+ ssize_t result = sendto(mSocket,
+ packet->getPacket(),
+ packet->getPacketLen(),
+ 0,
+ (const struct sockaddr *) &addr,
+ sizeof(addr));
+ if (result == -1) {
+ ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+ }
+}
+
+void AAH_TXSender::trimRetryBuffers() {
+ Mutex::Autolock lock(mEndpointLock);
+
+ nsecs_t localTimeNow = systemTime();
+
+ Vector<Endpoint> endpointsToRemove;
+
+ for (size_t i = 0; i < mEndpointMap.size(); i++) {
+ EndpointState* eps = mEndpointMap.editValueAt(i);
+ RetryBuffer& retry = eps->retry;
+
+ while (!retry.isEmpty()) {
+ if (retry[0]->getExpireTime() < localTimeNow) {
+ retry.pop_front();
+ } else {
+ break;
+ }
+ }
+
+ if (retry.isEmpty() && eps->playerRefCount == 0) {
+ endpointsToRemove.add(mEndpointMap.keyAt(i));
+ }
+ }
+
+ // remove the state for any endpoints that are no longer in use
+ for (size_t i = 0; i < endpointsToRemove.size(); i++) {
+ Endpoint& e = endpointsToRemove.editItemAt(i);
+ ALOGD("*** %s removing endpoint addr=%08x", __PRETTY_FUNCTION__, e.addr);
+ size_t index = mEndpointMap.indexOfKey(e);
+ delete mEndpointMap.valueAt(index);
+ mEndpointMap.removeItemsAt(index);
+ }
+
+ // schedule the next trim
+ if (mEndpointMap.size()) {
+ sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
+ handlerID());
+ trimMessage->post(kRetryTrimIntervalUs);
+ }
+}
+
+void AAH_TXSender::sendHeartbeats() {
+ Mutex::Autolock lock(mEndpointLock);
+
+ if (shouldSendHeartbeats_l()) {
+ for (size_t i = 0; i < mEndpointMap.size(); i++) {
+ EndpointState* eps = mEndpointMap.editValueAt(i);
+ const Endpoint& ep = mEndpointMap.keyAt(i);
+
+ sp<TRTPControlPacket> packet = new TRTPControlPacket();
+ packet->setCommandID(TRTPControlPacket::kCommandNop);
+
+ packet->setExpireTime(systemTime() +
+ AAH_TXPlayer::kAAHRetryKeepAroundTimeNs);
+ packet->pack();
+
+ doSendPacket_l(packet, ep);
+ }
+ }
+
+ // schedule the next heartbeat
+ if (mEndpointMap.size()) {
+ sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
+ handlerID());
+ heartbeatMessage->post(kHeartbeatIntervalUs);
+ }
+}
+
+bool AAH_TXSender::shouldSendHeartbeats_l() {
+ // assert(holding endpoint lock)
+ return (systemTime() < (mLastSentPacketTime + kHeartbeatTimeout));
+}
+
+// Receiver
+
+// initial 4-byte ID of a retry request packet
+const uint32_t AAH_TXSender::RetryReceiver::kRetryRequestID = 'Treq';
+
+// initial 4-byte ID of a retry NAK packet
+const uint32_t AAH_TXSender::RetryReceiver::kRetryNakID = 'Tnak';
+
+// initial 4-byte ID of a fast start request packet
+const uint32_t AAH_TXSender::RetryReceiver::kFastStartRequestID = 'Tfst';
+
+AAH_TXSender::RetryReceiver::RetryReceiver(AAH_TXSender* sender)
+ : Thread(false),
+ mSender(sender) {}
+
+ AAH_TXSender::RetryReceiver::~RetryReceiver() {
+ mWakeupEvent.clearPendingEvents();
+ }
+
+// Returns true if val is within the interval bounded inclusively by
+// start and end. Also handles the case where there is a rollover of the
+// range between start and end.
+template <typename T>
+static inline bool withinIntervalWithRollover(T val, T start, T end) {
+ return ((start <= end && val >= start && val <= end) ||
+ (start > end && (val >= start || val <= end)));
+}
+
+bool AAH_TXSender::RetryReceiver::threadLoop() {
+ struct pollfd pollFds[2];
+ pollFds[0].fd = mSender->mSocket;
+ pollFds[0].events = POLLIN;
+ pollFds[0].revents = 0;
+ pollFds[1].fd = mWakeupEvent.getWakeupHandle();
+ pollFds[1].events = POLLIN;
+ pollFds[1].revents = 0;
+
+ int pollResult = poll(pollFds, NELEM(pollFds), -1);
+ if (pollResult == -1) {
+ ALOGE("%s poll failed", __PRETTY_FUNCTION__);
+ return false;
+ }
+
+ if (exitPending()) {
+ ALOGI("*** %s exiting", __PRETTY_FUNCTION__);
+ return false;
+ }
+
+ if (pollFds[0].revents) {
+ handleRetryRequest();
+ }
+
+ return true;
+}
+
+void AAH_TXSender::RetryReceiver::handleRetryRequest() {
+ ALOGV("*** RX %s start", __PRETTY_FUNCTION__);
+
+ RetryPacket request;
+ struct sockaddr requestSrcAddr;
+ socklen_t requestSrcAddrLen = sizeof(requestSrcAddr);
+
+ ssize_t result = recvfrom(mSender->mSocket, &request, sizeof(request), 0,
+ &requestSrcAddr, &requestSrcAddrLen);
+ if (result == -1) {
+ ALOGE("%s recvfrom failed, errno=%d", __PRETTY_FUNCTION__, errno);
+ return;
+ }
+
+ if (static_cast<size_t>(result) < sizeof(RetryPacket)) {
+ ALOGW("%s short packet received", __PRETTY_FUNCTION__);
+ return;
+ }
+
+ uint32_t host_request_id = ntohl(request.id);
+ if ((host_request_id != kRetryRequestID) &&
+ (host_request_id != kFastStartRequestID)) {
+ ALOGW("%s received retry request with bogus ID (%08x)",
+ __PRETTY_FUNCTION__, host_request_id);
+ return;
+ }
+
+ Endpoint endpoint(request.endpointIP, ntohs(request.endpointPort));
+
+ Mutex::Autolock lock(mSender->mEndpointLock);
+
+ EndpointState* eps = mSender->mEndpointMap.valueFor(endpoint);
+
+ if (eps == NULL || eps->retry.isEmpty()) {
+ // we have no retry buffer or an empty retry buffer for this endpoint,
+ // so NAK the entire request
+ RetryPacket nak = request;
+ nak.id = htonl(kRetryNakID);
+ result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+ &requestSrcAddr, requestSrcAddrLen);
+ if (result == -1) {
+ ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+ }
+ return;
+ }
+
+ RetryBuffer& retry = eps->retry;
+
+ uint16_t startSeq = ntohs(request.seqStart);
+ uint16_t endSeq = ntohs(request.seqEnd);
+
+ uint16_t retryFirstSeq = retry[0]->getSeqNumber();
+ uint16_t retryLastSeq = retry[retry.size() - 1]->getSeqNumber();
+
+ // If this is a fast start, then force the start of the retry to match the
+ // start of the retransmit ring buffer (unless the end of the retransmit
+ // ring buffer is already past the point of fast start)
+ if ((host_request_id == kFastStartRequestID) &&
+ !((startSeq - retryFirstSeq) & 0x8000)) {
+ startSeq = retryFirstSeq;
+ }
+
+ int startIndex;
+ if (withinIntervalWithRollover(startSeq, retryFirstSeq, retryLastSeq)) {
+ startIndex = static_cast<uint16_t>(startSeq - retryFirstSeq);
+ } else {
+ startIndex = -1;
+ }
+
+ int endIndex;
+ if (withinIntervalWithRollover(endSeq, retryFirstSeq, retryLastSeq)) {
+ endIndex = static_cast<uint16_t>(endSeq - retryFirstSeq);
+ } else {
+ endIndex = -1;
+ }
+
+ if (startIndex == -1 && endIndex == -1) {
+ // no part of the request range is found in the retry buffer
+ RetryPacket nak = request;
+ nak.id = htonl(kRetryNakID);
+ result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+ &requestSrcAddr, requestSrcAddrLen);
+ if (result == -1) {
+ ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+ }
+ return;
+ }
+
+ if (startIndex == -1) {
+ // NAK a subrange at the front of the request range
+ RetryPacket nak = request;
+ nak.id = htonl(kRetryNakID);
+ nak.seqEnd = htons(retryFirstSeq - 1);
+ result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+ &requestSrcAddr, requestSrcAddrLen);
+ if (result == -1) {
+ ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+ }
+
+ startIndex = 0;
+ } else if (endIndex == -1) {
+ // NAK a subrange at the back of the request range
+ RetryPacket nak = request;
+ nak.id = htonl(kRetryNakID);
+ nak.seqStart = htons(retryLastSeq + 1);
+ result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+ &requestSrcAddr, requestSrcAddrLen);
+ if (result == -1) {
+ ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+ }
+
+ endIndex = retry.size() - 1;
+ }
+
+ // send the retry packets
+ for (int i = startIndex; i <= endIndex; i++) {
+ const sp<TRTPPacket>& replyPacket = retry[i];
+
+ result = sendto(mSender->mSocket,
+ replyPacket->getPacket(),
+ replyPacket->getPacketLen(),
+ 0,
+ &requestSrcAddr,
+ requestSrcAddrLen);
+
+ if (result == -1) {
+ ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+ }
+ }
+}
+
+// Endpoint
+
+AAH_TXSender::Endpoint::Endpoint()
+ : addr(0)
+ , port(0) { }
+
+AAH_TXSender::Endpoint::Endpoint(uint32_t a, uint16_t p)
+ : addr(a)
+ , port(p) {}
+
+bool AAH_TXSender::Endpoint::operator<(const Endpoint& other) const {
+ return ((addr < other.addr) ||
+ (addr == other.addr && port < other.port));
+}
+
+// EndpointState
+
+AAH_TXSender::EndpointState::EndpointState(uint32_t _epoch)
+ : retry(kRetryBufferCapacity)
+ , playerRefCount(1)
+ , trtpSeqNumber(0)
+ , nextProgramID(0)
+ , epoch(_epoch) { }
+
+// CircularBuffer
+
+template <typename T>
+CircularBuffer<T>::CircularBuffer(size_t capacity)
+ : mCapacity(capacity)
+ , mHead(0)
+ , mTail(0)
+ , mFillCount(0) {
+ mBuffer = new T[capacity];
+}
+
+template <typename T>
+CircularBuffer<T>::~CircularBuffer() {
+ delete [] mBuffer;
+}
+
+template <typename T>
+void CircularBuffer<T>::push_back(const T& item) {
+ if (this->isFull()) {
+ this->pop_front();
+ }
+ mBuffer[mHead] = item;
+ mHead = (mHead + 1) % mCapacity;
+ mFillCount++;
+}
+
+template <typename T>
+void CircularBuffer<T>::pop_front() {
+ CHECK(!isEmpty());
+ mBuffer[mTail] = T();
+ mTail = (mTail + 1) % mCapacity;
+ mFillCount--;
+}
+
+template <typename T>
+size_t CircularBuffer<T>::size() const {
+ return mFillCount;
+}
+
+template <typename T>
+bool CircularBuffer<T>::isFull() const {
+ return (mFillCount == mCapacity);
+}
+
+template <typename T>
+bool CircularBuffer<T>::isEmpty() const {
+ return (mFillCount == 0);
+}
+
+template <typename T>
+const T& CircularBuffer<T>::itemAt(size_t index) const {
+ CHECK(index < mFillCount);
+ return mBuffer[(mTail + index) % mCapacity];
+}
+
+template <typename T>
+const T& CircularBuffer<T>::operator[](size_t index) const {
+ return itemAt(index);
+}
+
+} // namespace android
diff --git a/media/libaah_rtp/aah_tx_sender.h b/media/libaah_rtp/aah_tx_sender.h
new file mode 100644
index 0000000..74206c4
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_sender.h
@@ -0,0 +1,162 @@
+/*
+ * 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 __AAH_TX_SENDER_H__
+#define __AAH_TX_SENDER_H__
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include "aah_tx_packet.h"
+#include "pipe_event.h"
+
+namespace android {
+
+template <typename T> class CircularBuffer {
+ public:
+ CircularBuffer(size_t capacity);
+ ~CircularBuffer();
+ void push_back(const T& item);;
+ void pop_front();
+ size_t size() const;
+ bool isFull() const;
+ bool isEmpty() const;
+ const T& itemAt(size_t index) const;
+ const T& operator[](size_t index) const;
+
+ private:
+ T* mBuffer;
+ size_t mCapacity;
+ size_t mHead;
+ size_t mTail;
+ size_t mFillCount;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CircularBuffer);
+};
+
+class AAH_TXSender : public virtual RefBase {
+ public:
+ ~AAH_TXSender();
+
+ static sp<AAH_TXSender> GetInstance();
+
+ ALooper::handler_id handlerID() { return mReflector->id(); }
+
+ // an IP address and port
+ struct Endpoint {
+ Endpoint();
+ Endpoint(uint32_t a, uint16_t p);
+ bool operator<(const Endpoint& other) const;
+
+ uint32_t addr;
+ uint16_t port;
+ };
+
+ uint16_t registerEndpoint(const Endpoint& endpoint);
+ void unregisterEndpoint(const Endpoint& endpoint);
+
+ enum {
+ kWhatSendPacket,
+ kWhatTrimRetryBuffers,
+ kWhatSendHeartbeats,
+ };
+
+ // fields for SendPacket messages
+ static const char* kSendPacketIPAddr;
+ static const char* kSendPacketPort;
+ static const char* kSendPacketTRTPPacket;
+
+ private:
+ AAH_TXSender();
+
+ static Mutex sLock;
+ static wp<AAH_TXSender> sInstance;
+ static uint32_t sNextEpoch;
+ static bool sNextEpochValid;
+
+ static uint32_t getNextEpoch();
+
+ typedef CircularBuffer<sp<TRTPPacket> > RetryBuffer;
+
+ // state maintained on a per-endpoint basis
+ struct EndpointState {
+ EndpointState(uint32_t epoch);
+ RetryBuffer retry;
+ int playerRefCount;
+ uint16_t trtpSeqNumber;
+ uint16_t nextProgramID;
+ uint32_t epoch;
+ };
+
+ friend class AHandlerReflector<AAH_TXSender>;
+ void onMessageReceived(const sp<AMessage>& msg);
+ void onSendPacket(const sp<AMessage>& msg);
+ void doSendPacket_l(const sp<TRTPPacket>& packet,
+ const Endpoint& endpoint);
+ void trimRetryBuffers();
+ void sendHeartbeats();
+ bool shouldSendHeartbeats_l();
+
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<AAH_TXSender> > mReflector;
+
+ int mSocket;
+ nsecs_t mLastSentPacketTime;
+
+ DefaultKeyedVector<Endpoint, EndpointState*> mEndpointMap;
+ Mutex mEndpointLock;
+
+ static const int kRetryTrimIntervalUs;
+ static const int kHeartbeatIntervalUs;
+ static const int kRetryBufferCapacity;
+ static const nsecs_t kHeartbeatTimeout;
+
+ class RetryReceiver : public Thread {
+ private:
+ friend class AAH_TXSender;
+
+ RetryReceiver(AAH_TXSender* sender);
+ virtual ~RetryReceiver();
+ virtual bool threadLoop();
+ void handleRetryRequest();
+
+ static const int kMaxReceiverPacketLen;
+ static const uint32_t kRetryRequestID;
+ static const uint32_t kFastStartRequestID;
+ static const uint32_t kRetryNakID;
+
+ AAH_TXSender* mSender;
+ PipeEvent mWakeupEvent;
+ };
+
+ sp<RetryReceiver> mRetryReceiver;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AAH_TXSender);
+};
+
+struct RetryPacket {
+ uint32_t id;
+ uint32_t endpointIP;
+ uint16_t endpointPort;
+ uint16_t seqStart;
+ uint16_t seqEnd;
+} __attribute__((packed));
+
+} // namespace android
+
+#endif // __AAH_TX_SENDER_H__
diff --git a/media/libaah_rtp/pipe_event.cpp b/media/libaah_rtp/pipe_event.cpp
new file mode 100644
index 0000000..b8e6960
--- /dev/null
+++ b/media/libaah_rtp/pipe_event.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "pipe_event.h"
+
+namespace android {
+
+PipeEvent::PipeEvent() {
+ pipe_[0] = -1;
+ pipe_[1] = -1;
+
+ // Create the pipe.
+ if (pipe(pipe_) >= 0) {
+ // Set non-blocking mode on the read side of the pipe so we can
+ // easily drain it whenever we wakeup.
+ fcntl(pipe_[0], F_SETFL, O_NONBLOCK);
+ } else {
+ ALOGE("Failed to create pipe event %d %d %d",
+ pipe_[0], pipe_[1], errno);
+ pipe_[0] = -1;
+ pipe_[1] = -1;
+ }
+}
+
+PipeEvent::~PipeEvent() {
+ if (pipe_[0] >= 0) {
+ close(pipe_[0]);
+ }
+
+ if (pipe_[1] >= 0) {
+ close(pipe_[1]);
+ }
+}
+
+void PipeEvent::clearPendingEvents() {
+ char drain_buffer[16];
+ while (read(pipe_[0], drain_buffer, sizeof(drain_buffer)) > 0) {
+ // No body.
+ }
+}
+
+bool PipeEvent::wait(int timeout) {
+ struct pollfd wait_fd;
+
+ wait_fd.fd = getWakeupHandle();
+ wait_fd.events = POLLIN;
+ wait_fd.revents = 0;
+
+ int res = poll(&wait_fd, 1, timeout);
+
+ if (res < 0) {
+ ALOGE("Wait error in PipeEvent; sleeping to prevent overload!");
+ usleep(1000);
+ }
+
+ return (res > 0);
+}
+
+void PipeEvent::setEvent() {
+ char foo = 'q';
+ write(pipe_[1], &foo, 1);
+}
+
+} // namespace android
+
diff --git a/media/libaah_rtp/pipe_event.h b/media/libaah_rtp/pipe_event.h
new file mode 100644
index 0000000..e53b0fd
--- /dev/null
+++ b/media/libaah_rtp/pipe_event.h
@@ -0,0 +1,51 @@
+/*
+ * 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 __PIPE_EVENT_H__
+#define __PIPE_EVENT_H__
+
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+class PipeEvent {
+ public:
+ PipeEvent();
+ ~PipeEvent();
+
+ bool initCheck() const {
+ return ((pipe_[0] >= 0) && (pipe_[1] >= 0));
+ }
+
+ int getWakeupHandle() const { return pipe_[0]; }
+
+ // block until the event fires; returns true if the event fired and false if
+ // the wait timed out. Timeout is expressed in milliseconds; negative
+ // values mean wait forever.
+ bool wait(int timeout = -1);
+
+ void clearPendingEvents();
+ void setEvent();
+
+ private:
+ int pipe_[2];
+
+ DISALLOW_EVIL_CONSTRUCTORS(PipeEvent);
+};
+
+} // namespace android
+
+#endif // __PIPE_EVENT_H__
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 4d94a75..098a1a2 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1298,7 +1298,7 @@
return -EINVAL;
}
- Session_GetConfig(effect->session, (effect_config_t *)pCmdData);
+ Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
break;
case EFFECT_CMD_SET_CONFIG_REVERSE:
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 6549ce6..19b7e32 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -159,7 +159,7 @@
mCblk->buffer = (uint8_t *)mCblk + bufOffset;
iEffect->asBinder()->linkToDeath(mIEffectClient);
- ALOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled);
+ ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, mStatus, mEnabled);
return mStatus;
}
@@ -202,7 +202,7 @@
status_t AudioEffect::setEnabled(bool enabled)
{
if (mStatus != NO_ERROR) {
- return INVALID_OPERATION;
+ return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
}
status_t status = NO_ERROR;
@@ -231,7 +231,7 @@
{
if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
ALOGV("command() bad status %d", mStatus);
- return INVALID_OPERATION;
+ return mStatus;
}
if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
@@ -263,7 +263,7 @@
status_t AudioEffect::setParameter(effect_param_t *param)
{
if (mStatus != NO_ERROR) {
- return INVALID_OPERATION;
+ return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
}
if (param == NULL || param->psize == 0 || param->vsize == 0) {
@@ -281,7 +281,7 @@
status_t AudioEffect::setParameterDeferred(effect_param_t *param)
{
if (mStatus != NO_ERROR) {
- return INVALID_OPERATION;
+ return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
}
if (param == NULL || param->psize == 0 || param->vsize == 0) {
@@ -307,7 +307,7 @@
status_t AudioEffect::setParameterCommit()
{
if (mStatus != NO_ERROR) {
- return INVALID_OPERATION;
+ return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
}
Mutex::Autolock _l(mCblk->lock);
@@ -321,7 +321,7 @@
status_t AudioEffect::getParameter(effect_param_t *param)
{
if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
- return INVALID_OPERATION;
+ return mStatus;
}
if (param == NULL || param->psize == 0 || param->vsize == 0) {
@@ -341,7 +341,7 @@
void AudioEffect::binderDied()
{
ALOGW("IEffect died");
- mStatus = NO_INIT;
+ mStatus = DEAD_OBJECT;
if (mCbf != NULL) {
status_t status = DEAD_OBJECT;
mCbf(EVENT_ERROR, mUserData, &status);
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index b74b3e3..a4068ff 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -304,10 +304,25 @@
if (mActive == 0) {
mActive = 1;
+ pid_t tid;
+ if (t != 0) {
+ mReadyToRun = WOULD_BLOCK;
+ t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
+ tid = t->getTid(); // pid_t is unknown until run()
+ ALOGV("getTid=%d", tid);
+ if (tid == -1) {
+ tid = 0;
+ }
+ // thread blocks in readyToRun()
+ } else {
+ tid = 0; // not gettid()
+ }
+
cblk->lock.lock();
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
- ret = mAudioRecord->start();
+ ALOGV("mAudioRecord->start(tid=%d)", tid);
+ ret = mAudioRecord->start(tid);
cblk->lock.lock();
if (ret == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -322,7 +337,9 @@
cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
cblk->waitTimeMs = 0;
if (t != 0) {
- t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
+ // thread unblocks in readyToRun() and returns NO_ERROR
+ mReadyToRun = NO_ERROR;
+ mCondition.signal();
} else {
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
@@ -330,6 +347,9 @@
}
} else {
mActive = 0;
+ // thread unblocks in readyToRun() and returns NO_INIT
+ mReadyToRun = NO_INIT;
+ mCondition.signal();
}
}
@@ -522,7 +542,7 @@
ALOGW( "obtainBuffer timed out (is the CPU pegged?) "
"user=%08x, server=%08x", cblk->user, cblk->server);
cblk->lock.unlock();
- result = mAudioRecord->start();
+ result = mAudioRecord->start(0); // callback thread hasn't changed
cblk->lock.lock();
if (result == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -760,7 +780,7 @@
result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
mFrameCount, mFlags, getInput_l());
if (result == NO_ERROR) {
- result = mAudioRecord->start();
+ result = mAudioRecord->start(0); // callback thread hasn't changed
}
if (result != NO_ERROR) {
mActive = false;
@@ -811,6 +831,15 @@
return mReceiver.processAudioBuffer(this);
}
+status_t AudioRecord::ClientRecordThread::readyToRun()
+{
+ AutoMutex(mReceiver.mLock);
+ while (mReceiver.mReadyToRun == WOULD_BLOCK) {
+ mReceiver.mCondition.wait(mReceiver.mLock);
+ }
+ return mReceiver.mReadyToRun;
+}
+
// -------------------------------------------------------------------------
}; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 087d7b2..74c97ed 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1,4 +1,4 @@
-/* frameworks/base/media/libmedia/AudioTrack.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -80,7 +80,9 @@
AudioTrack::AudioTrack()
: mStatus(NO_INIT),
- mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
+ mIsTimed(false),
+ mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+ mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
{
}
@@ -96,7 +98,9 @@
int notificationFrames,
int sessionId)
: mStatus(NO_INIT),
- mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
+ mIsTimed(false),
+ mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+ mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
@@ -134,7 +138,9 @@
int notificationFrames,
int sessionId)
: mStatus(NO_INIT),
- mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
+ mIsTimed(false),
+ mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+ mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
{
mStatus = set(streamType, sampleRate, format, channelMask,
0, flags, cbf, user, notificationFrames,
@@ -362,18 +368,26 @@
cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
cblk->waitTimeMs = 0;
android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
+ pid_t tid;
if (t != 0) {
t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO);
+ tid = t->getTid(); // pid_t is unknown until run()
+ ALOGV("getTid=%d", tid);
+ if (tid == -1) {
+ tid = 0;
+ }
} else {
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+ tid = 0; // not gettid()
}
ALOGV("start %p before lock cblk %p", this, mCblk);
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
- status = mAudioTrack->start();
+ ALOGV("mAudioTrack->start(tid=%d)", tid);
+ status = mAudioTrack->start(tid);
cblk->lock.lock();
if (status == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -532,6 +546,10 @@
{
int afSamplingRate;
+ if (mIsTimed) {
+ return INVALID_OPERATION;
+ }
+
if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
return NO_INIT;
}
@@ -545,6 +563,10 @@
uint32_t AudioTrack::getSampleRate() const
{
+ if (mIsTimed) {
+ return INVALID_OPERATION;
+ }
+
AutoMutex lock(mLock);
return mCblk->sampleRate;
}
@@ -570,6 +592,10 @@
return NO_ERROR;
}
+ if (mIsTimed) {
+ return INVALID_OPERATION;
+ }
+
if (loopStart >= loopEnd ||
loopEnd - loopStart > cblk->frameCount ||
cblk->server > loopStart) {
@@ -591,26 +617,6 @@
return NO_ERROR;
}
-status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const
-{
- AutoMutex lock(mLock);
- if (loopStart != NULL) {
- *loopStart = mCblk->loopStart;
- }
- if (loopEnd != NULL) {
- *loopEnd = mCblk->loopEnd;
- }
- if (loopCount != NULL) {
- if (mCblk->loopCount < 0) {
- *loopCount = -1;
- } else {
- *loopCount = mCblk->loopCount;
- }
- }
-
- return NO_ERROR;
-}
-
status_t AudioTrack::setMarkerPosition(uint32_t marker)
{
if (mCbf == NULL) return INVALID_OPERATION;
@@ -653,6 +659,8 @@
status_t AudioTrack::setPosition(uint32_t position)
{
+ if (mIsTimed) return INVALID_OPERATION;
+
AutoMutex lock(mLock);
if (!stopped_l()) return INVALID_OPERATION;
@@ -784,7 +792,7 @@
}
}
} else {
- // Ensure that buffer alignment matches channelcount
+ // Ensure that buffer alignment matches channelCount
int channelCount = popcount(channelMask);
if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
ALOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
@@ -803,6 +811,7 @@
((uint16_t)flags) << 16,
sharedBuffer,
output,
+ mIsTimed,
&mSessionId,
&status);
@@ -895,7 +904,7 @@
"user=%08x, server=%08x", this, cblk->user, cblk->server);
//unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
- result = mAudioTrack->start();
+ result = mAudioTrack->start(0); // callback thread hasn't changed
cblk->lock.lock();
if (result == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -927,7 +936,7 @@
if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
ALOGW("obtainBuffer() track %p disabled, restarting", this);
- mAudioTrack->start();
+ mAudioTrack->start(0); // callback thread hasn't changed
}
cblk->waitTimeMs = 0;
@@ -969,9 +978,11 @@
{
if (mSharedBuffer != 0) return INVALID_OPERATION;
+ if (mIsTimed) return INVALID_OPERATION;
if (ssize_t(userSize) < 0) {
- // sanity-check. user is most-likely passing an error code.
+ // Sanity-check: user is most-likely passing an error code, and it would
+ // make the return value ambiguous (actualSize vs error).
ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
buffer, userSize, userSize);
return BAD_VALUE;
@@ -994,8 +1005,6 @@
do {
audioBuffer.frameCount = userSize/frameSz;
- // Calling obtainBuffer() with a negative wait count causes
- // an (almost) infinite wait time.
status_t err = obtainBuffer(&audioBuffer, -1);
if (err < 0) {
// out of buffers, return #bytes written
@@ -1026,6 +1035,59 @@
// -------------------------------------------------------------------------
+TimedAudioTrack::TimedAudioTrack() {
+ mIsTimed = true;
+}
+
+status_t TimedAudioTrack::allocateTimedBuffer(size_t size, sp<IMemory>* buffer)
+{
+ status_t result = UNKNOWN_ERROR;
+
+ // If the track is not invalid already, try to allocate a buffer. alloc
+ // fails indicating that the server is dead, flag the track as invalid so
+ // we can attempt to restore in in just a bit.
+ if (!(mCblk->flags & CBLK_INVALID_MSK)) {
+ result = mAudioTrack->allocateTimedBuffer(size, buffer);
+ if (result == DEAD_OBJECT) {
+ android_atomic_or(CBLK_INVALID_ON, &mCblk->flags);
+ }
+ }
+
+ // If the track is invalid at this point, attempt to restore it. and try the
+ // allocation one more time.
+ if (mCblk->flags & CBLK_INVALID_MSK) {
+ mCblk->lock.lock();
+ result = restoreTrack_l(mCblk, false);
+ mCblk->lock.unlock();
+
+ if (result == OK)
+ result = mAudioTrack->allocateTimedBuffer(size, buffer);
+ }
+
+ return result;
+}
+
+status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer,
+ int64_t pts)
+{
+ // restart track if it was disabled by audioflinger due to previous underrun
+ if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
+ android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
+ ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
+ mAudioTrack->start(0);
+ }
+
+ return mAudioTrack->queueTimedBuffer(buffer, pts);
+}
+
+status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
+ TargetTimeline target)
+{
+ return mAudioTrack->setMediaTimeTransform(xform, target);
+}
+
+// -------------------------------------------------------------------------
+
bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
{
Buffer audioBuffer;
@@ -1085,6 +1147,9 @@
frames = mRemainingFrames;
}
+ // See description of waitCount parameter at declaration of obtainBuffer().
+ // The logic below prevents us from being stuck below at obtainBuffer()
+ // not being able to handle timed events (position, markers, loops).
int32_t waitCount = -1;
if (mUpdatePeriod || (!mMarkerReached && mMarkerPosition) || mLoopCount) {
waitCount = 1;
@@ -1094,9 +1159,6 @@
audioBuffer.frameCount = frames;
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
- // stuck here not being able to handle timed events (position, markers, loops).
status_t err = obtainBuffer(&audioBuffer, waitCount);
if (err < NO_ERROR) {
if (err != TIMED_OUT) {
@@ -1218,7 +1280,7 @@
}
}
if (mActive) {
- result = mAudioTrack->start();
+ result = mAudioTrack->start(0); // callback thread hasn't changed
ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
}
if (fromStart && result == NO_ERROR) {
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index c3252e7..ebadbfa 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -90,6 +90,7 @@
uint32_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ bool isTimed,
int *sessionId,
status_t *status)
{
@@ -105,6 +106,7 @@
data.writeInt32(flags);
data.writeStrongBinder(sharedBuffer->asBinder());
data.writeInt32((int32_t) output);
+ data.writeInt32(isTimed);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
@@ -559,7 +561,7 @@
if (status != NO_ERROR) {
return status;
}
- if (numEffects) {
+ if (numEffects != NULL) {
*numEffects = (uint32_t)reply.readInt32();
}
return NO_ERROR;
@@ -689,11 +691,12 @@
uint32_t flags = data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
+ bool isTimed = data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
(audio_stream_type_t) streamType, sampleRate, format,
- channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
+ channelCount, bufferCount, flags, buffer, output, isTimed, &sessionId, &status);
reply->writeInt32(sessionId);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 8c7a960..6b473c9 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -42,10 +42,11 @@
{
}
- virtual status_t start()
+ virtual status_t start(pid_t tid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ data.writeInt32(tid);
status_t status = remote()->transact(START, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
@@ -90,7 +91,7 @@
} break;
case START: {
CHECK_INTERFACE(IAudioRecord, data, reply);
- reply->writeInt32(start());
+ reply->writeInt32(start(data.readInt32()));
return NO_ERROR;
} break;
case STOP: {
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index e618619..28ebbbfc 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -1,4 +1,4 @@
-/* //device/extlibs/pv/android/IAudioTrack.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -35,7 +35,10 @@
FLUSH,
MUTE,
PAUSE,
- ATTACH_AUX_EFFECT
+ ATTACH_AUX_EFFECT,
+ ALLOCATE_TIMED_BUFFER,
+ QUEUE_TIMED_BUFFER,
+ SET_MEDIA_TIME_TRANSFORM,
};
class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -58,10 +61,11 @@
return cblk;
}
- virtual status_t start()
+ virtual status_t start(pid_t tid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeInt32(tid);
status_t status = remote()->transact(START, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
@@ -113,6 +117,52 @@
}
return status;
}
+
+ virtual status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeInt32(size);
+ status_t status = remote()->transact(ALLOCATE_TIMED_BUFFER,
+ data, &reply);
+ if (status == NO_ERROR) {
+ status = reply.readInt32();
+ if (status == NO_ERROR) {
+ *buffer = interface_cast<IMemory>(reply.readStrongBinder());
+ }
+ }
+ return status;
+ }
+
+ virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
+ int64_t pts) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeStrongBinder(buffer->asBinder());
+ data.writeInt64(pts);
+ status_t status = remote()->transact(QUEUE_TIMED_BUFFER,
+ data, &reply);
+ if (status == NO_ERROR) {
+ status = reply.readInt32();
+ }
+ return status;
+ }
+
+ virtual status_t setMediaTimeTransform(const LinearTransform& xform,
+ int target) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeInt64(xform.a_zero);
+ data.writeInt64(xform.b_zero);
+ data.writeInt32(xform.a_to_b_numer);
+ data.writeInt32(xform.a_to_b_denom);
+ data.writeInt32(target);
+ status_t status = remote()->transact(SET_MEDIA_TIME_TRANSFORM,
+ data, &reply);
+ if (status == NO_ERROR) {
+ status = reply.readInt32();
+ }
+ return status;
+ }
};
IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -130,7 +180,7 @@
} break;
case START: {
CHECK_INTERFACE(IAudioTrack, data, reply);
- reply->writeInt32(start());
+ reply->writeInt32(start(data.readInt32()));
return NO_ERROR;
} break;
case STOP: {
@@ -158,10 +208,38 @@
reply->writeInt32(attachAuxEffect(data.readInt32()));
return NO_ERROR;
} break;
+ case ALLOCATE_TIMED_BUFFER: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ sp<IMemory> buffer;
+ status_t status = allocateTimedBuffer(data.readInt32(), &buffer);
+ reply->writeInt32(status);
+ if (status == NO_ERROR) {
+ reply->writeStrongBinder(buffer->asBinder());
+ }
+ return NO_ERROR;
+ } break;
+ case QUEUE_TIMED_BUFFER: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ sp<IMemory> buffer = interface_cast<IMemory>(
+ data.readStrongBinder());
+ uint64_t pts = data.readInt64();
+ reply->writeInt32(queueTimedBuffer(buffer, pts));
+ return NO_ERROR;
+ } break;
+ case SET_MEDIA_TIME_TRANSFORM: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ LinearTransform xform;
+ xform.a_zero = data.readInt64();
+ xform.b_zero = data.readInt64();
+ xform.a_to_b_numer = data.readInt32();
+ xform.a_to_b_denom = data.readInt32();
+ int target = data.readInt32();
+ reply->writeInt32(setMediaTimeTransform(xform, target));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}; // namespace android
-
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index d469e28..5d40cc8 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -83,8 +83,15 @@
size = *pReplySize;
}
data.writeInt32(size);
- remote()->transact(COMMAND, data, &reply);
- status_t status = reply.readInt32();
+
+ status_t status = remote()->transact(COMMAND, data, &reply);
+ if (status != NO_ERROR) {
+ if (pReplySize != NULL)
+ *pReplySize = 0;
+ return status;
+ }
+
+ status = reply.readInt32();
size = reply.readInt32();
if (size != 0 && pReplyData != NULL && pReplySize != NULL) {
reply.read(pReplyData, size);
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 8456db5..6cb5b82 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -246,14 +246,12 @@
}//while (1)
threadExit:
- if (mAudioTrack) {
+ if (mAudioTrack != NULL) {
mAudioTrack->stop();
mAudioTrack->flush();
}
- if (mAudioBuffer) {
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- }
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
mMutex.lock();
mTid = -1;
mCondition.signal();
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c905762..93ddca8 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -25,7 +25,7 @@
#include <cutils/properties.h>
#include <expat.h>
#include <media/MediaProfiles.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/openmax/OMX_Video.h>
namespace android {
@@ -349,7 +349,7 @@
{
CHECK(!strcmp("quality", atts[0]));
int quality = atoi(atts[1]);
- ALOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality);
+ ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
if (levels == NULL) {
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 79cab74..73d4519 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -143,7 +143,7 @@
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
if (access(path, F_OK) == 0) {
- ALOGV("found .nomedia, setting noMedia flag\n");
+ ALOGV("found .nomedia, setting noMedia flag");
noMedia = true;
}
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 9fe1820..cdfd477 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -142,12 +142,12 @@
UConverter *conv = ucnv_open(enc, &status);
if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for %s\n", enc);
+ ALOGE("could not create UConverter for %s", enc);
return;
}
UConverter *utf8Conv = ucnv_open("UTF-8", &status);
if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for UTF-8\n");
+ ALOGE("could not create UConverter for UTF-8");
ucnv_close(conv);
return;
}
@@ -181,7 +181,7 @@
ucnv_convertEx(utf8Conv, conv, &target, target + targetLength,
&source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
if (U_FAILURE(status)) {
- ALOGE("ucnv_convertEx failed: %d\n", status);
+ ALOGE("ucnv_convertEx failed: %d", status);
mValues->setEntry(i, "???");
} else {
// zero terminate
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index e6e989d..54eb98a 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -791,7 +791,7 @@
// generators, instantiates output audio track.
//
// Input:
-// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type)
+// streamType: Type of stream used for tone playback
// volume: volume applied to tone (0.0 to 1.0)
//
// Output:
@@ -800,7 +800,7 @@
////////////////////////////////////////////////////////////////////////////////
ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava) {
- ALOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
+ ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume);
mState = TONE_IDLE;
@@ -829,9 +829,9 @@
}
if (initAudioTrack()) {
- ALOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("ToneGenerator INIT OK, time: %d", (unsigned int)(systemTime()/1000000));
} else {
- ALOGV("!!!ToneGenerator INIT FAILED!!!\n");
+ ALOGV("!!!ToneGenerator INIT FAILED!!!");
}
}
@@ -853,11 +853,11 @@
//
////////////////////////////////////////////////////////////////////////////////
ToneGenerator::~ToneGenerator() {
- ALOGV("ToneGenerator destructor\n");
+ ALOGV("ToneGenerator destructor");
if (mpAudioTrack != NULL) {
stopTone();
- ALOGV("Delete Track: %p\n", mpAudioTrack);
+ ALOGV("Delete Track: %p", mpAudioTrack);
delete mpAudioTrack;
}
}
@@ -892,7 +892,7 @@
}
}
- ALOGV("startTone\n");
+ ALOGV("startTone");
mLock.lock();
@@ -915,7 +915,7 @@
if (mState == TONE_INIT) {
if (prepareWave()) {
- ALOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
lResult = true;
mState = TONE_STARTING;
mLock.unlock();
@@ -934,7 +934,7 @@
mState = TONE_IDLE;
}
} else {
- ALOGV("Delayed start\n");
+ ALOGV("Delayed start");
mState = TONE_RESTARTING;
lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
if (lStatus == NO_ERROR) {
@@ -949,8 +949,8 @@
}
mLock.unlock();
- ALOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
- ALOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV_IF(lResult, "Tone started, time %d", (unsigned int)(systemTime()/1000000));
+ ALOGW_IF(!lResult, "Tone start failed!!!, time %d", (unsigned int)(systemTime()/1000000));
return lResult;
}
@@ -1017,7 +1017,7 @@
// Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
mpAudioTrack = new AudioTrack();
- ALOGV("Create Track: %p\n", mpAudioTrack);
+ ALOGV("Create Track: %p", mpAudioTrack);
mpAudioTrack->set(mStreamType,
0,
@@ -1045,8 +1045,8 @@
initAudioTrack_exit:
// Cleanup
- if (mpAudioTrack) {
- ALOGV("Delete Track I: %p\n", mpAudioTrack);
+ if (mpAudioTrack != NULL) {
+ ALOGV("Delete Track I: %p", mpAudioTrack);
delete mpAudioTrack;
mpAudioTrack = NULL;
}
@@ -1141,7 +1141,7 @@
if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
// Time to go to next sequence segment
- ALOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
lGenSmp = lReqSmp;
@@ -1156,13 +1156,13 @@
lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
}
- ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
}
// check if we need to loop and loop for the reqd times
if (lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
if (lpToneGen->mLoopCounter < lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
- ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+ ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
lpToneGen->mLoopCounter,
lpToneGen->mCurSegment);
@@ -1172,14 +1172,14 @@
// completed loop. go to next segment
lpToneGen->mLoopCounter = 0;
lpToneGen->mCurSegment++;
- ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+ ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
lpToneGen->mLoopCounter,
lpToneGen->mCurSegment);
}
} else {
lpToneGen->mCurSegment++;
- ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+ ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d)",
lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
lpToneGen->mLoopCounter,
lpToneGen->mCurSegment);
@@ -1188,32 +1188,32 @@
// Handle loop if last segment reached
if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
- ALOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+ ALOGV("Last Seg: %d", lpToneGen->mCurSegment);
// Pre increment loop count and restart if total count not reached. Stop sequence otherwise
if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
- ALOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+ ALOGV("Repeating Count: %d", lpToneGen->mCurCount);
lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
lWaveCmd = WaveGenerator::WAVEGEN_START;
}
- ALOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
} else {
lGenSmp = 0;
- ALOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+ ALOGV("End repeat, time: %d", (unsigned int)(systemTime()/1000000));
}
} else {
- ALOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
// If next segment is not silent, OFF -> ON transition : reset wave generator
lWaveCmd = WaveGenerator::WAVEGEN_START;
- ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
} else {
lGenSmp = 0;
}
@@ -1251,13 +1251,13 @@
switch (lpToneGen->mState) {
case TONE_RESTARTING:
- ALOGV("Cbk restarting track\n");
+ ALOGV("Cbk restarting track");
if (lpToneGen->prepareWave()) {
lpToneGen->mState = TONE_STARTING;
// must reload lpToneDesc as prepareWave() may change mpToneDesc
lpToneDesc = lpToneGen->mpToneDesc;
} else {
- ALOGW("Cbk restarting prepareWave() failed\n");
+ ALOGW("Cbk restarting prepareWave() failed");
lpToneGen->mState = TONE_IDLE;
lpToneGen->mpAudioTrack->stop();
// Force loop exit
@@ -1266,14 +1266,14 @@
lSignal = true;
break;
case TONE_STOPPING:
- ALOGV("Cbk Stopping\n");
+ ALOGV("Cbk Stopping");
lpToneGen->mState = TONE_STOPPED;
// Force loop exit
lNumSmp = 0;
break;
case TONE_STOPPED:
lpToneGen->mState = TONE_INIT;
- ALOGV("Cbk Stopped track\n");
+ ALOGV("Cbk Stopped track");
lpToneGen->mpAudioTrack->stop();
// Force loop exit
lNumSmp = 0;
@@ -1281,7 +1281,7 @@
lSignal = true;
break;
case TONE_STARTING:
- ALOGV("Cbk starting track\n");
+ ALOGV("Cbk starting track");
lpToneGen->mState = TONE_PLAYING;
lSignal = true;
break;
@@ -1491,7 +1491,7 @@
d0 = 32767;
mA1_Q14 = (short) d0;
- ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
+ ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d",
mA1_Q14, mS2_0, mAmplitude_Q15);
}
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 13b64e9..70f8c0c 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -168,7 +168,7 @@
uint32_t replySize = mCaptureSize;
status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
ALOGV("getWaveForm() command returned %d", status);
- if (replySize == 0) {
+ if ((status == NO_ERROR) && (replySize == 0)) {
status = NOT_ENOUGH_DATA;
}
} else {
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index f1c47dd..250425b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -1,4 +1,4 @@
-/* mediaplayer.cpp
+/*
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index a3e2517..e521648 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -29,7 +29,8 @@
libstagefright_omx \
libstagefright_foundation \
libgui \
- libdl
+ libdl \
+ libaah_rtp
LOCAL_STATIC_LIBRARIES := \
libstagefright_nuplayer \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a0c20ae..764eddc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -70,6 +70,11 @@
#include <OMX.h>
+namespace android {
+sp<MediaPlayerBase> createAAH_TXPlayer();
+sp<MediaPlayerBase> createAAH_RXPlayer();
+}
+
namespace {
using android::media::Metadata;
using android::status_t;
@@ -593,6 +598,14 @@
return NU_PLAYER;
}
+ if (!strncasecmp("aahRX://", url, 8)) {
+ return AAH_RX_PLAYER;
+ }
+
+ if (!strncasecmp("aahTX://", url, 8)) {
+ return AAH_TX_PLAYER;
+ }
+
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
@@ -629,6 +642,14 @@
ALOGV("Create Test Player stub");
p = new TestPlayerStub();
break;
+ case AAH_RX_PLAYER:
+ ALOGV(" create A@H RX Player");
+ p = createAAH_RXPlayer();
+ break;
+ case AAH_TX_PLAYER:
+ ALOGV(" create A@H TX Player");
+ p = createAAH_TXPlayer();
+ break;
default:
ALOGE("Unknown player type: %d", playerType);
return NULL;
@@ -1031,9 +1052,21 @@
status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
{
ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
- // TODO: for hardware output, call player instead
- Mutex::Autolock l(mLock);
- if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
+
+ // for hardware output, call player instead
+ sp<MediaPlayerBase> p = getPlayer();
+ {
+ Mutex::Autolock l(mLock);
+ if (p != 0 && p->hardwareOutput()) {
+ MediaPlayerHWInterface* hwp =
+ reinterpret_cast<MediaPlayerHWInterface*>(p.get());
+ return hwp->setVolume(leftVolume, rightVolume);
+ } else {
+ if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
+ return NO_ERROR;
+ }
+ }
+
return NO_ERROR;
}
@@ -1265,6 +1298,8 @@
mStreamType = AUDIO_STREAM_MUSIC;
mLeftVolume = 1.0;
mRightVolume = 1.0;
+ mPlaybackRatePermille = 1000;
+ mSampleRateHz = 0;
mLatency = 0;
mMsecsPerFrame = 0;
mAuxEffectId = 0;
@@ -1402,10 +1437,15 @@
ALOGV("setVolume");
t->setVolume(mLeftVolume, mRightVolume);
- mMsecsPerFrame = 1.e3 / (float) sampleRate;
+ mSampleRateHz = sampleRate;
+ mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
mLatency = t->latency();
mTrack = t;
+ status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
+ if (res != NO_ERROR) {
+ return res;
+ }
t->setAuxEffectSendLevel(mSendLevel);
return t->attachAuxEffect(mAuxEffectId);;
}
@@ -1469,6 +1509,22 @@
}
}
+status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille)
+{
+ ALOGV("setPlaybackRatePermille(%d)", ratePermille);
+ status_t res = NO_ERROR;
+ if (mTrack) {
+ res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000);
+ } else {
+ res = NO_INIT;
+ }
+ mPlaybackRatePermille = ratePermille;
+ if (mSampleRateHz != 0) {
+ mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz;
+ }
+ return res;
+}
+
status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
{
ALOGV("setAuxEffectSendLevel(%f)", level);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index fa71d11..52af64d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -95,6 +95,7 @@
virtual void close();
void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; }
void setVolume(float left, float right);
+ virtual status_t setPlaybackRatePermille(int32_t ratePermille);
status_t setAuxEffectSendLevel(float level);
status_t attachAuxEffect(int effectId);
virtual status_t dump(int fd, const Vector<String16>& args) const;
@@ -112,6 +113,8 @@
audio_stream_type_t mStreamType;
float mLeftVolume;
float mRightVolume;
+ int32_t mPlaybackRatePermille;
+ uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
uint32_t mLatency;
int mSessionId;
@@ -152,6 +155,7 @@
virtual void close() {}
void setAudioStreamType(audio_stream_type_t streamType) {}
void setVolume(float left, float right) {}
+ virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
uint32_t sampleRate() const { return mSampleRate; }
audio_format_t format() const { return mFormat; }
size_t size() const { return mSize; }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 6d7771a..052ebf0 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -176,7 +176,7 @@
}
status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
- ALOGV("setParameter");
+ ALOGV("setParameter(key=%d)", key);
return mPlayer->setParameter(key, request);
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 4632016..fe519b0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,6 +24,7 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AACWriter.h>
@@ -31,7 +32,6 @@
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -241,8 +241,8 @@
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
ALOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
// These don't make any sense, do they?
- CHECK_EQ(offset, 0);
- CHECK_EQ(length, 0);
+ CHECK_EQ(offset, 0ll);
+ CHECK_EQ(length, 0ll);
if (fd < 0) {
ALOGE("Invalid file descriptor: %d", fd);
@@ -734,7 +734,7 @@
}
status_t StagefrightRecorder::start() {
- CHECK(mOutputFd >= 0);
+ CHECK_GE(mOutputFd, 0);
if (mWriter != NULL) {
ALOGE("File writer is not avaialble");
@@ -837,7 +837,7 @@
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
sp<MediaSource> audioEncoder =
OMXCodec::Create(client.interface(), encMeta,
@@ -850,9 +850,9 @@
status_t StagefrightRecorder::startAACRecording() {
// FIXME:
// Add support for OUTPUT_FORMAT_AAC_ADIF
- CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+ CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
- CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
+ CHECK_EQ(mAudioEncoder, AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_CNT);
mWriter = new AACWriter(mOutputFd);
@@ -1386,7 +1386,7 @@
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
uint32_t encoder_flags = 0;
if (mIsMetaDataStoredInVideoBuffers) {
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 33f22f2..4d1072f 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -23,9 +23,9 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 5a28347..03dcbf9 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -20,9 +20,9 @@
#include "include/AMRExtractor.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 59b4ca7..ca85640 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 9a9c3ef..df27566 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -268,6 +268,16 @@
return mReachedEOS;
}
+status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->setPlaybackRatePermille(ratePermille);
+ } else if (mAudioTrack != NULL){
+ return mAudioTrack->setSampleRate(ratePermille * mSampleRate / 1000);
+ } else {
+ return NO_INIT;
+ }
+}
+
// static
size_t AudioPlayer::AudioSinkCallback(
MediaPlayerBase::AudioSink *audioSink,
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8073af8..70945e3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1360,7 +1360,7 @@
mAudioTrack = source;
}
-void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+void AwesomePlayer::addTextSource(const sp<MediaSource>& source) {
Mutex::Autolock autoLock(mTimedTextLock);
CHECK(source != NULL);
@@ -1609,7 +1609,7 @@
mSeekTimeUs,
mSeeking == SEEK_VIDEO_ONLY
? MediaSource::ReadOptions::SEEK_NEXT_SYNC
- : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ : MediaSource::ReadOptions::SEEK_CLOSEST);
}
for (;;) {
status_t err = mVideoSource->read(&mVideoBuffer, &options);
@@ -2251,6 +2251,14 @@
{
return setCacheStatCollectFreq(request);
}
+ case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
+ {
+ if (mAudioPlayer != NULL) {
+ return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
+ } else {
+ return NO_INIT;
+ }
+ }
default:
{
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 228659c..ed1d5f4 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -20,8 +20,8 @@
#include <OMX_Component.h>
#include <binder/IPCThreadState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -114,7 +114,7 @@
ALOGE("Uknown color format (%s), please add it to "
"CameraSource::getColorFormat", colorFormat);
- CHECK_EQ(0, "Unknown color format");
+ CHECK(!"Unknown color format");
}
CameraSource *CameraSource::Create() {
@@ -517,7 +517,7 @@
// This CHECK is good, since we just passed the lock/unlock
// check earlier by calling mCamera->setParameters().
- CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
+ CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
// By default, do not store metadata in video buffers
mIsMetaDataStoredInVideoBuffers = false;
@@ -566,7 +566,8 @@
if (mCameraFlags & FLAGS_HOT_CAMERA) {
mCamera->unlock();
mCamera.clear();
- CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+ CHECK_EQ((status_t)OK,
+ mCameraRecordingProxy->startRecording(new ProxyListener(this)));
} else {
mCamera->setListener(new CameraSourceListener(this));
mCamera->startRecording();
@@ -718,7 +719,7 @@
return;
}
}
- CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ CHECK(!"signalBufferReturned: bogus buffer");
}
status_t CameraSource::read(
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 83d67b9..26ce7ae 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -20,9 +20,9 @@
#include <binder/IPCThreadState.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index afc4a80..524c3aa 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaSource.h>
@@ -30,7 +31,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <drm/drm_framework_common.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 01f53e4..73c8d03 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index e818115..bafa4b2 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "JPEGSource"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -59,7 +59,7 @@
mWidth(0),
mHeight(0),
mOffset(0) {
- CHECK_EQ(parseJPEG(), OK);
+ CHECK_EQ(parseJPEG(), (status_t)OK);
CHECK(mSource->getSize(&mSize) == OK);
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index c7a8b32..7ebbe1d 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -23,10 +23,10 @@
#include <pthread.h>
#include <sys/prctl.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -141,7 +141,7 @@
: sampleCount(count), sampleDuration(timescaledDur) {}
uint32_t sampleCount;
- int32_t sampleDuration; // time scale based
+ uint32_t sampleDuration; // time scale based
};
size_t mNumCttsTableEntries;
List<CttsTableEntry> mCttsTableEntries;
@@ -478,7 +478,7 @@
!param->findInt32(kKeyTimeScale, &mTimeScale)) {
mTimeScale = 1000;
}
- CHECK(mTimeScale > 0);
+ CHECK_GT(mTimeScale, 0);
ALOGV("movie time scale: %d", mTimeScale);
mStreamableFile = true;
@@ -497,7 +497,7 @@
}
mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
}
- CHECK(mEstimatedMoovBoxSize >= 8);
+ CHECK_GE(mEstimatedMoovBoxSize, 8);
lseek64(mFd, mFreeBoxOffset, SEEK_SET);
writeInt32(mEstimatedMoovBoxSize);
write("free", 4);
@@ -691,7 +691,7 @@
mWriteMoovBoxToMemory = false;
if (mStreamableFile) {
- CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
+ CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
// Moov box
lseek64(mFd, mFreeBoxOffset, SEEK_SET);
@@ -863,7 +863,7 @@
mOffset += length + 4;
} else {
- CHECK(length < 65536);
+ CHECK_LT(length, 65536);
uint8_t x = length >> 8;
::write(mFd, &x, 1);
@@ -1092,7 +1092,7 @@
void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
ALOGI("setStartTimestampUs: %lld", timeUs);
- CHECK(timeUs >= 0);
+ CHECK_GE(timeUs, 0ll);
Mutex::Autolock autoLock(mLock);
if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
mStartTimestampUs = timeUs;
@@ -1222,7 +1222,7 @@
mTimeScale = timeScale;
}
- CHECK(mTimeScale > 0);
+ CHECK_GT(mTimeScale, 0);
}
void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
@@ -1303,7 +1303,7 @@
}
}
- CHECK("Received a chunk for a unknown track" == 0);
+ CHECK(!"Received a chunk for a unknown track");
}
void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
@@ -1846,7 +1846,7 @@
int64_t cttsOffsetTimeUs = 0;
int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks
int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks
- int32_t cttsSampleCount = 1; // Sample count in the current ctts table entry
+ int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry
if (mIsAudio) {
prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
@@ -1889,7 +1889,7 @@
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
buffer->range_length());
- CHECK_EQ(OK, err);
+ CHECK_EQ((status_t)OK, err);
} else if (mIsMPEG4) {
mCodecSpecificDataSize = buffer->range_length();
mCodecSpecificData = malloc(mCodecSpecificDataSize);
@@ -1955,15 +1955,15 @@
if (mResumed) {
int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
- CHECK(durExcludingEarlierPausesUs >= 0);
+ CHECK_GE(durExcludingEarlierPausesUs, 0ll);
int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
- CHECK(pausedDurationUs >= lastDurationUs);
+ CHECK_GE(pausedDurationUs, lastDurationUs);
previousPausedDurationUs += pausedDurationUs - lastDurationUs;
mResumed = false;
}
timestampUs -= previousPausedDurationUs;
- CHECK(timestampUs >= 0);
+ CHECK_GE(timestampUs, 0ll);
if (!mIsAudio) {
/*
* Composition time: timestampUs
@@ -1975,7 +1975,7 @@
decodingTimeUs -= previousPausedDurationUs;
cttsOffsetTimeUs =
timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
- CHECK(cttsOffsetTimeUs >= 0);
+ CHECK_GE(cttsOffsetTimeUs, 0ll);
timestampUs = decodingTimeUs;
ALOGV("decoding time: %lld and ctts offset time: %lld",
timestampUs, cttsOffsetTimeUs);
@@ -1983,16 +1983,23 @@
// Update ctts box table if necessary
currCttsOffsetTimeTicks =
(cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
- CHECK(currCttsOffsetTimeTicks <= 0x7FFFFFFFLL);
-#if 0
- // FIXME:
- // Optimize to reduce the number of ctts table entries.
- // Also, make sure that the very first ctts table entry contains
- // only a single sample.
-#else
- addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
-#endif
- lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+ CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
+ if (mNumSamples == 0) {
+ // Force the first ctts table entry to have one single entry
+ // so that we can do adjustment for the initial track start
+ // time offset easily in writeCttsBox().
+ lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+ addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
+ cttsSampleCount = 0; // No sample in ctts box is pending
+ } else {
+ if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+ cttsSampleCount = 1; // One sample in ctts box is pending
+ } else {
+ ++cttsSampleCount;
+ }
+ }
// Update ctts time offset range
if (mNumSamples == 0) {
@@ -2014,7 +2021,7 @@
}
}
- CHECK(timestampUs >= 0);
+ CHECK_GE(timestampUs, 0ll);
ALOGV("%s media time stamp: %lld and previous paused duration %lld",
mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
if (timestampUs > mTrackDurationUs) {
@@ -2029,7 +2036,7 @@
currDurationTicks =
((timestampUs * mTimeScale + 500000LL) / 1000000LL -
(lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
- CHECK(currDurationTicks >= 0);
+ CHECK_GE(currDurationTicks, 0ll);
mSampleSizes.push_back(sampleSize);
++mNumSamples;
@@ -2127,7 +2134,6 @@
lastDurationTicks = 0;
} else {
++sampleCount; // Count for the last sample
- ++cttsSampleCount;
}
if (mNumSamples <= 2) {
@@ -2139,6 +2145,14 @@
addOneSttsTableEntry(sampleCount, lastDurationTicks);
}
+ // The last ctts box may not have been written yet, and this
+ // is to make sure that we write out the last ctts box.
+ if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+ if (cttsSampleCount > 0) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ }
+ }
+
mTrackDurationUs += lastDurationUs;
mReachedEOS = true;
@@ -2404,7 +2418,7 @@
mOwner->writeInt16(0x18); // depth
mOwner->writeInt16(-1); // predefined
- CHECK(23 + mCodecSpecificDataSize < 128);
+ CHECK_LT(23 + mCodecSpecificDataSize, 128);
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
writeMp4vEsdsBox();
@@ -2463,10 +2477,10 @@
void MPEG4Writer::Track::writeMp4aEsdsBox() {
mOwner->beginBox("esds");
CHECK(mCodecSpecificData);
- CHECK(mCodecSpecificDataSize > 0);
+ CHECK_GT(mCodecSpecificDataSize, 0);
// Make sure all sizes encode to a single byte.
- CHECK(mCodecSpecificDataSize + 23 < 128);
+ CHECK_LT(mCodecSpecificDataSize + 23, 128);
mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt8(0x03); // ES_DescrTag
@@ -2500,7 +2514,7 @@
void MPEG4Writer::Track::writeMp4vEsdsBox() {
CHECK(mCodecSpecificData);
- CHECK(mCodecSpecificDataSize > 0);
+ CHECK_GT(mCodecSpecificDataSize, 0);
mOwner->beginBox("esds");
mOwner->writeInt32(0); // version=0, flags=0
@@ -2660,7 +2674,7 @@
void MPEG4Writer::Track::writeAvccBox() {
CHECK(mCodecSpecificData);
- CHECK(mCodecSpecificDataSize >= 5);
+ CHECK_GE(mCodecSpecificDataSize, 5);
// Patch avcc's lengthSize field to match the number
// of bytes we use to indicate the size of a nal unit.
@@ -2692,7 +2706,7 @@
int64_t trackStartTimeOffsetUs = 0;
int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
if (mStartTimestampUs != moovStartTimeUs) {
- CHECK(mStartTimestampUs > moovStartTimeUs);
+ CHECK_GT(mStartTimestampUs, moovStartTimeUs);
trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
}
return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
@@ -2715,7 +2729,7 @@
mOwner->writeInt32(it->sampleDuration);
totalCount += it->sampleCount;
}
- CHECK(totalCount == mNumSamples);
+ CHECK_EQ(totalCount, mNumSamples);
mOwner->endBox(); // stts
}
@@ -2758,7 +2772,7 @@
mOwner->writeInt32(it->sampleDuration - mMinCttsOffsetTimeUs);
totalCount += it->sampleCount;
}
- CHECK(totalCount == mNumSamples);
+ CHECK_EQ(totalCount, mNumSamples);
mOwner->endBox(); // ctts
}
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 96271e4..11b80bf 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -22,8 +22,8 @@
#include <stdlib.h>
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <ui/GraphicBuffer.h>
@@ -157,7 +157,7 @@
}
MediaBuffer::~MediaBuffer() {
- CHECK_EQ(mObserver, NULL);
+ CHECK(mObserver == NULL);
if (mOwnsData && mData != NULL) {
free(mData);
@@ -188,7 +188,7 @@
}
MediaBuffer *MediaBuffer::clone() {
- CHECK_EQ(mGraphicBuffer, NULL);
+ CHECK(mGraphicBuffer == NULL);
MediaBuffer *buffer = new MediaBuffer(mData, mSize);
buffer->set_range(mRangeOffset, mRangeLength);
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
index c8d05f4..80aae51 100644
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "MediaBufferGroup"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp
index 8af0694..3b64ded 100644
--- a/media/libstagefright/MediaSourceSplitter.cpp
+++ b/media/libstagefright/MediaSourceSplitter.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "MediaSourceSplitter"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSourceSplitter.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 884f3b4..66dec90 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -17,7 +17,7 @@
#include <stdlib.h>
#include <string.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MetaData.h>
namespace android {
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 73efc27..5e79e78 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -21,10 +21,10 @@
#include "include/OggExtractor.h"
#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 81ec5c1..eae721b 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -22,8 +22,8 @@
#include <arpa/inet.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include "include/SampleTable.h"
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 43bfd9e..35f9c1f 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,10 +20,10 @@
#include "include/StagefrightMetadataRetriever.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
@@ -37,7 +37,7 @@
ALOGV("StagefrightMetadataRetriever()");
DataSource::RegisterDefaultSniffers();
- CHECK_EQ(mClient.connect(), OK);
+ CHECK_EQ(mClient.connect(), (status_t)OK);
}
StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
@@ -169,7 +169,7 @@
|| (buffer != NULL && buffer->range_length() == 0));
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
ALOGV("decoding frame failed.");
decoder->stop();
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index d068381..aa047d6 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -16,14 +16,14 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SurfaceMediaSource"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/SurfaceMediaSource.h>
-#include <ui/GraphicBuffer.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/openmax/OMX_IVCommon.h>
#include <media/stagefright/MetadataBufferType.h>
+#include <ui/GraphicBuffer.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -855,7 +855,7 @@
}
if (!foundBuffer) {
- CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ CHECK(!"signalBufferReturned: bogus buffer");
}
}
diff --git a/media/libstagefright/ThrottledSource.cpp b/media/libstagefright/ThrottledSource.cpp
index 88e07b0..b1fcafd 100644
--- a/media/libstagefright/ThrottledSource.cpp
+++ b/media/libstagefright/ThrottledSource.cpp
@@ -16,7 +16,7 @@
#include "include/ThrottledSource.h"
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 12c9c36..f4b5d4f 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,7 +31,7 @@
#include <sys/prctl.h>
#include <sys/time.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#ifdef ANDROID_SIMULATOR
#include <jni.h>
diff --git a/media/libstagefright/VideoSourceDownSampler.cpp b/media/libstagefright/VideoSourceDownSampler.cpp
index 1b66990..90a42c9 100644
--- a/media/libstagefright/VideoSourceDownSampler.cpp
+++ b/media/libstagefright/VideoSourceDownSampler.cpp
@@ -17,9 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "VideoSourceDownSampler"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/VideoSourceDownSampler.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/YUVImage.h>
#include <media/stagefright/YUVCanvas.h>
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 0bcaf08..501f4806 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -20,9 +20,9 @@
#include "include/WAVExtractor.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -217,7 +217,7 @@
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
break;
default:
- CHECK_EQ(mWaveFormat, WAVE_FORMAT_MULAW);
+ CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
mTrackMeta->setCString(
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
break;
@@ -362,7 +362,7 @@
// Convert 8-bit unsigned samples to 16-bit signed.
MediaBuffer *tmp;
- CHECK_EQ(mGroup->acquire_buffer(&tmp), OK);
+ CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
// The new buffer holds the sample number of samples, but each
// one is 2 bytes wide.
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 1e4e049..c7ad513 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -21,6 +21,7 @@
#include <arpa/inet.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaSource.h>
@@ -28,7 +29,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <dlfcn.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 2b8633d..8b5007e 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -22,8 +22,8 @@
#include "voAAC.h"
#include "cmnMemory.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -114,8 +114,8 @@
ALOGV("setAudioSpecificConfigData: %d hz, %d bps, and %d channels",
mSampleRate, mBitRate, mChannels);
- int32_t index;
- CHECK_EQ(OK, getSampleRateTableIndex(mSampleRate, index));
+ int32_t index = 0;
+ CHECK_EQ((status_t)OK, getSampleRateTableIndex(mSampleRate, index));
if (mChannels > 2 || mChannels <= 0) {
ALOGE("Unsupported number of channels(%d)", mChannels);
return UNKNOWN_ERROR;
@@ -142,7 +142,7 @@
mBufferGroup = new MediaBufferGroup;
mBufferGroup->add_buffer(new MediaBuffer(2048));
- CHECK_EQ(OK, initCheck());
+ CHECK_EQ((status_t)OK, initCheck());
mNumInputSamples = 0;
mAnchorTimeUs = 0;
@@ -183,7 +183,7 @@
mSource->stop();
if (mEncoderHandle) {
- CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
}
delete mApiHandle;
@@ -223,7 +223,7 @@
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
bool readFromSource = false;
int64_t wallClockTimeUs = -1;
@@ -255,7 +255,7 @@
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
- CHECK_EQ(align, 0);
+ CHECK_EQ(align, (size_t)0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index 3afbc4f..27d7e4d 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -18,8 +18,8 @@
#include "gsmamr_enc.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -210,7 +210,7 @@
}
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index 60b1163..7fd3a95 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -22,8 +22,8 @@
#include "voAMRWB.h"
#include "cmnMemory.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -134,7 +134,7 @@
// The largest buffer size is header + 477 bits
mBufferGroup->add_buffer(new MediaBuffer(1024));
- CHECK_EQ(OK, initCheck());
+ CHECK_EQ((status_t)OK, initCheck());
mNumFramesOutput = 0;
@@ -163,7 +163,7 @@
mBufferGroup = NULL;
- CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
delete mApiHandle;
@@ -222,7 +222,7 @@
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
- CHECK_EQ(align, 0);
+ CHECK_EQ(align, (size_t)0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
@@ -271,7 +271,7 @@
CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
VO_CODECBUFFER outputData;
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e202a2b..7533f07 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -24,8 +24,8 @@
#include "avcenc_int.h"
#include "OMX_Video.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -417,7 +417,7 @@
*out = NULL;
MediaBuffer *outputBuffer;
- CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+ CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
uint32_t dataLength = outputBuffer->size();
@@ -557,9 +557,9 @@
encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
if (encoderStatus == AVCENC_SUCCESS) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
- CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
} else if (encoderStatus == AVCENC_PICTURE_READY) {
- CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
if (mIsIDRFrame) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
mIsIDRFrame = 0;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index d538603..20b0f8d 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -23,8 +23,8 @@
#include "mp4enc_api.h"
#include "OMX_Video.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -379,7 +379,7 @@
*out = NULL;
MediaBuffer *outputBuffer;
- CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+ CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
int32_t dataLength = outputBuffer->size();
@@ -467,7 +467,7 @@
mInputBuffer = NULL;
return UNKNOWN_ERROR;
}
- CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVGetOverrunBuffer(mHandle));
if (hintTrack.CodeType == 0) { // I-frame serves as sync frame
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index f3ef3de..597167f 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "ColorConverter"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 23c8e44..ff35d4a 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -16,7 +16,7 @@
testid3.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libutils libbinder
+ libstagefright libutils libbinder libstagefright_foundation
LOCAL_STATIC_LIBRARIES := \
libstagefright_id3
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 6dde9d8..2e92926 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,8 +20,8 @@
#include "../include/ID3.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
#include <byteswap.h>
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 0741045..bc4572c 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -23,7 +23,7 @@
#include <binder/ProcessState.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#define MAXPATHLEN 256
@@ -70,7 +70,7 @@
void scanFile(const char *path) {
sp<FileSource> file = new FileSource(path);
- CHECK_EQ(file->initCheck(), OK);
+ CHECK_EQ(file->initCheck(), (status_t)OK);
ID3 tag(file);
if (!tag.isValid()) {
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index a7a3d47..4c7bfa6 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -258,7 +258,7 @@
void setVideoSource(sp<MediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
- void addTextSource(sp<MediaSource> source);
+ void addTextSource(const sp<MediaSource>& source);
void onStreamDone();
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a1644d2..a0db719 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -93,7 +93,10 @@
void advance();
void reset();
- void seek(int64_t seekTimeUs, bool seekToKeyFrame);
+
+ void seek(
+ int64_t seekTimeUs, bool seekToKeyFrame,
+ int64_t *actualFrameTimeUs);
const mkvparser::Block *block() const;
int64_t blockTimeUs() const;
@@ -303,22 +306,52 @@
} while (!eos() && block()->GetTrackNumber() != mTrackNum);
}
-void BlockIterator::seek(int64_t seekTimeUs, bool seekToKeyFrame) {
+void BlockIterator::seek(
+ int64_t seekTimeUs, bool seekToKeyFrame,
+ int64_t *actualFrameTimeUs) {
Mutex::Autolock autoLock(mExtractor->mLock);
- mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+ *actualFrameTimeUs = -1ll;
+
+ int64_t seekTimeNs = seekTimeUs * 1000ll;
+
+ mCluster = mExtractor->mSegment->FindCluster(seekTimeNs);
mBlockEntry = NULL;
mBlockEntryIndex = 0;
- do {
- advance_l();
- }
- while (!eos() && block()->GetTrackNumber() != mTrackNum);
+ long prevKeyFrameBlockEntryIndex = -1;
- if (seekToKeyFrame) {
- while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
- advance_l();
+ for (;;) {
+ advance_l();
+
+ if (eos()) {
+ break;
}
+
+ if (block()->GetTrackNumber() != mTrackNum) {
+ continue;
+ }
+
+ if (block()->IsKey()) {
+ prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1;
+ }
+
+ int64_t timeNs = block()->GetTime(mCluster);
+
+ if (timeNs >= seekTimeNs) {
+ *actualFrameTimeUs = (timeNs + 500ll) / 1000ll;
+ break;
+ }
+ }
+
+ if (eos()) {
+ return;
+ }
+
+ if (seekToKeyFrame && !block()->IsKey()) {
+ CHECK_GE(prevKeyFrameBlockEntryIndex, 0);
+ mBlockEntryIndex = prevKeyFrameBlockEntryIndex;
+ advance_l();
}
}
@@ -397,6 +430,8 @@
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
+ int64_t targetSampleTimeUs = -1ll;
+
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)
@@ -406,10 +441,14 @@
// Apparently keyframe indication in audio tracks is unreliable,
// fortunately in all our currently supported audio encodings every
// frame is effectively a keyframe.
- mBlockIter.seek(seekTimeUs, !mIsAudio);
+ int64_t actualFrameTimeUs;
+ mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs);
+
+ if (mode == ReadOptions::SEEK_CLOSEST) {
+ targetSampleTimeUs = actualFrameTimeUs;
+ }
}
-again:
while (mPendingFrames.empty()) {
status_t err = readBlock();
@@ -424,6 +463,11 @@
mPendingFrames.erase(mPendingFrames.begin());
if (mType != AVC) {
+ if (targetSampleTimeUs >= 0ll) {
+ frame->meta_data()->setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
*out = frame;
return OK;
@@ -506,6 +550,11 @@
frame->release();
frame = NULL;
+ if (targetSampleTimeUs >= 0ll) {
+ buffer->meta_data()->setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
*out = buffer;
return OK;
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 03033f5..e1589b4 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -22,8 +22,8 @@
#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index ace883c..f11fcd2 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -25,7 +25,7 @@
#include "../include/OMXNodeInstance.h"
#include <binder/IMemory.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <utils/threads.h>
#include "OMXMaster.h"
@@ -102,7 +102,7 @@
if (status != WOULD_BLOCK) {
// Other than join to self, the only other error return codes are
// whatever readyToRun() returns, and we don't override that
- CHECK_EQ(status, NO_ERROR);
+ CHECK_EQ(status, (status_t)NO_ERROR);
}
}
diff --git a/media/libstagefright/omx/OMXComponentBase.cpp b/media/libstagefright/omx/OMXComponentBase.cpp
index 35227a0..7d11dce 100644
--- a/media/libstagefright/omx/OMXComponentBase.cpp
+++ b/media/libstagefright/omx/OMXComponentBase.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -33,7 +33,7 @@
OMXComponentBase::~OMXComponentBase() {}
void OMXComponentBase::setComponentHandle(OMX_COMPONENTTYPE *handle) {
- CHECK_EQ(mComponentHandle, NULL);
+ CHECK(mComponentHandle == NULL);
mComponentHandle = handle;
}
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index d698939..6b6d0ab 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -24,7 +24,7 @@
#include <dlfcn.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 8938e33..099c4f5 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -24,8 +24,8 @@
#include <OMX_Component.h>
#include <binder/IMemory.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/HardwareAPI.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -91,11 +91,11 @@
}
OMXNodeInstance::~OMXNodeInstance() {
- CHECK_EQ(mHandle, NULL);
+ CHECK(mHandle == NULL);
}
void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
- CHECK_EQ(mHandle, NULL);
+ CHECK(mHandle == NULL);
mNodeID = node_id;
mHandle = handle;
}
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 41c08be..0c0a70c 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -5,7 +5,7 @@
OMXHarness.cpp \
LOCAL_SHARED_LIBRARIES := \
- libstagefright libbinder libmedia libutils
+ libstagefright libbinder libmedia libutils libstagefright_foundation
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 8faf544..fab1771 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -26,9 +26,9 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
@@ -155,7 +155,7 @@
if (err == TIMED_OUT) {
return err;
}
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
}
}
@@ -317,7 +317,7 @@
EXPECT_SUCCESS(err, "allocatePortBuffers(input)");
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
Vector<Buffer> outputBuffers;
err = allocatePortBuffers(dealer, node, 1, &outputBuffers);
@@ -412,7 +412,7 @@
// Make sure node doesn't just transition to loaded before we are done
// freeing all input and output buffers.
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
for (size_t i = 0; i < inputBuffers.size(); ++i) {
err = mOMX->freeBuffer(node, 0, inputBuffers[i].mID);
@@ -420,7 +420,7 @@
}
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
for (size_t i = 0; i < outputBuffers.size(); ++i) {
err = mOMX->freeBuffer(node, 1, outputBuffers[i].mID);
@@ -584,7 +584,7 @@
return UNKNOWN_ERROR;
}
- CHECK_EQ(seekSource->start(), OK);
+ CHECK_EQ(seekSource->start(), (status_t)OK);
sp<MediaSource> codec = OMXCodec::Create(
mOMX, source->getFormat(), false /* createEncoder */,
@@ -592,7 +592,7 @@
CHECK(codec != NULL);
- CHECK_EQ(codec->start(), OK);
+ CHECK_EQ(codec->start(), (status_t)OK);
int64_t durationUs;
CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -638,7 +638,7 @@
requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
if (seekSource->read(&buffer, &options) != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
actualSeekTimeUs = -1;
} else {
CHECK(buffer != NULL);
@@ -659,7 +659,7 @@
err = codec->read(&buffer, &options);
options.clearSeekTo();
if (err == INFO_FORMAT_CHANGED) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
continue;
}
if (err == OK) {
@@ -670,7 +670,7 @@
continue;
}
} else {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
}
break;
@@ -679,7 +679,7 @@
if (requestedSeekTimeUs < 0) {
// Linear read.
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
} else {
CHECK(buffer != NULL);
buffer->release();
@@ -694,8 +694,8 @@
"We attempted to seek beyond EOS and expected "
"ERROR_END_OF_STREAM to be returned, but instead "
"we found some other error.");
- CHECK_EQ(err, ERROR_END_OF_STREAM);
- CHECK_EQ(buffer, NULL);
+ CHECK_EQ(err, (status_t)ERROR_END_OF_STREAM);
+ CHECK(buffer == NULL);
} else {
EXPECT(err == OK,
"Expected a valid buffer to be returned from "
@@ -715,7 +715,7 @@
buffer->release();
buffer = NULL;
- CHECK_EQ(codec->stop(), OK);
+ CHECK_EQ(codec->stop(), (status_t)OK);
return UNKNOWN_ERROR;
}
@@ -725,7 +725,7 @@
}
}
- CHECK_EQ(codec->stop(), OK);
+ CHECK_EQ(codec->stop(), (status_t)OK);
return OK;
}
@@ -841,7 +841,7 @@
srand(seed);
sp<Harness> h = new Harness;
- CHECK_EQ(h->initCheck(), OK);
+ CHECK_EQ(h->initCheck(), (status_t)OK);
if (argc == 0) {
h->testAll();
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 76b507f..d7cec04 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -35,7 +35,7 @@
#include <binder/ProcessState.h>
#include <ui/FramebufferNativeWindow.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
@@ -475,7 +475,7 @@
mr->setVideoFrameRate(fps);
mr->prepare();
ALOGV("Starting MediaRecorder...");
- CHECK_EQ(OK, mr->start());
+ CHECK_EQ((status_t)OK, mr->start());
return mr;
}
@@ -757,7 +757,7 @@
ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
@@ -886,7 +886,7 @@
mEglSurface = EGL_NO_SURFACE;
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
@@ -929,7 +929,7 @@
mEglSurface = EGL_NO_SURFACE;
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
index f2c4d54..afb73fb 100644
--- a/media/libstagefright/timedtext/TimedTextInBandSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
@@ -19,8 +19,8 @@
#include <utils/Log.h>
#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ADebug.h> // CHECK_XX macro
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h> // CHECK_XX macro
#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 8c2df88..bf7cbf6 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "TimedTextPlayer"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
#include <media/MediaPlayerInterface.h>
diff --git a/media/libstagefright/yuv/YUVCanvas.cpp b/media/libstagefright/yuv/YUVCanvas.cpp
index 38aa779..4c9fee8 100644
--- a/media/libstagefright/yuv/YUVCanvas.cpp
+++ b/media/libstagefright/yuv/YUVCanvas.cpp
@@ -17,7 +17,7 @@
#define LOG_NDEBUG 0
#define LOG_TAG "YUVCanvas"
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/YUVCanvas.h>
#include <media/stagefright/YUVImage.h>
#include <ui/Rect.h>
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index 0d67c96..7b9000b 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -17,9 +17,9 @@
#define LOG_NDEBUG 0
#define LOG_TAG "YUVImage"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/YUVImage.h>
#include <ui/Rect.h>
-#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 81c6167..025a131 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -26,6 +26,7 @@
libcutils \
libskia \
libstagefright \
+ libstagefright_foundation \
libbinder \
libutils \
libjpeg
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
index dfdf676..a25e854 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <SkBitmap.h>
#include "SkOmxPixelRef.h"
@@ -32,7 +32,7 @@
SkOmxPixelRef::~SkOmxPixelRef() {
mBuffer->release();
- CHECK_EQ(mDecoder->stop(), OK);
+ CHECK_EQ(mDecoder->stop(), (status_t)OK);
SkSafeUnref(mCTable);
}
diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp
index 5f44203..f764121a 100644
--- a/media/tests/omxjpegdecoder/StreamSource.cpp
+++ b/media/tests/omxjpegdecoder/StreamSource.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include "StreamSource.h"
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 42df66c..6424744 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -25,7 +25,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -89,7 +89,7 @@
OmxJpegImageDecoder::OmxJpegImageDecoder() {
status_t err = mClient.connect();
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
}
OmxJpegImageDecoder::~OmxJpegImageDecoder() {
@@ -152,7 +152,7 @@
int64_t duration = getNowUs() - startTime;
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
}
printf("Duration in decoder->read(): %.1f (msecs). \n",
duration / 1E3 );
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index f5db57c..01db1d3 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -18,9 +18,9 @@
#include <utils/Log.h>
#include <android/asset_manager_jni.h>
-#include <utils/AssetManager.h>
-#include <utils/AssetDir.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetDir.h>
+#include <androidfw/AssetManager.h>
#include <utils/threads.h>
#include "jni.h"
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 687924b..7eb51dd 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "Configuration"
#include <utils/Log.h>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
#include <android_runtime/android_content_res_Configuration.h>
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 91671c3..6eb2990 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -18,8 +18,8 @@
#include <utils/Log.h>
#include <android/input.h>
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/native/android/obb.cpp b/native/android/obb.cpp
index e0cb1a6..e990024 100644
--- a/native/android/obb.cpp
+++ b/native/android/obb.cpp
@@ -18,8 +18,8 @@
#include <android/obb.h>
+#include <androidfw/ObbFile.h>
#include <utils/Log.h>
-#include <utils/ObbFile.h>
using namespace android;
diff --git a/opengl/java/android/opengl/Group.java b/opengl/java/android/opengl/Group.java
deleted file mode 100644
index 1ef2953..0000000
--- a/opengl/java/android/opengl/Group.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.opengl;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Iterator;
-import javax.microedition.khronos.opengles.*;
-
-class MaterialIndices {
-
- private Material material = null;
- private ShortBuffer indexBuffer = null;
-
- public MaterialIndices(Material material, ShortBuffer indexBuffer) {
- this.material = material;
- this.indexBuffer = indexBuffer;
- }
-
- public Material getMaterial() {
- return material;
- }
-
- public ShortBuffer getIndexBuffer() {
- return indexBuffer;
- }
-}
-
-/**
- * {@hide}
- */
-public class Group {
-
- private Object3D parent;
- private String name;
-
- private List<MaterialIndices> materialIndices =
- new ArrayList<MaterialIndices>();
-
- public Group(Object3D parent) {
- this.parent = parent;
- }
-
- public String getName() {
- return name;
- }
-
- public void load(DataInputStream dis) throws IOException {
- dis.readInt(); // name length
- this.name = dis.readUTF();
-
- int numMaterials = dis.readInt();
-
- for (int i = 0; i < numMaterials; i++) {
- dis.readInt(); // material name length
- String matName = dis.readUTF();
- Material material = parent.getMaterial(matName);
-
- int numIndices = dis.readInt();
- byte[] indicesBytes = new byte[numIndices * 2];
- dis.readFully(indicesBytes);
-
- // Swap bytes from network to native order if necessary
- if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
- int idx = 0;
- for (int j = 0; j < numIndices; j++) {
- byte b0 = indicesBytes[idx];
- byte b1 = indicesBytes[idx + 1];
- indicesBytes[idx] = b1;
- indicesBytes[idx + 1] = b0;
- idx += 2;
- }
- }
-
- ByteBuffer ibb = ByteBuffer.allocateDirect(2*numIndices);
- ibb.order(ByteOrder.nativeOrder());
- ibb.put(indicesBytes);
- ibb.position(0);
-
- ShortBuffer sb = ibb.asShortBuffer();
- materialIndices.add(new MaterialIndices(material, sb));
- }
- }
-
- public int getNumTriangles() {
- int numTriangles = 0;
- Iterator<MaterialIndices> iter = materialIndices.iterator();
- while (iter.hasNext()) {
- MaterialIndices matIdx = iter.next();
- ShortBuffer indexBuffer = matIdx.getIndexBuffer();
- numTriangles += indexBuffer.capacity()/3;
- }
- return numTriangles;
- }
-
- public void draw(GL10 gl) {
- gl.glDisableClientState(gl.GL_COLOR_ARRAY);
-
- gl.glVertexPointer(3, gl.GL_FIXED, 0, parent.getVertexBuffer());
- gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
-
- gl.glNormalPointer(gl.GL_FIXED, 0, parent.getNormalBuffer());
- gl.glEnableClientState(gl.GL_NORMAL_ARRAY);
-
- if (parent.hasTexcoords()) {
- gl.glTexCoordPointer(2, gl.GL_FIXED, 0, parent.getTexcoordBuffer());
- gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY);
- gl.glEnable(gl.GL_TEXTURE_2D);
- } else {
- gl.glDisable(gl.GL_TEXTURE_2D);
- }
-
- Iterator<MaterialIndices> iter = materialIndices.iterator();
- while (iter.hasNext()) {
- MaterialIndices matIdx = iter.next();
- ShortBuffer indexBuffer = matIdx.getIndexBuffer();
- Material mat = matIdx.getMaterial();
- mat.setMaterialParameters(gl);
- if (parent.hasTexcoords() && mat.getMap_Kd().length() > 0) {
- Texture texture = parent.getTexture(mat.getMap_Kd());
- texture.setTextureParameters(gl);
- }
-
- gl.glDrawElements(gl.GL_TRIANGLES,
- indexBuffer.capacity(),
- gl.GL_UNSIGNED_SHORT,
- indexBuffer);
- }
- }
-
- public String toString() {
- return "Group[" +
- "name=" + name +
- "]";
- }
-}
diff --git a/opengl/java/android/opengl/Material.java b/opengl/java/android/opengl/Material.java
deleted file mode 100644
index 60a3e72..0000000
--- a/opengl/java/android/opengl/Material.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.opengl;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import javax.microedition.khronos.opengles.GL10;
-
-/**
- * {@hide}
- */
-public class Material {
-
- private Object3D parent;
- private String name;
- private String map_kd;
- private float[] ka = new float[4];
- private float[] kd = new float[4];
- private float[] ks = new float[4];
- private float ns;
- private int illum;
- private float d;
-
- private static float[] black = { 0.0f, 0.0f, 0.0f, 1.0f };
-
- public Material(Object3D parent) {
- this.parent = parent;
- }
-
- public String getName() {
- return name;
- }
-
- public String getMap_Kd() {
- return map_kd;
- }
-
- public void setMaterialParameters(GL10 gl) {
- gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0);
- gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0);
- gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0);
- gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS,
- Math.min(Math.max(ns, 0), 128));
-
-// if (illum == 0) {
-// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0);
-// } else {
-// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, ka, 0);
-// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0);
-// }
-
-// if (illum > 1) {
-// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0);
-// gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS,
-// Math.min(Math.max(ns, 0), 128));
-// } else {
-// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, black, 0);
-// }
- }
-
- public void load(DataInputStream dis) throws IOException {
- dis.readInt(); // name length
- this.name = dis.readUTF();
-
- dis.readInt(); // map_kdLength
- this.map_kd = dis.readUTF();
-
- if (parent.hasTexcoords() && map_kd.length() > 0) {
- parent.loadTexture(map_kd);
- }
-
- this.ka[0] = dis.readFloat();
- this.ka[1] = dis.readFloat();
- this.ka[2] = dis.readFloat();
- this.ka[3] = dis.readFloat();
-
- this.kd[0] = dis.readFloat();
- this.kd[1] = dis.readFloat();
- this.kd[2] = dis.readFloat();
- this.kd[3] = dis.readFloat();
-
- this.ks[0] = dis.readFloat();
- this.ks[1] = dis.readFloat();
- this.ks[2] = dis.readFloat();
- this.ks[3] = dis.readFloat();
-
- this.ns = dis.readFloat();
- this.illum = dis.readInt();
- this.d = dis.readFloat();
- }
-
- public String toString() {
- return "Material[" +
- "name=\"" + name + "\"," +
- "ka={" + ka[0] + "," + ka[1] + "," + ka[2] + "}," +
- "kd={" + kd[0] + "," + kd[1] + "," + kd[2] + "}," +
- "ks={" + ks[0] + "," + ks[1] + "," + ks[2] + "}," +
- "ns=" + ns + "," +
- "map_kd=\"" +
- (map_kd == null ? "" : map_kd) +
- "\"," +
- "illum=" + illum + "," +
- "d=" + d +
- "]";
- }
-}
diff --git a/opengl/java/android/opengl/Object3D.java b/opengl/java/android/opengl/Object3D.java
deleted file mode 100644
index 340c6a7..0000000
--- a/opengl/java/android/opengl/Object3D.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.opengl;
-
-import java.io.BufferedReader;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.IntBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import javax.microedition.khronos.opengles.*;
-
-/**
- * {@hide}
- */
-public abstract class Object3D {
-
- private boolean mHasTexcoords = false;
-
- private float mBoundsMinX = Float.MAX_VALUE;
- private float mBoundsMaxX = Float.MIN_VALUE;
- private float mBoundsMinY = Float.MAX_VALUE;
- private float mBoundsMaxY = Float.MIN_VALUE;
- private float mBoundsMinZ = Float.MAX_VALUE;
- private float mBoundsMaxZ = Float.MIN_VALUE;
-
- private IntBuffer mVertexBuffer;
- private IntBuffer mNormalBuffer;
- private IntBuffer mTexcoordBuffer;
-
- // All groups, by name
- private Map<String, Group> mGroups;
-
- // All materials, by name
- private Map<String, Material> mMaterials;
-
- // All texture maps, by name
- private Map<String, Texture> mTextures;
-
- public Object3D() {
- reset();
- }
-
- /**
- * Override this method with an implementation that contructs
- * and InputStream from the given filename. For example, if the
- * source files are to be retrieved using an AssetManager,
- * the implementation would use AssetManager.load() to
- * get the input stream.
- */
- public abstract InputStream readFile(String filename) throws IOException;
-
- private void reset() {
- mVertexBuffer = mNormalBuffer = mTexcoordBuffer = null;
-
- mGroups = new HashMap<String,Group>();
- mMaterials = new HashMap<String,Material>();
- mTextures = new HashMap<String,Texture>();
- }
-
- public Material getMaterial(String name) {
- Material mat = mMaterials.get(name);
- return mat;
- }
-
- public Texture getTexture(String name) {
- return mTextures.get(name);
- }
-
- public IntBuffer getVertexBuffer() {
- return mVertexBuffer;
- }
-
- public IntBuffer getNormalBuffer() {
- return mNormalBuffer;
- }
-
- public IntBuffer getTexcoordBuffer() {
- return mTexcoordBuffer;
- }
-
- public int getNumTriangles() {
- int numTriangles = 0;
- Iterator<Group> iter = mGroups.values().iterator();
- while (iter.hasNext()) {
- numTriangles += iter.next().getNumTriangles();
- }
- return numTriangles;
- }
-
- public boolean hasTexcoords() {
- return mHasTexcoords;
- }
-
- public float getBoundsMinX() {
- return mBoundsMinX;
- }
-
- public float getBoundsMaxX() {
- return mBoundsMaxX;
- }
-
- public float getBoundsMinY() {
- return mBoundsMinY;
- }
-
- public float getBoundsMaxY() {
- return mBoundsMaxY;
- }
-
- public float getBoundsMinZ() {
- return mBoundsMinZ;
- }
-
- public float getBoundsMaxZ() {
- return mBoundsMaxZ;
- }
-
- public void loadTexture(String name) throws IOException {
- InputStream is = readFile(name + ".raw");
- Texture texture = new Texture(is);
- mTextures.put(name, texture);
- }
-
- private static void verifyByte(DataInputStream dis, int b)
- throws IOException {
- int x = dis.read() & 0xff;
- if (x != b) {
- throw new RuntimeException("Bad byte: " +
- x +
- " (expected " + b + ")");
- }
- }
-
- public void load(String filename) throws IOException {
- reset();
-
- DataInputStream dis = new DataInputStream(readFile(filename));
- verifyByte(dis, 'g' + 128);
- verifyByte(dis, 'l');
- verifyByte(dis, 'e');
- verifyByte(dis, 's');
-
- int numTuples = dis.readInt();
-
- this.mBoundsMinX = dis.readFloat();
- this.mBoundsMaxX = dis.readFloat();
- this.mBoundsMinY = dis.readFloat();
- this.mBoundsMaxY = dis.readFloat();
- this.mBoundsMinZ = dis.readFloat();
- this.mBoundsMaxZ = dis.readFloat();
-
- this.mHasTexcoords = dis.readInt() == 1;
-
- int intsPerTuple = mHasTexcoords ? 8 : 6;
- int numInts = numTuples*intsPerTuple;
-
- int len = 4*numTuples*(mHasTexcoords ? 8 : 6);
-
- byte[] tmp = new byte[len];
- int tidx = 0;
- while (tidx < len) {
- tidx += dis.read(tmp, tidx, len - tidx);
- }
- if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < len; i += 4) {
- byte tmp0 = tmp[i];
- byte tmp1 = tmp[i + 1];
- byte tmp2 = tmp[i + 2];
- byte tmp3 = tmp[i + 3];
- tmp[i] = tmp3;
- tmp[i + 1] = tmp2;
- tmp[i + 2] = tmp1;
- tmp[i + 3] = tmp0;
- }
- }
-
- ByteBuffer allbb = ByteBuffer.allocateDirect(len);
- allbb.order(ByteOrder.nativeOrder());
- allbb.put(tmp);
-
- allbb.position(0);
- allbb.limit(4*3*numTuples);
- ByteBuffer vbb = allbb.slice();
- this.mVertexBuffer = vbb.asIntBuffer();
- mVertexBuffer.position(0);
-
- if (mHasTexcoords) {
- allbb.position(allbb.limit());
- allbb.limit(allbb.position() + 4*2*numTuples);
- ByteBuffer tbb = allbb.slice();
- this.mTexcoordBuffer = tbb.asIntBuffer();
- mTexcoordBuffer.position(0);
- }
-
- allbb.position(allbb.limit());
- allbb.limit(allbb.position() + 4*3*numTuples);
- ByteBuffer nbb = allbb.slice();
- this.mNormalBuffer = nbb.asIntBuffer();
- mNormalBuffer.position(0);
-
- int numMaterials = dis.readInt();
- for (int i = 0; i < numMaterials; i++) {
- Material mat = new Material(this);
- mat.load(dis);
- mMaterials.put(mat.getName(), mat);
- }
-
- int numGroups = dis.readInt();
- for (int i = 0; i < numGroups; i++) {
- Group g = new Group(this);
- g.load(dis);
- mGroups.put(g.getName(), g);
- }
- }
-
- public void draw(GL10 gl) {
- Iterator<Group> iter = mGroups.values().iterator();
- while (iter.hasNext()) {
- iter.next().draw(gl);
- }
- }
-}
-
diff --git a/opengl/java/android/opengl/Texture.java b/opengl/java/android/opengl/Texture.java
deleted file mode 100644
index dcd894d..0000000
--- a/opengl/java/android/opengl/Texture.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.opengl;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import javax.microedition.khronos.opengles.GL10;
-
-import android.content.res.AssetManager;
-
-/**
- * {@hide}
- */
-public class Texture {
-
- private int width, height, bpp;
- private ByteBuffer data;
- private int name = -1;
-
- // Texture maps have the following format. All integers
- // are 16 bits, high byte first. Pixels are in 5/6/5
- // RGB format, low byte first.
- //
- // width
- // height
- // pixel (0, 0)
- // pixel (1, 0)
- // ...
- // pixel (width - 1, height - 1)
-
- private int readInt16(InputStream is) throws IOException {
- return is.read() | (is.read() << 8);
- }
-
- public Texture(InputStream is) throws IOException {
- this.width = readInt16(is);
- this.height = readInt16(is);
- this.bpp = 2;
-
- int npixels = width*height;
- int nbytes = npixels*bpp;
- byte[] arr = new byte[nbytes];
-
- int idx = 0;
- while (idx < nbytes) {
- int nread = is.read(arr, idx, nbytes - idx);
- idx += nread;
- }
-
- if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
- // Swap pairs of bytes on big-endian platforms
- for (int i = 0; i < npixels; i++) {
- int j = i*2;
- int k = j + 1;
-
- byte tmp = arr[j];
- arr[j] = arr[k];
- arr[k] = tmp;
- }
- }
-
- this.data = ByteBuffer.allocateDirect(arr.length);
- this.data.order(ByteOrder.nativeOrder());
- data.put(arr);
- data.position(0);
- }
-
- private int loadTexture(GL10 gl,
- int textureUnit,
- int minFilter, int magFilter,
- int wrapS, int wrapT,
- int mode,
- int width, int height,
- int dataType,
- Buffer data) {
- int[] texture = new int[1];
- gl.glGenTextures(1, texture, 0);
-
- gl.glEnable(gl.GL_TEXTURE_2D);
- gl.glClientActiveTexture(textureUnit);
- gl.glBindTexture(gl.GL_TEXTURE_2D, texture[0]);
- gl.glTexParameterf(gl.GL_TEXTURE_2D,
- gl.GL_TEXTURE_MIN_FILTER,
- minFilter);
- gl.glTexParameterf(gl.GL_TEXTURE_2D,
- gl.GL_TEXTURE_MAG_FILTER,
- magFilter);
- gl.glTexParameterf(gl.GL_TEXTURE_2D,
- gl.GL_TEXTURE_WRAP_S,
- wrapS);
- gl.glTexParameterf(gl.GL_TEXTURE_2D,
- gl.GL_TEXTURE_WRAP_T,
- wrapT);
- gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, mode);
-
- gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB,
- width, height,
- 0, gl.GL_RGB, dataType,
- data);
-
- return texture[0];
- }
-
- public void setTextureParameters(GL10 gl) {
- if (name < 0) {
- name = loadTexture(gl,
- gl.GL_TEXTURE0,
- gl.GL_NEAREST, gl.GL_NEAREST,
- gl.GL_REPEAT, gl.GL_REPEAT,
- gl.GL_MODULATE,
- width, height,
- gl.GL_UNSIGNED_SHORT_5_6_5,
- data);
- }
-
- gl.glBindTexture(gl.GL_TEXTURE_2D, name);
- }
-}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 06be2ef..0b1016c 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -118,12 +118,6 @@
// ----------------------------------------------------------------------------
-Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
- : dpy(dpy), impl(impl), tag(tag) {
-}
-
-// ----------------------------------------------------------------------------
-
Loader::Loader()
{
char line[256];
@@ -131,8 +125,9 @@
/* Special case for GLES emulation */
if (checkGlesEmulationStatus() == 0) {
- ALOGD("Emulator without GPU support detected. Fallback to software renderer.");
- gConfig.add( entry_t(0, 0, "android") );
+ ALOGD("Emulator without GPU support detected. "
+ "Fallback to software renderer.");
+ mDriverTag.setTo("android");
return;
}
@@ -141,14 +136,16 @@
if (cfg == NULL) {
// default config
ALOGD("egl.cfg not found, using default config");
- gConfig.add( entry_t(0, 0, "android") );
+ mDriverTag.setTo("android");
} else {
while (fgets(line, 256, cfg)) {
- int dpy;
- int impl;
+ int dpy, impl;
if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
//ALOGD(">>> %u %u %s", dpy, impl, tag);
- gConfig.add( entry_t(dpy, impl, tag) );
+ // We only load the h/w accelerated implementation
+ if (tag != String8("android")) {
+ mDriverTag = tag;
+ }
}
}
fclose(cfg);
@@ -160,30 +157,12 @@
GLTrace_stop();
}
-const char* Loader::getTag(int dpy, int impl)
+void* Loader::open(egl_connection_t* cnx)
{
- const Vector<entry_t>& cfgs(gConfig);
- const size_t c = cfgs.size();
- for (size_t i=0 ; i<c ; i++) {
- if (dpy == cfgs[i].dpy)
- if (impl == cfgs[i].impl)
- return cfgs[i].tag.string();
- }
- return 0;
-}
-
-void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx)
-{
- /*
- * TODO: if we don't find display/0, then use 0/0
- * (0/0 should always work)
- */
-
void* dso;
- int index = int(display);
driver_t* hnd = 0;
- char const* tag = getTag(index, impl);
+ char const* tag = mDriverTag.string();
if (tag) {
dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
@@ -193,16 +172,14 @@
dso = load_driver("EGL", tag, cnx, EGL);
if (dso) {
hnd = new driver_t(dso);
-
// TODO: make this more automated
hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
-
- hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
+ hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
}
}
}
- LOG_FATAL_IF(!index && !impl && !hnd,
+ LOG_FATAL_IF(!index && !hnd,
"couldn't find the default OpenGL ES implementation "
"for default display");
@@ -221,7 +198,7 @@
__eglMustCastToProperFunctionPointerType* curr,
getProcAddressType getProcAddress)
{
- const size_t SIZE = 256;
+ const ssize_t SIZE = 256;
char scrap[SIZE];
while (*api) {
char const * name = *api;
@@ -326,14 +303,14 @@
if (mask & GLESv1_CM) {
init_api(dso, gl_names,
(__eglMustCastToProperFunctionPointerType*)
- &cnx->hooks[GLESv1_INDEX]->gl,
+ &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
getProcAddress);
}
if (mask & GLESv2) {
init_api(dso, gl_names,
(__eglMustCastToProperFunctionPointerType*)
- &cnx->hooks[GLESv2_INDEX]->gl,
+ &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
getProcAddress);
}
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 580d6e4..30773cb 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -24,7 +24,6 @@
#include <utils/Errors.h>
#include <utils/Singleton.h>
#include <utils/String8.h>
-#include <utils/Vector.h>
#include <EGL/egl.h>
@@ -53,23 +52,13 @@
void* dso[3];
};
- struct entry_t {
- entry_t() { }
- entry_t(int dpy, int impl, const char* tag);
- int dpy;
- int impl;
- String8 tag;
- };
-
- Vector<entry_t> gConfig;
+ String8 mDriverTag;
getProcAddressType getProcAddress;
- const char* getTag(int dpy, int impl);
-
public:
~Loader();
- void* open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx);
+ void* open(egl_connection_t* cnx);
status_t close(void* driver);
private:
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 83933e5..eec5ce1 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -48,8 +48,8 @@
namespace android {
// ----------------------------------------------------------------------------
-egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
-gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+egl_connection_t gEGLImpl;
+gl_hooks_t gHooks[2];
gl_hooks_t gHooksNoContext;
pthread_key_t gGLWrapperKey = -1;
@@ -187,16 +187,13 @@
return dp;
}
-egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config,
+egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig,
egl_display_t const*& dp) {
dp = validate_display(dpy);
if (!dp)
return (egl_connection_t*) NULL;
- if (intptr_t(config) >= dp->numTotalConfigs) {
- return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
- }
- egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl];
+ egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso == 0) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
@@ -205,34 +202,6 @@
// ----------------------------------------------------------------------------
-EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
-{
- EGLContext context = egl_tls_t::getContext();
- if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
- return EGL_NO_IMAGE_KHR;
-
- egl_context_t const * const c = get_context(context);
- if (c == NULL) // this should never happen, by construction
- return EGL_NO_IMAGE_KHR;
-
- egl_display_t* display = egl_display_t::get(c->dpy);
- if (display == NULL) // this should never happen, by construction
- return EGL_NO_IMAGE_KHR;
-
- ImageRef _i(display, image);
- if (!_i.get())
- return EGL_NO_IMAGE_KHR;
-
- // here we don't validate the context because if it's been marked for
- // termination, this call should still succeed since it's internal to
- // EGL.
-
- egl_image_t const * const i = get_image(image);
- return i->images[c->impl];
-}
-
-// ----------------------------------------------------------------------------
-
const GLubyte * egl_get_string_for_current_context(GLenum name) {
// NOTE: returning NULL here will fall-back to the default
// implementation.
@@ -266,34 +235,17 @@
// get our driver loader
Loader& loader(Loader::getInstance());
- // dynamically load all our EGL implementations
- egl_connection_t* cnx;
-
- cnx = &gEGLImpl[IMPL_SOFTWARE];
+ // dynamically load our EGL implementation
+ egl_connection_t* cnx = &gEGLImpl;
if (cnx->dso == 0) {
- cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
- cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
- cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
+ cnx->hooks[egl_connection_t::GLESv1_INDEX] =
+ &gHooks[egl_connection_t::GLESv1_INDEX];
+ cnx->hooks[egl_connection_t::GLESv2_INDEX] =
+ &gHooks[egl_connection_t::GLESv2_INDEX];
+ cnx->dso = loader.open(cnx);
}
- cnx = &gEGLImpl[IMPL_HARDWARE];
- if (cnx->dso == 0) {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.hw", value, "1");
- if (atoi(value) != 0) {
- cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
- cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
- cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
- } else {
- ALOGD("3D hardware acceleration is disabled");
- }
- }
-
- if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
- return EGL_FALSE;
- }
-
- return EGL_TRUE;
+ return cnx->dso ? EGL_TRUE : EGL_FALSE;
}
static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 73aab26..a5dc832 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -44,6 +44,7 @@
#include "egl_impl.h"
#include "egl_object.h"
#include "egl_tls.h"
+#include "egldefs.h"
using namespace android;
@@ -88,24 +89,6 @@
// ----------------------------------------------------------------------------
-template<typename T>
-static __attribute__((noinline))
-int binarySearch(T const sortedArray[], int first, int last, T key) {
- while (first <= last) {
- int mid = (first + last) / 2;
- if (sortedArray[mid] < key) {
- first = mid + 1;
- } else if (key < sortedArray[mid]) {
- last = mid - 1;
- } else {
- return mid;
- }
- }
- return -1;
-}
-
-// ----------------------------------------------------------------------------
-
namespace android {
extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
extern EGLBoolean egl_init_drivers();
@@ -183,21 +166,20 @@
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- GLint numConfigs = dp->numTotalConfigs;
- if (!configs) {
- *num_config = numConfigs;
- return EGL_TRUE;
+ if (num_config==0) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
- GLint n = 0;
- for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
- *configs++ = EGLConfig(i);
- config_size--;
- n++;
+ EGLBoolean res = EGL_FALSE;
+ *num_config = 0;
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ res = cnx->egl.eglGetConfigs(
+ dp->disp.dpy, configs, config_size, num_config);
}
-
- *num_config = n;
- return EGL_TRUE;
+
+ return res;
}
EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
@@ -213,105 +195,13 @@
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
- EGLint n;
EGLBoolean res = EGL_FALSE;
*num_config = 0;
-
- // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
- // to do this, we have to go through the attrib_list array once
- // to figure out both its size and if it contains an EGL_CONFIG_ID
- // key. If so, the full array is copied and patched.
- // NOTE: we assume that there can be only one occurrence
- // of EGL_CONFIG_ID.
-
- EGLint patch_index = -1;
- GLint attr;
- size_t size = 0;
- if (attrib_list) {
- while ((attr=attrib_list[size]) != EGL_NONE) {
- if (attr == EGL_CONFIG_ID)
- patch_index = size;
- size += 2;
- }
- }
- if (patch_index >= 0) {
- size += 2; // we need copy the sentinel as well
- EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
- if (new_list == 0)
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- memcpy(new_list, attrib_list, size*sizeof(EGLint));
-
- // patch the requested EGL_CONFIG_ID
- bool found = false;
- EGLConfig ourConfig(0);
- EGLint& configId(new_list[patch_index+1]);
- for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
- if (dp->configs[i].configId == configId) {
- ourConfig = EGLConfig(i);
- configId = dp->configs[i].implConfigId;
- found = true;
- break;
- }
- }
-
- egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
- if (found && cnx->dso) {
- // and switch to the new list
- attrib_list = const_cast<const EGLint *>(new_list);
-
- // At this point, the only configuration that can match is
- // dp->configs[i][index], however, we don't know if it would be
- // rejected because of the other attributes, so we do have to call
- // cnx->egl.eglChooseConfig() -- but we don't have to loop
- // through all the EGLimpl[].
- // We also know we can only get a single config back, and we know
- // which one.
-
- res = cnx->egl.eglChooseConfig(
- dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
- attrib_list, configs, config_size, &n);
- if (res && n>0) {
- // n has to be 0 or 1, by construction, and we already know
- // which config it will return (since there can be only one).
- if (configs) {
- configs[0] = ourConfig;
- }
- *num_config = 1;
- }
- }
-
- free(const_cast<EGLint *>(attrib_list));
- return res;
- }
-
-
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglChooseConfig(
- dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
- if (configs) {
- // now we need to convert these client EGLConfig to our
- // internal EGLConfig format.
- // This is done in O(n Log(n)) time.
- for (int j=0 ; j<n ; j++) {
- egl_config_t key(i, configs[j]);
- intptr_t index = binarySearch<egl_config_t>(
- dp->configs, 0, dp->numTotalConfigs, key);
- if (index >= 0) {
- configs[j] = EGLConfig(index);
- } else {
- return setError(EGL_BAD_CONFIG, EGL_FALSE);
- }
- }
- configs += n;
- config_size -= n;
- }
- *num_config += n;
- res = EGL_TRUE;
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ res = cnx->egl.eglChooseConfig(
+ dp->disp.dpy, attrib_list, configs, config_size, num_config);
}
return res;
}
@@ -325,13 +215,8 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (!cnx) return EGL_FALSE;
- if (attribute == EGL_CONFIG_ID) {
- *value = dp->configs[intptr_t(config)].configId;
- return EGL_TRUE;
- }
return cnx->egl.eglGetConfigAttrib(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, attribute, value);
+ dp->disp.dpy, config, attribute, value);
}
// ----------------------------------------------------------------------------
@@ -347,8 +232,7 @@
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
- EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
- EGLConfig iConfig = dp->configs[intptr_t(config)].config;
+ EGLDisplay iDpy = dp->disp.dpy;
EGLint format;
if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
@@ -359,7 +243,7 @@
// set the native window's buffers format to match this config
if (cnx->egl.eglGetConfigAttrib(iDpy,
- iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
+ config, EGL_NATIVE_VISUAL_ID, &format)) {
if (format != 0) {
int err = native_window_set_buffers_format(window, format);
if (err != 0) {
@@ -377,10 +261,9 @@
anw->setSwapInterval(anw, 1);
EGLSurface surface = cnx->egl.eglCreateWindowSurface(
- iDpy, iConfig, window, attrib_list);
+ iDpy, config, window, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
- dp->configs[intptr_t(config)].impl, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx);
return s;
}
@@ -401,11 +284,9 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, pixmap, attrib_list);
+ dp->disp.dpy, config, pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
- dp->configs[intptr_t(config)].impl, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
return s;
}
}
@@ -421,11 +302,9 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, attrib_list);
+ dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
- dp->configs[intptr_t(config)].impl, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
return s;
}
}
@@ -444,8 +323,7 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t * const s = get_surface(surface);
- EGLBoolean result = s->cnx->egl.eglDestroySurface(
- dp->disp[s->impl].dpy, s->surface);
+ EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
if (result == EGL_TRUE) {
_s.terminate();
}
@@ -465,16 +343,8 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
- EGLBoolean result(EGL_TRUE);
- if (attribute == EGL_CONFIG_ID) {
- // We need to remap EGL_CONFIG_IDs
- *value = dp->configs[intptr_t(s->config)].configId;
- } else {
- result = s->cnx->egl.eglQuerySurface(
- dp->disp[s->impl].dpy, s->surface, attribute, value);
- }
-
- return result;
+ return s->cnx->egl.eglQuerySurface(
+ dp->disp.dpy, s->surface, attribute, value);
}
void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
@@ -514,9 +384,7 @@
share_list = c->context;
}
EGLContext context = cnx->egl.eglCreateContext(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config,
- share_list, attrib_list);
+ dp->disp.dpy, config, share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
// figure out if it's a GLESv1 or GLESv2
int version = 0;
@@ -526,15 +394,14 @@
GLint value = *attrib_list++;
if (attr == EGL_CONTEXT_CLIENT_VERSION) {
if (value == 1) {
- version = GLESv1_INDEX;
+ version = egl_connection_t::GLESv1_INDEX;
} else if (value == 2) {
- version = GLESv2_INDEX;
+ version = egl_connection_t::GLESv2_INDEX;
}
}
};
}
- egl_context_t* c = new egl_context_t(dpy, context, config,
- dp->configs[intptr_t(config)].impl, cnx, version);
+ egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
#if EGL_TRACE
if (gEGLDebugLevel > 0)
GLTrace_eglCreateContext(version, c);
@@ -558,8 +425,7 @@
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
egl_context_t * const c = get_context(ctx);
- EGLBoolean result = c->cnx->egl.eglDestroyContext(
- dp->disp[c->impl].dpy, c->context);
+ EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
if (result == EGL_TRUE) {
_c.terminate();
}
@@ -625,20 +491,12 @@
// retrieve the underlying implementation's draw EGLSurface
if (draw != EGL_NO_SURFACE) {
d = get_surface(draw);
- // make sure the EGLContext and EGLSurface passed in are for
- // the same driver
- if (c && d->impl != c->impl)
- return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_draw = d->surface;
}
// retrieve the underlying implementation's read EGLSurface
if (read != EGL_NO_SURFACE) {
r = get_surface(read);
- // make sure the EGLContext and EGLSurface passed in are for
- // the same driver
- if (c && r->impl != c->impl)
- return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_read = r->surface;
}
@@ -682,17 +540,9 @@
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
egl_context_t * const c = get_context(ctx);
+ return c->cnx->egl.eglQueryContext(
+ dp->disp.dpy, c->context, attribute, value);
- EGLBoolean result(EGL_TRUE);
- if (attribute == EGL_CONFIG_ID) {
- *value = dp->configs[intptr_t(c->config)].configId;
- } else {
- // We need to remap EGL_CONFIG_IDs
- result = c->cnx->egl.eglQueryContext(
- dp->disp[c->impl].dpy, c->context, attribute, value);
- }
-
- return result;
}
EGLContext eglGetCurrentContext(void)
@@ -744,87 +594,37 @@
EGLBoolean eglWaitGL(void)
{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
-
clearError();
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->egl.eglWaitGL();
- }
- return res;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ return cnx->egl.eglWaitGL();
}
EGLBoolean eglWaitNative(EGLint engine)
{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
-
clearError();
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->egl.eglWaitNative(engine);
- }
- return res;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ return cnx->egl.eglWaitNative(engine);
}
EGLint eglGetError(void)
{
- EGLint result = EGL_SUCCESS;
- EGLint err;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- err = EGL_SUCCESS;
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso)
- err = cnx->egl.eglGetError();
- if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
- result = err;
+ EGLint err = EGL_SUCCESS;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ err = cnx->egl.eglGetError();
}
- err = egl_tls_t::getError();
- if (result == EGL_SUCCESS)
- result = err;
- return result;
-}
-
-// Note: Similar implementations of these functions also exist in
-// gl2.cpp and gl.cpp, and are used by applications that call the
-// exported entry points directly.
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
-
-static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
-static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
-
-static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- glEGLImageTargetTexture2DOES_impl(target, implImage);
-}
-
-static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
+ if (err == EGL_SUCCESS) {
+ err = egl_tls_t::getError();
+ }
+ return err;
}
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
@@ -885,32 +685,22 @@
if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
bool found = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->egl.eglGetProcAddress) {
- found = true;
- // Extensions are independent of the bound context
- cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglGetProcAddress) {
+ found = true;
+ // Extensions are independent of the bound context
+ cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
+ cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
#if EGL_TRACE
- debugHooks->ext.extensions[slot] =
- gHooksTrace.ext.extensions[slot] =
+ debugHooks->ext.extensions[slot] =
+ gHooksTrace.ext.extensions[slot] =
#endif
- cnx->egl.eglGetProcAddress(procname);
- }
+ cnx->egl.eglGetProcAddress(procname);
}
+
if (found) {
addr = gExtensionForwarders[slot];
-
- if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
- glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
- addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
- }
- if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
- glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
- addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
- }
-
sGLExtentionMap.add(name, addr);
sGLExtentionSlot++;
}
@@ -937,7 +727,7 @@
#endif
egl_surface_t const * const s = get_surface(draw);
- return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
+ return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
@@ -953,8 +743,7 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
- return s->cnx->egl.eglCopyBuffers(
- dp->disp[s->impl].dpy, s->surface, target);
+ return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -973,12 +762,8 @@
return dp->getExtensionString();
case EGL_CLIENT_APIS:
return dp->getClientApiString();
- case EGL_VERSION_HW_ANDROID: {
- if (gEGLImpl[IMPL_HARDWARE].dso) {
- return dp->disp[IMPL_HARDWARE].queryString.version;
- }
- return dp->disp[IMPL_SOFTWARE].queryString.version;
- }
+ case EGL_VERSION_HW_ANDROID:
+ return dp->disp.queryString.version;
}
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
@@ -1003,7 +788,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglSurfaceAttrib) {
return s->cnx->egl.eglSurfaceAttrib(
- dp->disp[s->impl].dpy, s->surface, attribute, value);
+ dp->disp.dpy, s->surface, attribute, value);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1023,7 +808,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglBindTexImage) {
return s->cnx->egl.eglBindTexImage(
- dp->disp[s->impl].dpy, s->surface, buffer);
+ dp->disp.dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1043,7 +828,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglReleaseTexImage) {
return s->cnx->egl.eglReleaseTexImage(
- dp->disp[s->impl].dpy, s->surface, buffer);
+ dp->disp.dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1056,17 +841,11 @@
if (!dp) return EGL_FALSE;
EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglSwapInterval) {
- if (cnx->egl.eglSwapInterval(
- dp->disp[i].dpy, interval) == EGL_FALSE) {
- res = EGL_FALSE;
- }
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglSwapInterval) {
+ res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
}
+
return res;
}
@@ -1079,23 +858,15 @@
{
clearError();
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (cnx->egl.eglWaitClient) {
- res = cnx->egl.eglWaitClient();
- } else {
- res = cnx->egl.eglWaitGL();
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ EGLBoolean res;
+ if (cnx->egl.eglWaitClient) {
+ res = cnx->egl.eglWaitClient();
+ } else {
+ res = cnx->egl.eglWaitGL();
}
return res;
}
@@ -1110,15 +881,9 @@
// bind this API on all EGLs
EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglBindAPI) {
- if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
- res = EGL_FALSE;
- }
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglBindAPI) {
+ res = cnx->egl.eglBindAPI(api);
}
return res;
}
@@ -1131,16 +896,11 @@
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglQueryAPI) {
- // the first one we find is okay, because they all
- // should be the same
- return cnx->egl.eglQueryAPI();
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglQueryAPI) {
+ return cnx->egl.eglQueryAPI();
}
+
// or, it can only be OpenGL ES
return EGL_OPENGL_ES_API;
}
@@ -1152,14 +912,11 @@
// If there is context bound to the thread, release it
egl_display_t::loseCurrent(get_context(getContext()));
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglReleaseThread) {
- cnx->egl.eglReleaseThread();
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglReleaseThread) {
+ cnx->egl.eglReleaseThread();
}
+
egl_tls_t::clearTLS();
#if EGL_TRACE
if (gEGLDebugLevel > 0)
@@ -1179,9 +936,7 @@
if (!cnx) return EGL_FALSE;
if (cnx->egl.eglCreatePbufferFromClientBuffer) {
return cnx->egl.eglCreatePbufferFromClientBuffer(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- buftype, buffer,
- dp->configs[intptr_t(config)].config, attrib_list);
+ dp->disp.dpy, buftype, buffer, config, attrib_list);
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
@@ -1205,7 +960,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglLockSurfaceKHR) {
return s->cnx->egl.eglLockSurfaceKHR(
- dp->disp[s->impl].dpy, s->surface, attrib_list);
+ dp->disp.dpy, s->surface, attrib_list);
}
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
@@ -1223,8 +978,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglUnlockSurfaceKHR) {
- return s->cnx->egl.eglUnlockSurfaceKHR(
- dp->disp[s->impl].dpy, s->surface);
+ return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
}
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
@@ -1237,67 +991,18 @@
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_NO_IMAGE_KHR;
- if (ctx != EGL_NO_CONTEXT) {
- ContextRef _c(dp, ctx);
- if (!_c.get())
- return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
- egl_context_t * const c = get_context(ctx);
- // since we have an EGLContext, we know which implementation to use
- EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
- dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
- if (image == EGL_NO_IMAGE_KHR)
- return image;
-
- egl_image_t* result = new egl_image_t(dpy, ctx);
- result->images[c->impl] = image;
- return (EGLImageKHR)result;
- } else {
- // EGL_NO_CONTEXT is a valid parameter
+ ContextRef _c(dp, ctx);
+ egl_context_t * const c = _c.get();
- /* Since we don't have a way to know which implementation to call,
- * we're calling all of them. If at least one of the implementation
- * succeeded, this is a success.
- */
-
- EGLint currentError = eglGetError();
-
- EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
- bool success = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- implImages[i] = EGL_NO_IMAGE_KHR;
- if (cnx->dso) {
- if (cnx->egl.eglCreateImageKHR) {
- implImages[i] = cnx->egl.eglCreateImageKHR(
- dp->disp[i].dpy, ctx, target, buffer, attrib_list);
- if (implImages[i] != EGL_NO_IMAGE_KHR) {
- success = true;
- }
- }
- }
- }
-
- if (!success) {
- // failure, if there was an error when we entered this function,
- // the error flag must not be updated.
- // Otherwise, the error is whatever happened in the implementation
- // that faulted.
- if (currentError != EGL_SUCCESS) {
- setError(currentError, EGL_NO_IMAGE_KHR);
- }
- return EGL_NO_IMAGE_KHR;
- } else {
- // In case of success, we need to clear all error flags
- // (especially those caused by the implementation that didn't
- // succeed). TODO: we could avoid this if we knew this was
- // a "full" success (all implementation succeeded).
- eglGetError();
- }
-
- egl_image_t* result = new egl_image_t(dpy, ctx);
- memcpy(result->images, implImages, sizeof(implImages));
- return (EGLImageKHR)result;
+ EGLImageKHR result = EGL_NO_IMAGE_KHR;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglCreateImageKHR) {
+ result = cnx->egl.eglCreateImageKHR(
+ dp->disp.dpy,
+ c ? c->context : EGL_NO_CONTEXT,
+ target, buffer, attrib_list);
}
+ return result;
}
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
@@ -1307,29 +1012,10 @@
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- ImageRef _i(dp, img);
- if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
- egl_image_t* image = get_image(img);
- bool success = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (image->images[i] != EGL_NO_IMAGE_KHR) {
- if (cnx->dso) {
- if (cnx->egl.eglDestroyImageKHR) {
- if (cnx->egl.eglDestroyImageKHR(
- dp->disp[i].dpy, image->images[i])) {
- success = true;
- }
- }
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
+ cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
}
- if (!success)
- return EGL_FALSE;
-
- _i.terminate();
-
return EGL_TRUE;
}
@@ -1345,21 +1031,12 @@
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_NO_SYNC_KHR;
- EGLContext ctx = eglGetCurrentContext();
- ContextRef _c(dp, ctx);
- if (!_c.get())
- return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
-
- egl_context_t * const c = get_context(ctx);
EGLSyncKHR result = EGL_NO_SYNC_KHR;
- if (c->cnx->egl.eglCreateSyncKHR) {
- EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
- dp->disp[c->impl].dpy, type, attrib_list);
- if (sync == EGL_NO_SYNC_KHR)
- return sync;
- result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
+ result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
}
- return (EGLSyncKHR)result;
+ return result;
}
EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
@@ -1369,75 +1046,46 @@
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- SyncRef _s(dp, sync);
- if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- egl_sync_t* syncObject = get_sync(sync);
-
- EGLContext ctx = syncObject->context;
- ContextRef _c(dp, ctx);
- if (!_c.get())
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-
EGLBoolean result = EGL_FALSE;
- egl_context_t * const c = get_context(ctx);
- if (c->cnx->egl.eglDestroySyncKHR) {
- result = c->cnx->egl.eglDestroySyncKHR(
- dp->disp[c->impl].dpy, syncObject->sync);
- if (result)
- _s.terminate();
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
+ result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
}
return result;
}
-EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
+ EGLint flags, EGLTimeKHR timeout)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- SyncRef _s(dp, sync);
- if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- egl_sync_t* syncObject = get_sync(sync);
-
- EGLContext ctx = syncObject->context;
- ContextRef _c(dp, ctx);
- if (!_c.get())
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-
- egl_context_t * const c = get_context(ctx);
- if (c->cnx->egl.eglClientWaitSyncKHR) {
- return c->cnx->egl.eglClientWaitSyncKHR(
- dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
+ result = cnx->egl.eglClientWaitSyncKHR(
+ dp->disp.dpy, sync, flags, timeout);
}
-
- return EGL_FALSE;
+ return result;
}
-EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
+ EGLint attribute, EGLint *value)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- SyncRef _s(dp, sync);
- if (!_s.get())
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
- egl_sync_t* syncObject = get_sync(sync);
- EGLContext ctx = syncObject->context;
- ContextRef _c(dp, ctx);
- if (!_c.get())
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-
- egl_context_t * const c = get_context(ctx);
- if (c->cnx->egl.eglGetSyncAttribKHR) {
- return c->cnx->egl.eglGetSyncAttribKHR(
- dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
+ EGLBoolean result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
+ result = cnx->egl.eglGetSyncAttribKHR(
+ dp->disp.dpy, sync, attribute, value);
}
-
- return EGL_FALSE;
+ return result;
}
// ----------------------------------------------------------------------------
@@ -1458,12 +1106,10 @@
}
EGLuint64NV ret = 0;
- egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
+ egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- if (cnx->egl.eglGetSystemTimeFrequencyNV) {
- return cnx->egl.eglGetSystemTimeFrequencyNV();
- }
+ if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
+ return cnx->egl.eglGetSystemTimeFrequencyNV();
}
return setErrorQuiet(EGL_BAD_DISPLAY, 0);
@@ -1478,12 +1124,10 @@
}
EGLuint64NV ret = 0;
- egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
+ egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- if (cnx->egl.eglGetSystemTimeNV) {
- return cnx->egl.eglGetSystemTimeNV();
- }
+ if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
+ return cnx->egl.eglGetSystemTimeNV();
}
return setErrorQuiet(EGL_BAD_DISPLAY, 0);
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 7fd6519..c79fb5f 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -83,39 +83,39 @@
void egl_cache_t::initialize(egl_display_t *display) {
Mutex::Autolock lock(mMutex);
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
- const char* exts = display->disp[i].queryString.extensions;
- size_t bcExtLen = strlen(BC_EXT_STR);
- size_t extsLen = strlen(exts);
- bool equal = !strcmp(BC_EXT_STR, exts);
- bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
- bool atEnd = (bcExtLen+1) < extsLen &&
- !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
- bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
- if (equal || atStart || atEnd || inMiddle) {
- PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
- eglSetBlobCacheFuncsANDROID =
- reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
+ const char* exts = display->disp.queryString.extensions;
+ size_t bcExtLen = strlen(BC_EXT_STR);
+ size_t extsLen = strlen(exts);
+ bool equal = !strcmp(BC_EXT_STR, exts);
+ bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
+ bool atEnd = (bcExtLen+1) < extsLen &&
+ !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
+ bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
+ if (equal || atStart || atEnd || inMiddle) {
+ PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
+ eglSetBlobCacheFuncsANDROID =
+ reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
cnx->egl.eglGetProcAddress(
"eglSetBlobCacheFuncsANDROID"));
- if (eglSetBlobCacheFuncsANDROID == NULL) {
- ALOGE("EGL_ANDROID_blob_cache advertised by display %d, "
- "but unable to get eglSetBlobCacheFuncsANDROID", i);
- continue;
- }
+ if (eglSetBlobCacheFuncsANDROID == NULL) {
+ ALOGE("EGL_ANDROID_blob_cache advertised, "
+ "but unable to get eglSetBlobCacheFuncsANDROID");
+ return;
+ }
- eglSetBlobCacheFuncsANDROID(display->disp[i].dpy,
- android::setBlob, android::getBlob);
- EGLint err = cnx->egl.eglGetError();
- if (err != EGL_SUCCESS) {
- ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
- "%#x", err);
- }
+ eglSetBlobCacheFuncsANDROID(display->disp.dpy,
+ android::setBlob, android::getBlob);
+ EGLint err = cnx->egl.eglGetError();
+ if (err != EGL_SUCCESS) {
+ ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
+ "%#x", err);
}
}
}
+
mInitialized = true;
}
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 6b2ae51..c85b4ce 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -60,18 +60,12 @@
extern void initEglTraceLevel();
extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
-static int cmp_configs(const void* a, const void *b) {
- const egl_config_t& c0 = *(egl_config_t const *)a;
- const egl_config_t& c1 = *(egl_config_t const *)b;
- return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
-}
-
// ----------------------------------------------------------------------------
egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
egl_display_t::egl_display_t() :
- magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
+ magic('_dpy'), refs(0) {
}
egl_display_t::~egl_display_t() {
@@ -119,15 +113,13 @@
// get our driver loader
Loader& loader(Loader::getInstance());
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
- EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
- disp[i].dpy = dpy;
- if (dpy == EGL_NO_DISPLAY) {
- loader.close(cnx->dso);
- cnx->dso = NULL;
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
+ EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
+ disp.dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
}
}
@@ -160,12 +152,11 @@
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- cnx->major = -1;
- cnx->minor = -1;
- if (!cnx->dso)
- continue;
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ cnx->major = -1;
+ cnx->minor = -1;
+ if (cnx->dso) {
#if defined(ADRENO130)
#warning "Adreno-130 eglInitialize() workaround"
@@ -177,31 +168,30 @@
* eglGetDisplay() before calling eglInitialize();
*/
if (i == IMPL_HARDWARE) {
- disp[i].dpy =
- cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
#endif
- EGLDisplay idpy = disp[i].dpy;
+ EGLDisplay idpy = disp.dpy;
if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
- //ALOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
- // i, idpy, cnx->major, cnx->minor, cnx);
+ //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
+ // idpy, cnx->major, cnx->minor, cnx);
// display is now initialized
- disp[i].state = egl_display_t::INITIALIZED;
+ disp.state = egl_display_t::INITIALIZED;
// get the query-strings for this display for each implementation
- disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
+ disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
EGL_VENDOR);
- disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
+ disp.queryString.version = cnx->egl.eglQueryString(idpy,
EGL_VERSION);
- disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
+ disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
EGL_EXTENSIONS);
- disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
+ disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
EGL_CLIENT_APIS);
} else {
- ALOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+ ALOGW("eglInitialize(%p) failed (%s)", idpy,
egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
}
}
@@ -211,7 +201,7 @@
mVersionString.setTo(sVersionString);
mClientApiString.setTo(sClientApiString);
- // we only add extensions that exist in at least one implementation
+ // we only add extensions that exist in the implementation
char const* start = sExtensionString;
char const* end;
do {
@@ -223,15 +213,13 @@
if (len) {
// NOTE: we could avoid the copy if we had strnstr.
const String8 ext(start, len);
- // now go through all implementations and look for this extension
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- if (disp[i].queryString.extensions) {
- // if we find it, add this extension string to our list
- // (and don't forget the space)
- const char* match = strstr(disp[i].queryString.extensions, ext.string());
- if (match && (match[len] == ' ' || match[len] == 0)) {
- mExtensionString.append(start, len+1);
- }
+ // now look for this extension
+ if (disp.queryString.extensions) {
+ // if we find it, add this extension string to our list
+ // (and don't forget the space)
+ const char* match = strstr(disp.queryString.extensions, ext.string());
+ if (match && (match[len] == ' ' || match[len] == 0)) {
+ mExtensionString.append(start, len+1);
}
}
}
@@ -242,52 +230,12 @@
egl_cache_t::get()->initialize(this);
- EGLBoolean res = EGL_FALSE;
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
- EGLint n;
- if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
- disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
- if (disp[i].config) {
- if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
- &disp[i].numConfigs)) {
- numTotalConfigs += n;
- res = EGL_TRUE;
- }
- }
- }
- }
- }
-
- if (res == EGL_TRUE) {
- configs = new egl_config_t[numTotalConfigs];
- for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
- for (int j = 0; j < disp[i].numConfigs; j++) {
- configs[k].impl = i;
- configs[k].config = disp[i].config[j];
- configs[k].configId = k + 1; // CONFIG_ID start at 1
- // store the implementation's CONFIG_ID
- cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
- EGL_CONFIG_ID, &configs[k].implConfigId);
- k++;
- }
- }
- }
-
- // sort our configurations so we can do binary-searches
- qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
-
- refs++;
- if (major != NULL)
- *major = VERSION_MAJOR;
- if (minor != NULL)
- *minor = VERSION_MINOR;
- return EGL_TRUE;
- }
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ refs++;
+ if (major != NULL)
+ *major = VERSION_MAJOR;
+ if (minor != NULL)
+ *minor = VERSION_MINOR;
+ return EGL_TRUE;
}
EGLBoolean egl_display_t::terminate() {
@@ -305,22 +253,15 @@
}
EGLBoolean res = EGL_FALSE;
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
- if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
- ALOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
- egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
- }
- // REVISIT: it's unclear what to do if eglTerminate() fails
- free(disp[i].config);
-
- disp[i].numConfigs = 0;
- disp[i].config = 0;
- disp[i].state = egl_display_t::TERMINATED;
-
- res = EGL_TRUE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
+ if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
+ ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
+ egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
}
+ // REVISIT: it's unclear what to do if eglTerminate() fails
+ disp.state = egl_display_t::TERMINATED;
+ res = EGL_TRUE;
}
// Mark all objects remaining in the list as terminated, unless
@@ -337,8 +278,6 @@
objects.clear();
refs--;
- numTotalConfigs = 0;
- delete[] configs;
return res;
}
@@ -390,13 +329,13 @@
Mutex::Autolock _l(lock);
if (c) {
result = c->cnx->egl.eglMakeCurrent(
- disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
c->onMakeCurrent(draw, read);
}
} else {
result = cur_c->cnx->egl.eglMakeCurrent(
- disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
cur_c->onLooseCurrent();
}
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index f3c4ddf..6348228 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -44,23 +44,6 @@
// ----------------------------------------------------------------------------
-struct egl_config_t {
- egl_config_t() {}
- egl_config_t(int impl, EGLConfig config)
- : impl(impl), config(config), configId(0), implConfigId(0) { }
- int impl; // the implementation this config is for
- EGLConfig config; // the implementation's EGLConfig
- EGLint configId; // our CONFIG_ID
- EGLint implConfigId; // the implementation's CONFIG_ID
- inline bool operator < (const egl_config_t& rhs) const {
- if (impl < rhs.impl) return true;
- if (impl > rhs.impl) return false;
- return config < rhs.config;
- }
-};
-
-// ----------------------------------------------------------------------------
-
class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
static egl_display_t sDisplay[NUM_DISPLAYS];
EGLDisplay getDisplay(EGLNativeDisplayType display);
@@ -113,12 +96,9 @@
};
struct DisplayImpl {
- DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
- state(NOT_INITIALIZED), numConfigs(0) { }
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { }
EGLDisplay dpy;
- EGLConfig* config;
EGLint state;
- EGLint numConfigs;
strings_t queryString;
};
@@ -126,9 +106,7 @@
uint32_t magic;
public:
- DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- egl_config_t* configs;
+ DisplayImpl disp;
private:
uint32_t refs;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index b660c53..d0cbb31 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -64,9 +64,9 @@
// ----------------------------------------------------------------------------
egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version) :
+ egl_connection_t const* cnx, int version) :
egl_object_t(get_display(dpy)), dpy(dpy), context(context),
- config(config), read(0), draw(0), impl(impl), cnx(cnx),
+ config(config), read(0), draw(0), cnx(cnx),
version(version)
{
}
@@ -87,7 +87,7 @@
if (gl_extensions.isEmpty()) {
// call the implementation's glGetString(GL_EXTENSIONS)
- const char* exts = (const char *)gEGLImpl[impl].hooks[version]->gl.glGetString(GL_EXTENSIONS);
+ const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
gl_extensions.setTo(exts);
if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
String8 temp("GL_EXT_debug_marker ");
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index abd4cbb..4d91f54 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -125,7 +125,7 @@
// ----------------------------------------------------------------------------
-class egl_surface_t: public egl_object_t {
+class egl_surface_t : public egl_object_t {
protected:
~egl_surface_t() {
ANativeWindow* const window = win.get();
@@ -140,15 +140,14 @@
typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
- EGLSurface surface, int impl, egl_connection_t const* cnx) :
+ EGLSurface surface, egl_connection_t const* cnx) :
egl_object_t(get_display(dpy)), dpy(dpy), surface(surface),
- config(config), win(win), impl(impl), cnx(cnx) {
+ config(config), win(win), cnx(cnx) {
}
EGLDisplay dpy;
EGLSurface surface;
EGLConfig config;
sp<ANativeWindow> win;
- int impl;
egl_connection_t const* cnx;
};
@@ -159,7 +158,7 @@
typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version);
+ egl_connection_t const* cnx, int version);
void onLooseCurrent();
void onMakeCurrent(EGLSurface draw, EGLSurface read);
@@ -169,47 +168,15 @@
EGLConfig config;
EGLSurface read;
EGLSurface draw;
- int impl;
egl_connection_t const* cnx;
int version;
String8 gl_extensions;
};
-class egl_image_t: public egl_object_t {
-protected:
- ~egl_image_t() {}
-public:
- typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
-
- egl_image_t(EGLDisplay dpy, EGLContext context) :
- egl_object_t(get_display(dpy)), dpy(dpy), context(context) {
- memset(images, 0, sizeof(images));
- }
- EGLDisplay dpy;
- EGLContext context;
- EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
-};
-
-class egl_sync_t: public egl_object_t {
-protected:
- ~egl_sync_t() {}
-public:
- typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
-
- egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync) :
- egl_object_t(get_display(dpy)), dpy(dpy), context(context), sync(sync) {
- }
- EGLDisplay dpy;
- EGLContext context;
- EGLSyncKHR sync;
-};
-
// ----------------------------------------------------------------------------
typedef egl_surface_t::Ref SurfaceRef;
typedef egl_context_t::Ref ContextRef;
-typedef egl_image_t::Ref ImageRef;
-typedef egl_sync_t::Ref SyncRef;
// ----------------------------------------------------------------------------
@@ -228,16 +195,6 @@
return egl_to_native_cast<egl_context_t>(context);
}
-static inline
-egl_image_t* get_image(EGLImageKHR image) {
- return egl_to_native_cast<egl_image_t>(image);
-}
-
-static inline
-egl_sync_t* get_sync(EGLSyncKHR sync) {
- return egl_to_native_cast<egl_sync_t>(sync);
-}
-
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index ff20957..c900c1c 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -19,31 +19,24 @@
#include "hooks.h"
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-
// EGLDisplay are global, not attached to a given thread
const unsigned int NUM_DISPLAYS = 1;
-enum {
- IMPL_HARDWARE = 0,
- IMPL_SOFTWARE,
- IMPL_NUM_IMPLEMENTATIONS
-};
-
-enum {
- GLESv1_INDEX = 0,
- GLESv2_INDEX = 1,
-};
-
// ----------------------------------------------------------------------------
-struct egl_connection_t
-{
+struct egl_connection_t {
+ enum {
+ GLESv1_INDEX = 0,
+ GLESv2_INDEX = 1
+ };
+
inline egl_connection_t() : dso(0) { }
void * dso;
gl_hooks_t * hooks[2];
@@ -54,7 +47,7 @@
// ----------------------------------------------------------------------------
-extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooks[2];
extern gl_hooks_t gHooksNoContext;
extern pthread_key_t gGLWrapperKey;
extern "C" void gl_unimplemented();
@@ -63,7 +56,7 @@
extern char const * const gl_names[];
extern char const * const egl_names[];
-extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+extern egl_connection_t gEGLImpl;
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 79aa3cd..4345c2b 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -124,27 +124,3 @@
}
return ret;
}
-
-/*
- * These GL calls are special because they need to EGL to retrieve some
- * informations before they can execute.
- */
-
-extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
-extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
-
-
-void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- __glEGLImageTargetTexture2DOES(target, implImage);
-}
-
-void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- __glEGLImageTargetRenderbufferStorageOES(target, implImage);
-}
-
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
index a8907fd..c381075 100644
--- a/opengl/libs/GLES2/gl2ext_api.in
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -1,7 +1,7 @@
-void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
+void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
CALL_GL_API(glEGLImageTargetTexture2DOES, target, image);
}
-void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
+void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);
}
void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) {
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index adeaa5b..adcb60d 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -179,27 +179,3 @@
}
return ret;
}
-
-/*
- * These GL calls are special because they need to EGL to retrieve some
- * informations before they can execute.
- */
-
-extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
-extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
-
-
-void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- __glEGLImageTargetTexture2DOES(target, implImage);
-}
-
-void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- __glEGLImageTargetRenderbufferStorageOES(target, implImage);
-}
-
diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in
index 268a535..7cd6cb5 100644
--- a/opengl/libs/GLES_CM/glext_api.in
+++ b/opengl/libs/GLES_CM/glext_api.in
@@ -31,10 +31,10 @@
void API_ENTRY(glDrawTexfvOES)(const GLfloat *coords) {
CALL_GL_API(glDrawTexfvOES, coords);
}
-void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
+void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
CALL_GL_API(glEGLImageTargetTexture2DOES, target, image);
}
-void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
+void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);
}
void API_ENTRY(glAlphaFuncxOES)(GLenum func, GLclampx ref) {
diff --git a/opengl/libs/GLES_trace/TODO.txt b/opengl/libs/GLES_trace/TODO.txt
deleted file mode 100644
index f5e6e95..0000000
--- a/opengl/libs/GLES_trace/TODO.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-TODO:
- - Context - Currently, we don't do anything regarding the contexts that are created.
- Need to maintain more state regarding contexts, and figure out what happens in the
- presence of multiple contexts.
-
- - Transport: Each GLMessage is sent via a socket as soon as the message is received.
- i.e., there is no buffering of messages. Buffering should improve performance.
-
- - Initialization: On first connection, send some basic information that includes:
- 1. version of the trace library
- 2. implementation dependent GL state variables such as # of vertex arrays etc.
-
- - eglSwapBuffers: The images are lzf compressed, but there is no mode that transfers
- only the differences from the previous images.
diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto
index 11cf24f..2893e6e 100644
--- a/opengl/libs/GLES_trace/gltrace.proto
+++ b/opengl/libs/GLES_trace/gltrace.proto
@@ -543,11 +543,13 @@
required int32 context_id = 1; // GL context ID
required int64 start_time = 2; // time when call was invoked
- required int32 duration = 3; // duration of the call
+ required int32 duration = 3; // duration of the call (MONOTONIC TIME)
required Function function = 4 [default = invalid]; // GL function called
repeated DataType args = 5; // GL function's arguments
optional DataType returnValue = 6; // GL function's return value
optional FrameBuffer fb = 7; // contents of the framebuffer
+
+ optional int32 threadtime = 8; // duration of the call (THREAD TIME)
};
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
index bb9d4a7..d5f8180 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
@@ -1663,6 +1663,7 @@
const int GLMessage::kArgsFieldNumber;
const int GLMessage::kReturnValueFieldNumber;
const int GLMessage::kFbFieldNumber;
+const int GLMessage::kThreadtimeFieldNumber;
#endif // !_MSC_VER
GLMessage::GLMessage()
@@ -1689,6 +1690,7 @@
function_ = 3000;
returnvalue_ = NULL;
fb_ = NULL;
+ threadtime_ = 0;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
@@ -1730,6 +1732,7 @@
if (_has_bit(6)) {
if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear();
}
+ threadtime_ = 0;
}
args_.Clear();
::memset(_has_bits_, 0, sizeof(_has_bits_));
@@ -1846,6 +1849,22 @@
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(64)) goto parse_threadtime;
+ break;
+ }
+
+ // optional int32 threadtime = 8;
+ case 8: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_threadtime:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &threadtime_)));
+ _set_bit(7);
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectAtEnd()) return true;
break;
}
@@ -1906,6 +1925,11 @@
7, this->fb(), output);
}
+ // optional int32 threadtime = 8;
+ if (_has_bit(7)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->threadtime(), output);
+ }
+
}
int GLMessage::ByteSize() const {
@@ -1953,6 +1977,13 @@
this->fb());
}
+ // optional int32 threadtime = 8;
+ if (has_threadtime()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->threadtime());
+ }
+
}
// repeated .android.gltrace.GLMessage.DataType args = 5;
total_size += 1 * this->args_size();
@@ -1995,6 +2026,9 @@
if (from._has_bit(6)) {
mutable_fb()->::android::gltrace::GLMessage_FrameBuffer::MergeFrom(from.fb());
}
+ if (from._has_bit(7)) {
+ set_threadtime(from.threadtime());
+ }
}
}
@@ -2028,6 +2062,7 @@
args_.Swap(&other->args_);
std::swap(returnvalue_, other->returnvalue_);
std::swap(fb_, other->fb_);
+ std::swap(threadtime_, other->threadtime_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
std::swap(_cached_size_, other->_cached_size_);
}
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h
index e3b8990..a4fcbd3 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.h
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.h
@@ -1418,6 +1418,13 @@
inline const ::android::gltrace::GLMessage_FrameBuffer& fb() const;
inline ::android::gltrace::GLMessage_FrameBuffer* mutable_fb();
+ // optional int32 threadtime = 8;
+ inline bool has_threadtime() const;
+ inline void clear_threadtime();
+ static const int kThreadtimeFieldNumber = 8;
+ inline ::google::protobuf::int32 threadtime() const;
+ inline void set_threadtime(::google::protobuf::int32 value);
+
// @@protoc_insertion_point(class_scope:android.gltrace.GLMessage)
private:
mutable int _cached_size_;
@@ -1429,11 +1436,12 @@
::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType > args_;
::android::gltrace::GLMessage_DataType* returnvalue_;
::android::gltrace::GLMessage_FrameBuffer* fb_;
+ ::google::protobuf::int32 threadtime_;
friend void protobuf_AddDesc_gltrace_2eproto();
friend void protobuf_AssignDesc_gltrace_2eproto();
friend void protobuf_ShutdownFile_gltrace_2eproto();
- ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
+ ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
inline bool _has_bit(int index) const {
@@ -1860,6 +1868,22 @@
return fb_;
}
+// optional int32 threadtime = 8;
+inline bool GLMessage::has_threadtime() const {
+ return _has_bit(7);
+}
+inline void GLMessage::clear_threadtime() {
+ threadtime_ = 0;
+ _clear_bit(7);
+}
+inline ::google::protobuf::int32 GLMessage::threadtime() const {
+ return threadtime_;
+}
+inline void GLMessage::set_threadtime(::google::protobuf::int32 value) {
+ _set_bit(7);
+ threadtime_ = value;
+}
+
// @@protoc_insertion_point(namespace_scope)
diff --git a/opengl/libs/GLES_trace/src/gltrace_api.cpp b/opengl/libs/GLES_trace/src/gltrace_api.cpp
index a2366ac..358bf54 100644
--- a/opengl/libs/GLES_trace/src/gltrace_api.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_api.cpp
@@ -43,11 +43,15 @@
arg_texture->add_intvalue((int)texture);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glActiveTexture(texture);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -70,11 +74,15 @@
arg_shader->add_intvalue(shader);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glAttachShader(program, shader);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -103,11 +111,15 @@
arg_name->add_intvalue((int)name);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindAttribLocation(program, index, name);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -130,11 +142,15 @@
arg_buffer->add_intvalue(buffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindBuffer(target, buffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -157,11 +173,15 @@
arg_framebuffer->add_intvalue(framebuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindFramebuffer(target, framebuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -184,11 +204,15 @@
arg_renderbuffer->add_intvalue(renderbuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindRenderbuffer(target, renderbuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -211,11 +235,15 @@
arg_texture->add_intvalue(texture);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindTexture(target, texture);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -250,11 +278,15 @@
arg_alpha->add_floatvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendColor(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -271,11 +303,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendEquation(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -298,11 +334,15 @@
arg_modeAlpha->add_intvalue((int)modeAlpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendEquationSeparate(modeRGB, modeAlpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -325,11 +365,15 @@
arg_dfactor->add_intvalue((int)dfactor);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendFunc(sfactor, dfactor);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -364,11 +408,15 @@
arg_dstAlpha->add_intvalue((int)dstAlpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -403,11 +451,15 @@
arg_usage->add_intvalue((int)usage);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBufferData(target, size, data, usage);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -442,11 +494,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBufferSubData(target, offset, size, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -463,9 +519,11 @@
arg_target->add_intvalue((int)target);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLenum retValue = glContext->hooks->gl.glCheckFramebufferStatus(target);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -473,7 +531,9 @@
rt->set_type(GLMessage::DataType::ENUM);
rt->add_intvalue((int)retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -492,11 +552,15 @@
arg_mask->add_intvalue(mask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClear(mask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -531,11 +595,15 @@
arg_alpha->add_floatvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearColor(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -552,11 +620,15 @@
arg_depth->add_floatvalue(depth);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearDepthf(depth);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -573,11 +645,15 @@
arg_s->add_intvalue(s);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearStencil(s);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -612,11 +688,15 @@
arg_alpha->add_boolvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glColorMask(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -633,11 +713,15 @@
arg_shader->add_intvalue(shader);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCompileShader(shader);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -696,11 +780,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -765,11 +853,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -828,11 +920,15 @@
arg_border->add_intvalue(border);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -891,11 +987,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -906,9 +1006,11 @@
glmsg.set_function(GLMessage::glCreateProgram);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLuint retValue = glContext->hooks->gl.glCreateProgram();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -916,7 +1018,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -935,9 +1039,11 @@
arg_type->add_intvalue((int)type);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLuint retValue = glContext->hooks->gl.glCreateShader(type);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -945,7 +1051,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -964,11 +1072,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCullFace(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -991,11 +1103,15 @@
arg_buffers->add_intvalue((int)buffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteBuffers(n, buffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1018,11 +1134,15 @@
arg_framebuffers->add_intvalue((int)framebuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteFramebuffers(n, framebuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1039,11 +1159,15 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteProgram(program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1066,11 +1190,15 @@
arg_renderbuffers->add_intvalue((int)renderbuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteRenderbuffers(n, renderbuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1087,11 +1215,15 @@
arg_shader->add_intvalue(shader);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteShader(shader);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1114,11 +1246,15 @@
arg_textures->add_intvalue((int)textures);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteTextures(n, textures);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1135,11 +1271,15 @@
arg_func->add_intvalue((int)func);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDepthFunc(func);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1156,11 +1296,15 @@
arg_flag->add_boolvalue(flag);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDepthMask(flag);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1183,11 +1327,15 @@
arg_zFar->add_floatvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDepthRangef(zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1210,11 +1358,15 @@
arg_shader->add_intvalue(shader);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDetachShader(program, shader);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1231,11 +1383,15 @@
arg_cap->add_intvalue((int)cap);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDisable(cap);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1252,11 +1408,15 @@
arg_index->add_intvalue(index);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDisableVertexAttribArray(index);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1285,11 +1445,15 @@
arg_count->add_intvalue(count);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawArrays(mode, first, count);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1324,11 +1488,15 @@
arg_indices->add_intvalue((int)indices);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawElements(mode, count, type, indices);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1345,11 +1513,15 @@
arg_cap->add_intvalue((int)cap);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEnable(cap);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1366,11 +1538,15 @@
arg_index->add_intvalue(index);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEnableVertexAttribArray(index);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1381,11 +1557,15 @@
glmsg.set_function(GLMessage::glFinish);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFinish();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1396,11 +1576,15 @@
glmsg.set_function(GLMessage::glFlush);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFlush();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1435,11 +1619,15 @@
arg_renderbuffer->add_intvalue(renderbuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1480,11 +1668,15 @@
arg_level->add_intvalue(level);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferTexture2D(target, attachment, textarget, texture, level);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1501,11 +1693,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFrontFace(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1528,11 +1724,15 @@
arg_buffers->add_intvalue((int)buffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenBuffers(n, buffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1549,11 +1749,15 @@
arg_target->add_intvalue((int)target);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenerateMipmap(target);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1576,11 +1780,15 @@
arg_framebuffers->add_intvalue((int)framebuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenFramebuffers(n, framebuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1603,11 +1811,15 @@
arg_renderbuffers->add_intvalue((int)renderbuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenRenderbuffers(n, renderbuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1630,11 +1842,15 @@
arg_textures->add_intvalue((int)textures);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenTextures(n, textures);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1687,11 +1903,15 @@
arg_name->add_intvalue((int)name);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetActiveAttrib(program, index, bufsize, length, size, type, name);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1744,11 +1964,15 @@
arg_name->add_intvalue((int)name);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetActiveUniform(program, index, bufsize, length, size, type, name);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1783,11 +2007,15 @@
arg_shaders->add_intvalue((int)shaders);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetAttachedShaders(program, maxcount, count, shaders);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1810,9 +2038,11 @@
arg_name->add_intvalue((int)name);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
int retValue = glContext->hooks->gl.glGetAttribLocation(program, name);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -1820,7 +2050,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -1845,11 +2077,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetBooleanv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1878,11 +2114,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetBufferParameteriv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1893,9 +2133,11 @@
glmsg.set_function(GLMessage::glGetError);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLenum retValue = glContext->hooks->gl.glGetError();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -1903,7 +2145,9 @@
rt->set_type(GLMessage::DataType::ENUM);
rt->add_intvalue((int)retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -1928,11 +2172,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetFloatv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1967,11 +2215,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -1994,11 +2246,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetIntegerv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2027,11 +2283,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetProgramiv(program, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2066,11 +2326,15 @@
arg_infolog->add_intvalue((int)infolog);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetProgramInfoLog(program, bufsize, length, infolog);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2099,11 +2363,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetRenderbufferParameteriv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2132,11 +2400,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetShaderiv(shader, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2171,11 +2443,15 @@
arg_infolog->add_intvalue((int)infolog);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetShaderInfoLog(shader, bufsize, length, infolog);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2210,11 +2486,15 @@
arg_precision->add_intvalue((int)precision);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2249,11 +2529,15 @@
arg_source->add_intvalue((int)source);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetShaderSource(shader, bufsize, length, source);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2270,9 +2554,11 @@
arg_name->add_intvalue((int)name);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
const GLubyte* retValue = glContext->hooks->gl.glGetString(name);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2280,7 +2566,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue((int)retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2311,11 +2599,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexParameterfv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2344,11 +2636,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexParameteriv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2377,11 +2673,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetUniformfv(program, location, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2410,11 +2710,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetUniformiv(program, location, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2437,9 +2741,11 @@
arg_name->add_intvalue((int)name);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
int retValue = glContext->hooks->gl.glGetUniformLocation(program, name);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2447,7 +2753,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2478,11 +2786,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetVertexAttribfv(index, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2511,11 +2823,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetVertexAttribiv(index, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2544,11 +2860,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetVertexAttribPointerv(index, pname, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2571,11 +2891,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glHint(target, mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2592,9 +2916,11 @@
arg_buffer->add_intvalue(buffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsBuffer(buffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2602,7 +2928,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2621,9 +2949,11 @@
arg_cap->add_intvalue((int)cap);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsEnabled(cap);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2631,7 +2961,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2650,9 +2982,11 @@
arg_framebuffer->add_intvalue(framebuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsFramebuffer(framebuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2660,7 +2994,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2679,9 +3015,11 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsProgram(program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2689,7 +3027,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2708,9 +3048,11 @@
arg_renderbuffer->add_intvalue(renderbuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsRenderbuffer(renderbuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2718,7 +3060,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2737,9 +3081,11 @@
arg_shader->add_intvalue(shader);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsShader(shader);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2747,7 +3093,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2766,9 +3114,11 @@
arg_texture->add_intvalue(texture);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsTexture(texture);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2776,7 +3126,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -2795,11 +3147,15 @@
arg_width->add_floatvalue(width);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLineWidth(width);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2816,11 +3172,15 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLinkProgram(program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2843,11 +3203,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPixelStorei(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2870,11 +3234,15 @@
arg_units->add_floatvalue(units);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPolygonOffset(factor, units);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2927,11 +3295,15 @@
arg_pixels->add_intvalue((int)pixels);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2942,11 +3314,15 @@
glmsg.set_function(GLMessage::glReleaseShaderCompiler);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glReleaseShaderCompiler();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -2981,11 +3357,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRenderbufferStorage(target, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3008,11 +3388,15 @@
arg_invert->add_boolvalue(invert);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glSampleCoverage(value, invert);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3047,11 +3431,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glScissor(x, y, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3092,11 +3480,15 @@
arg_length->add_intvalue(length);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glShaderBinary(n, shaders, binaryformat, binary, length);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3131,11 +3523,15 @@
arg_length->add_intvalue((int)length);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glShaderSource(shader, count, string, length);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3164,11 +3560,15 @@
arg_mask->add_intvalue(mask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStencilFunc(func, ref, mask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3203,11 +3603,15 @@
arg_mask->add_intvalue(mask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStencilFuncSeparate(face, func, ref, mask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3224,11 +3628,15 @@
arg_mask->add_intvalue(mask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStencilMask(mask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3251,11 +3659,15 @@
arg_mask->add_intvalue(mask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStencilMaskSeparate(face, mask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3284,11 +3696,15 @@
arg_zpass->add_intvalue((int)zpass);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStencilOp(fail, zfail, zpass);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3323,11 +3739,15 @@
arg_zpass->add_intvalue((int)zpass);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStencilOpSeparate(face, fail, zfail, zpass);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3392,11 +3812,15 @@
arg_pixels->add_intvalue((int)pixels);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3425,11 +3849,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameterf(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3458,11 +3886,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameterfv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3491,11 +3923,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameteri(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3524,11 +3960,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameteriv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3593,11 +4033,15 @@
arg_pixels->add_intvalue((int)pixels);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3620,11 +4064,15 @@
arg_x->add_floatvalue(x);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform1f(location, x);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3653,11 +4101,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform1fv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3680,11 +4132,15 @@
arg_x->add_intvalue(x);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform1i(location, x);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3713,11 +4169,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform1iv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3746,11 +4206,15 @@
arg_y->add_floatvalue(y);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform2f(location, x, y);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3779,11 +4243,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform2fv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3812,11 +4280,15 @@
arg_y->add_intvalue(y);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform2i(location, x, y);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3845,11 +4317,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform2iv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3884,11 +4360,15 @@
arg_z->add_floatvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform3f(location, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3917,11 +4397,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform3fv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3956,11 +4440,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform3i(location, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -3989,11 +4477,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform3iv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4034,11 +4526,15 @@
arg_w->add_floatvalue(w);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform4f(location, x, y, z, w);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4067,11 +4563,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform4fv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4112,11 +4612,15 @@
arg_w->add_intvalue(w);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform4i(location, x, y, z, w);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4145,11 +4649,15 @@
arg_v->add_intvalue((int)v);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniform4iv(location, count, v);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4184,11 +4692,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniformMatrix2fv(location, count, transpose, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4223,11 +4735,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniformMatrix3fv(location, count, transpose, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4262,11 +4778,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUniformMatrix4fv(location, count, transpose, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4283,11 +4803,15 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUseProgram(program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4304,11 +4828,15 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glValidateProgram(program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4331,11 +4859,15 @@
arg_x->add_floatvalue(x);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib1f(indx, x);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4358,11 +4890,15 @@
arg_values->add_intvalue((int)values);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib1fv(indx, values);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4391,11 +4927,15 @@
arg_y->add_floatvalue(y);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib2f(indx, x, y);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4418,11 +4958,15 @@
arg_values->add_intvalue((int)values);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib2fv(indx, values);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4457,11 +5001,15 @@
arg_z->add_floatvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib3f(indx, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4484,11 +5032,15 @@
arg_values->add_intvalue((int)values);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib3fv(indx, values);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4529,11 +5081,15 @@
arg_w->add_floatvalue(w);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib4f(indx, x, y, z, w);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4556,11 +5112,15 @@
arg_values->add_intvalue((int)values);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttrib4fv(indx, values);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4607,11 +5167,15 @@
arg_ptr->add_intvalue((int)ptr);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4646,11 +5210,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glViewport(x, y, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4676,11 +5244,15 @@
arg_image->add_intvalue((int)image);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEGLImageTargetTexture2DOES(target, image);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4703,11 +5275,15 @@
arg_image->add_intvalue((int)image);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEGLImageTargetRenderbufferStorageOES(target, image);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4748,11 +5324,15 @@
arg_binary->add_intvalue((int)binary);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4787,11 +5367,15 @@
arg_length->add_intvalue(length);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramBinaryOES(program, binaryFormat, binary, length);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4814,9 +5398,11 @@
arg_access->add_intvalue((int)access);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
void* retValue = glContext->hooks->gl.glMapBufferOES(target, access);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -4824,7 +5410,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue((int)retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -4843,9 +5431,11 @@
arg_target->add_intvalue((int)target);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glUnmapBufferOES(target);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -4853,7 +5443,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -4884,11 +5476,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetBufferPointervOES(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -4959,11 +5555,15 @@
arg_pixels->add_intvalue((int)pixels);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexImage3DOES(target, level, internalformat, width, height, depth, border, format, type, pixels);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5040,11 +5640,15 @@
arg_pixels->add_intvalue((int)pixels);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5109,11 +5713,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCopyTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, x, y, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5178,11 +5786,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCompressedTexImage3DOES(target, level, internalformat, width, height, depth, border, imageSize, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5259,11 +5871,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCompressedTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5310,11 +5926,15 @@
arg_zoffset->add_intvalue(zoffset);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferTexture3DOES(target, attachment, textarget, texture, level, zoffset);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5331,11 +5951,15 @@
arg_array->add_intvalue(array);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindVertexArrayOES(array);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5358,11 +5982,15 @@
arg_arrays->add_intvalue((int)arrays);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteVertexArraysOES(n, arrays);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5385,11 +6013,15 @@
arg_arrays->add_intvalue((int)arrays);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenVertexArraysOES(n, arrays);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5406,9 +6038,11 @@
arg_array->add_intvalue(array);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsVertexArrayOES(array);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -5416,7 +6050,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -5447,11 +6083,15 @@
arg_groups->add_intvalue((int)groups);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPerfMonitorGroupsAMD(numGroups, groupsSize, groups);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5492,11 +6132,15 @@
arg_counters->add_intvalue((int)counters);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPerfMonitorCountersAMD(group, numCounters, maxActiveCounters, counterSize, counters);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5531,11 +6175,15 @@
arg_groupString->add_intvalue((int)groupString);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPerfMonitorGroupStringAMD(group, bufSize, length, groupString);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5576,11 +6224,15 @@
arg_counterString->add_intvalue((int)counterString);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPerfMonitorCounterStringAMD(group, counter, bufSize, length, counterString);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5615,11 +6267,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPerfMonitorCounterInfoAMD(group, counter, pname, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5642,11 +6298,15 @@
arg_monitors->add_intvalue((int)monitors);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenPerfMonitorsAMD(n, monitors);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5669,11 +6329,15 @@
arg_monitors->add_intvalue((int)monitors);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeletePerfMonitorsAMD(n, monitors);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5714,11 +6378,15 @@
arg_countersList->add_intvalue((int)countersList);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glSelectPerfMonitorCountersAMD(monitor, enable, group, numCounters, countersList);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5735,11 +6403,15 @@
arg_monitor->add_intvalue(monitor);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBeginPerfMonitorAMD(monitor);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5756,11 +6428,15 @@
arg_monitor->add_intvalue(monitor);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEndPerfMonitorAMD(monitor);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5801,11 +6477,15 @@
arg_bytesWritten->add_intvalue((int)bytesWritten);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPerfMonitorCounterDataAMD(monitor, pname, dataSize, data, bytesWritten);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5876,11 +6556,15 @@
arg_filter->add_intvalue((int)filter);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5921,11 +6605,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5966,11 +6654,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRenderbufferStorageMultisampleAPPLE(target, samples, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -5981,11 +6673,15 @@
glmsg.set_function(GLMessage::glResolveMultisampleFramebufferAPPLE);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glResolveMultisampleFramebufferAPPLE();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6020,11 +6716,15 @@
arg_label->add_intvalue((int)label);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLabelObjectEXT(type, object, length, label);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6065,11 +6765,15 @@
arg_label->add_intvalue((int)label);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetObjectLabelEXT(type, object, bufSize, length, label);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6092,11 +6796,15 @@
arg_marker->add_intvalue((int)marker);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glInsertEventMarkerEXT(length, marker);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6119,11 +6827,15 @@
arg_marker->add_intvalue((int)marker);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPushGroupMarkerEXT(length, marker);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6134,11 +6846,15 @@
glmsg.set_function(GLMessage::glPopGroupMarkerEXT);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPopGroupMarkerEXT();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6167,11 +6883,15 @@
arg_attachments->add_intvalue((int)attachments);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDiscardFramebufferEXT(target, numAttachments, attachments);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6212,11 +6932,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6263,11 +6987,15 @@
arg_samples->add_intvalue(samples);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6302,11 +7030,15 @@
arg_primcount->add_intvalue(primcount);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultiDrawArraysEXT(mode, first, count, primcount);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6347,11 +7079,15 @@
arg_primcount->add_intvalue(primcount);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultiDrawElementsEXT(mode, count, type, indices, primcount);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6374,11 +7110,15 @@
arg_ids->add_intvalue((int)ids);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenQueriesEXT(n, ids);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6401,11 +7141,15 @@
arg_ids->add_intvalue((int)ids);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteQueriesEXT(n, ids);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6422,9 +7166,11 @@
arg_id->add_intvalue(id);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsQueryEXT(id);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6432,7 +7178,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -6457,11 +7205,15 @@
arg_id->add_intvalue(id);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBeginQueryEXT(target, id);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6478,11 +7230,15 @@
arg_target->add_intvalue((int)target);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEndQueryEXT(target);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6511,11 +7267,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetQueryivEXT(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6544,11 +7304,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetQueryObjectuivEXT(id, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6559,9 +7323,11 @@
glmsg.set_function(GLMessage::glGetGraphicsResetStatusEXT);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLenum retValue = glContext->hooks->gl.glGetGraphicsResetStatusEXT();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6569,7 +7335,9 @@
rt->set_type(GLMessage::DataType::ENUM);
rt->add_intvalue((int)retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -6630,11 +7398,15 @@
arg_data->add_intvalue((int)data);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6669,11 +7441,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetnUniformfvEXT(program, location, bufSize, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6708,11 +7484,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetnUniformivEXT(program, location, bufSize, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6741,11 +7521,15 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glUseProgramStagesEXT(pipeline, stages, program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6768,11 +7552,15 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glActiveShaderProgramEXT(pipeline, program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6801,9 +7589,11 @@
arg_strings->add_intvalue((int)strings);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLuint retValue = glContext->hooks->gl.glCreateShaderProgramvEXT(type, count, strings);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6811,7 +7601,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -6830,11 +7622,15 @@
arg_pipeline->add_intvalue(pipeline);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindProgramPipelineEXT(pipeline);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6857,11 +7653,15 @@
arg_pipelines->add_intvalue((int)pipelines);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteProgramPipelinesEXT(n, pipelines);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6884,11 +7684,15 @@
arg_pipelines->add_intvalue((int)pipelines);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenProgramPipelinesEXT(n, pipelines);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6905,9 +7709,11 @@
arg_pipeline->add_intvalue(pipeline);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsProgramPipelineEXT(pipeline);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6915,7 +7721,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -6946,11 +7754,15 @@
arg_value->add_intvalue(value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramParameteriEXT(program, pname, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -6979,11 +7791,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetProgramPipelineivEXT(pipeline, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7012,11 +7828,15 @@
arg_x->add_intvalue(x);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform1iEXT(program, location, x);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7051,11 +7871,15 @@
arg_y->add_intvalue(y);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform2iEXT(program, location, x, y);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7096,11 +7920,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform3iEXT(program, location, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7147,11 +7975,15 @@
arg_w->add_intvalue(w);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform4iEXT(program, location, x, y, z, w);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7180,11 +8012,15 @@
arg_x->add_floatvalue(x);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform1fEXT(program, location, x);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7219,11 +8055,15 @@
arg_y->add_floatvalue(y);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform2fEXT(program, location, x, y);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7264,11 +8104,15 @@
arg_z->add_floatvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform3fEXT(program, location, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7315,11 +8159,15 @@
arg_w->add_floatvalue(w);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform4fEXT(program, location, x, y, z, w);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7354,11 +8202,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform1ivEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7393,11 +8245,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform2ivEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7432,11 +8288,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform3ivEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7471,11 +8331,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform4ivEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7510,11 +8374,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform1fvEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7549,11 +8417,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform2fvEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7588,11 +8460,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform3fvEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7627,11 +8503,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniform4fvEXT(program, location, count, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7672,11 +8552,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniformMatrix2fvEXT(program, location, count, transpose, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7717,11 +8601,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniformMatrix3fvEXT(program, location, count, transpose, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7762,11 +8650,15 @@
arg_value->add_intvalue((int)value);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glProgramUniformMatrix4fvEXT(program, location, count, transpose, value);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7783,11 +8675,15 @@
arg_pipeline->add_intvalue(pipeline);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glValidateProgramPipelineEXT(pipeline);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7822,11 +8718,15 @@
arg_infoLog->add_intvalue((int)infoLog);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetProgramPipelineInfoLogEXT(pipeline, bufSize, length, infoLog);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7861,11 +8761,15 @@
arg_width->add_intvalue(width);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexStorage1DEXT(target, levels, internalformat, width);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7906,11 +8810,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexStorage2DEXT(target, levels, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -7957,11 +8865,15 @@
arg_depth->add_intvalue(depth);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexStorage3DEXT(target, levels, internalformat, width, height, depth);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8002,11 +8914,15 @@
arg_width->add_intvalue(width);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTextureStorage1DEXT(texture, target, levels, internalformat, width);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8053,11 +8969,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTextureStorage2DEXT(texture, target, levels, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8110,11 +9030,15 @@
arg_depth->add_intvalue(depth);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTextureStorage3DEXT(texture, target, levels, internalformat, width, height, depth);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8155,11 +9079,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRenderbufferStorageMultisampleIMG(target, samples, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8206,11 +9134,15 @@
arg_samples->add_intvalue(samples);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferTexture2DMultisampleIMG(target, attachment, textarget, texture, level, samples);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8227,11 +9159,15 @@
arg_mask->add_boolvalue(mask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCoverageMaskNV(mask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8248,11 +9184,15 @@
arg_operation->add_intvalue((int)operation);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCoverageOperationNV(operation);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8275,11 +9215,15 @@
arg_bufs->add_intvalue((int)bufs);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawBuffersNV(n, bufs);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8302,11 +9246,15 @@
arg_fences->add_intvalue((int)fences);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteFencesNV(n, fences);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8329,11 +9277,15 @@
arg_fences->add_intvalue((int)fences);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenFencesNV(n, fences);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8350,9 +9302,11 @@
arg_fence->add_intvalue(fence);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsFenceNV(fence);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -8360,7 +9314,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -8379,9 +9335,11 @@
arg_fence->add_intvalue(fence);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glTestFenceNV(fence);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -8389,7 +9347,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -8420,11 +9380,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetFenceivNV(fence, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8441,11 +9405,15 @@
arg_fence->add_intvalue(fence);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFinishFenceNV(fence);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8468,11 +9436,15 @@
arg_condition->add_intvalue((int)condition);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glSetFenceNV(fence, condition);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8489,11 +9461,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glReadBufferNV(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8516,11 +9492,15 @@
arg_ref->add_floatvalue(ref);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glAlphaFuncQCOM(func, ref);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8549,11 +9529,15 @@
arg_driverControls->add_intvalue((int)driverControls);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetDriverControlsQCOM(num, size, driverControls);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8588,11 +9572,15 @@
arg_driverControlString->add_intvalue((int)driverControlString);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetDriverControlStringQCOM(driverControl, bufSize, length, driverControlString);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8609,11 +9597,15 @@
arg_driverControl->add_intvalue(driverControl);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEnableDriverControlQCOM(driverControl);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8630,11 +9622,15 @@
arg_driverControl->add_intvalue(driverControl);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDisableDriverControlQCOM(driverControl);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8663,11 +9659,15 @@
arg_numTextures->add_intvalue((int)numTextures);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetTexturesQCOM(textures, maxTextures, numTextures);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8696,11 +9696,15 @@
arg_numBuffers->add_intvalue((int)numBuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetBuffersQCOM(buffers, maxBuffers, numBuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8729,11 +9733,15 @@
arg_numRenderbuffers->add_intvalue((int)numRenderbuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetRenderbuffersQCOM(renderbuffers, maxRenderbuffers, numRenderbuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8762,11 +9770,15 @@
arg_numFramebuffers->add_intvalue((int)numFramebuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetFramebuffersQCOM(framebuffers, maxFramebuffers, numFramebuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8807,11 +9819,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetTexLevelParameterivQCOM(texture, face, level, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8840,11 +9856,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtTexObjectStateOverrideiQCOM(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8921,11 +9941,15 @@
arg_texels->add_intvalue((int)texels);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetTexSubImageQCOM(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8948,11 +9972,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetBufferPointervQCOM(target, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -8981,11 +10009,15 @@
arg_numShaders->add_intvalue((int)numShaders);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetShadersQCOM(shaders, maxShaders, numShaders);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9014,11 +10046,15 @@
arg_numPrograms->add_intvalue((int)numPrograms);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetProgramsQCOM(programs, maxPrograms, numPrograms);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9035,9 +10071,11 @@
arg_program->add_intvalue(program);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glExtIsProgramBinaryQCOM(program);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -9045,7 +10083,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -9082,11 +10122,15 @@
arg_length->add_intvalue((int)length);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glExtGetProgramBinarySourceQCOM(program, shadertype, source, length);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9127,11 +10171,15 @@
arg_preserveMask->add_intvalue(preserveMask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glStartTilingQCOM(x, y, width, height, preserveMask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9148,11 +10196,15 @@
arg_preserveMask->add_intvalue(preserveMask);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEndTilingQCOM(preserveMask);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9178,11 +10230,15 @@
arg_ref->add_floatvalue(ref);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glAlphaFunc(func, ref);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9205,11 +10261,15 @@
arg_equation->add_intvalue((int)equation);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClipPlanef(plane, equation);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9244,11 +10304,15 @@
arg_alpha->add_floatvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glColor4f(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9271,11 +10335,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFogf(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9298,11 +10366,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFogfv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9349,11 +10421,15 @@
arg_zFar->add_floatvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFrustumf(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9376,11 +10452,15 @@
arg_eqn->add_intvalue((int)eqn);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetClipPlanef(pname, eqn);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9409,11 +10489,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetLightfv(light, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9442,11 +10526,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetMaterialfv(face, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9475,11 +10563,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexEnvfv(env, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9502,11 +10594,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightModelf(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9529,11 +10625,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightModelfv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9562,11 +10662,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightf(light, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9595,11 +10699,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightfv(light, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9616,11 +10724,15 @@
arg_m->add_intvalue((int)m);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLoadMatrixf(m);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9649,11 +10761,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMaterialf(face, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9682,11 +10798,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMaterialfv(face, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9703,11 +10823,15 @@
arg_m->add_intvalue((int)m);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultMatrixf(m);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9748,11 +10872,15 @@
arg_q->add_floatvalue(q);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultiTexCoord4f(target, s, t, r, q);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9781,11 +10909,15 @@
arg_nz->add_floatvalue(nz);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glNormal3f(nx, ny, nz);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9832,11 +10964,15 @@
arg_zFar->add_floatvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glOrthof(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9859,11 +10995,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointParameterf(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9886,11 +11026,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointParameterfv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9907,11 +11051,15 @@
arg_size->add_floatvalue(size);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointSize(size);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9946,11 +11094,15 @@
arg_z->add_floatvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRotatef(angle, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -9979,11 +11131,15 @@
arg_z->add_floatvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glScalef(x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10012,11 +11168,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvf(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10045,11 +11205,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvfv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10078,11 +11242,15 @@
arg_z->add_floatvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTranslatef(x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10105,11 +11273,15 @@
arg_ref->add_intvalue(ref);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glAlphaFuncx(func, ref);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10144,11 +11316,15 @@
arg_alpha->add_intvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearColorx(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10165,11 +11341,15 @@
arg_depth->add_intvalue(depth);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearDepthx(depth);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10186,11 +11366,15 @@
arg_texture->add_intvalue((int)texture);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClientActiveTexture(texture);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10213,11 +11397,15 @@
arg_equation->add_intvalue((int)equation);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClipPlanex(plane, equation);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10252,11 +11440,15 @@
arg_alpha->add_intvalue((int)alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glColor4ub(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10291,11 +11483,15 @@
arg_alpha->add_intvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glColor4x(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10330,11 +11526,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glColorPointer(size, type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10357,11 +11557,15 @@
arg_zFar->add_intvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDepthRangex(zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10378,11 +11582,15 @@
arg_array->add_intvalue((int)array);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDisableClientState(array);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10399,11 +11607,15 @@
arg_array->add_intvalue((int)array);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glEnableClientState(array);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10426,11 +11638,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFogx(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10453,11 +11669,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFogxv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10504,11 +11724,15 @@
arg_zFar->add_intvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFrustumx(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10531,11 +11755,15 @@
arg_eqn->add_intvalue((int)eqn);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetClipPlanex(pname, eqn);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10558,11 +11786,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetFixedv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10591,11 +11823,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetLightxv(light, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10624,11 +11860,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetMaterialxv(face, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10651,11 +11891,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetPointerv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10684,11 +11928,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexEnviv(env, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10717,11 +11965,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexEnvxv(env, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10750,11 +12002,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexParameterxv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10777,11 +12033,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightModelx(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10804,11 +12064,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightModelxv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10837,11 +12101,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightx(light, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10870,11 +12138,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightxv(light, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10891,11 +12163,15 @@
arg_width->add_intvalue(width);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLineWidthx(width);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10906,11 +12182,15 @@
glmsg.set_function(GLMessage::glLoadIdentity);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLoadIdentity();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10927,11 +12207,15 @@
arg_m->add_intvalue((int)m);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLoadMatrixx(m);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10948,11 +12232,15 @@
arg_opcode->add_intvalue((int)opcode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLogicOp(opcode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -10981,11 +12269,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMaterialx(face, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11014,11 +12306,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMaterialxv(face, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11035,11 +12331,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMatrixMode(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11056,11 +12356,15 @@
arg_m->add_intvalue((int)m);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultMatrixx(m);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11101,11 +12405,15 @@
arg_q->add_intvalue(q);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultiTexCoord4x(target, s, t, r, q);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11134,11 +12442,15 @@
arg_nz->add_intvalue(nz);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glNormal3x(nx, ny, nz);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11167,11 +12479,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glNormalPointer(type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11218,11 +12534,15 @@
arg_zFar->add_intvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glOrthox(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11245,11 +12565,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointParameterx(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11272,11 +12596,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointParameterxv(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11293,11 +12621,15 @@
arg_size->add_intvalue(size);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointSizex(size);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11320,11 +12652,15 @@
arg_units->add_intvalue(units);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPolygonOffsetx(factor, units);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11335,11 +12671,15 @@
glmsg.set_function(GLMessage::glPopMatrix);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPopMatrix();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11350,11 +12690,15 @@
glmsg.set_function(GLMessage::glPushMatrix);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPushMatrix();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11389,11 +12733,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRotatex(angle, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11416,11 +12764,15 @@
arg_invert->add_boolvalue(invert);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glSampleCoveragex(value, invert);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11449,11 +12801,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glScalex(x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11470,11 +12826,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glShadeModel(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11509,11 +12869,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexCoordPointer(size, type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11542,11 +12906,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvi(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11575,11 +12943,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvx(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11608,11 +12980,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnviv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11641,11 +13017,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvxv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11674,11 +13054,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameterx(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11707,11 +13091,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameterxv(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11740,11 +13128,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTranslatex(x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11779,11 +13171,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glVertexPointer(size, type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11812,11 +13208,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointSizePointerOES(type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11842,11 +13242,15 @@
arg_modeAlpha->add_intvalue((int)modeAlpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendEquationSeparateOES(modeRGB, modeAlpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11881,11 +13285,15 @@
arg_dstAlpha->add_intvalue((int)dstAlpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendFuncSeparateOES(srcRGB, dstRGB, srcAlpha, dstAlpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11902,11 +13310,15 @@
arg_mode->add_intvalue((int)mode);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBlendEquationOES(mode);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11947,11 +13359,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexsOES(x, y, z, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -11992,11 +13408,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexiOES(x, y, z, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12037,11 +13457,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexxOES(x, y, z, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12058,11 +13482,15 @@
arg_coords->add_intvalue((int)coords);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexsvOES(coords);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12079,11 +13507,15 @@
arg_coords->add_intvalue((int)coords);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexivOES(coords);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12100,11 +13532,15 @@
arg_coords->add_intvalue((int)coords);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexxvOES(coords);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12145,11 +13581,15 @@
arg_height->add_floatvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexfOES(x, y, z, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12166,11 +13606,15 @@
arg_coords->add_intvalue((int)coords);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDrawTexfvOES(coords);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12193,11 +13637,15 @@
arg_ref->add_intvalue(ref);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glAlphaFuncxOES(func, ref);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12232,11 +13680,15 @@
arg_alpha->add_intvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearColorxOES(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12253,11 +13705,15 @@
arg_depth->add_intvalue(depth);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearDepthxOES(depth);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12280,11 +13736,15 @@
arg_equation->add_intvalue((int)equation);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClipPlanexOES(plane, equation);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12319,11 +13779,15 @@
arg_alpha->add_intvalue(alpha);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glColor4xOES(red, green, blue, alpha);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12346,11 +13810,15 @@
arg_zFar->add_intvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDepthRangexOES(zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12373,11 +13841,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFogxOES(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12400,11 +13872,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFogxvOES(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12451,11 +13927,15 @@
arg_zFar->add_intvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFrustumxOES(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12478,11 +13958,15 @@
arg_eqn->add_intvalue((int)eqn);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetClipPlanexOES(pname, eqn);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12505,11 +13989,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetFixedvOES(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12538,11 +14026,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetLightxvOES(light, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12571,11 +14063,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetMaterialxvOES(face, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12604,11 +14100,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexEnvxvOES(env, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12637,11 +14137,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexParameterxvOES(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12664,11 +14168,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightModelxOES(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12691,11 +14199,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightModelxvOES(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12724,11 +14236,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightxOES(light, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12757,11 +14273,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLightxvOES(light, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12778,11 +14298,15 @@
arg_width->add_intvalue(width);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLineWidthxOES(width);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12799,11 +14323,15 @@
arg_m->add_intvalue((int)m);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLoadMatrixxOES(m);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12832,11 +14360,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMaterialxOES(face, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12865,11 +14397,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMaterialxvOES(face, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12886,11 +14422,15 @@
arg_m->add_intvalue((int)m);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultMatrixxOES(m);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12931,11 +14471,15 @@
arg_q->add_intvalue(q);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMultiTexCoord4xOES(target, s, t, r, q);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -12964,11 +14508,15 @@
arg_nz->add_intvalue(nz);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glNormal3xOES(nx, ny, nz);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13015,11 +14563,15 @@
arg_zFar->add_intvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glOrthoxOES(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13042,11 +14594,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointParameterxOES(pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13069,11 +14625,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointParameterxvOES(pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13090,11 +14650,15 @@
arg_size->add_intvalue(size);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPointSizexOES(size);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13117,11 +14681,15 @@
arg_units->add_intvalue(units);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glPolygonOffsetxOES(factor, units);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13156,11 +14724,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRotatexOES(angle, x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13183,11 +14755,15 @@
arg_invert->add_boolvalue(invert);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glSampleCoveragexOES(value, invert);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13216,11 +14792,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glScalexOES(x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13249,11 +14829,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvxOES(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13282,11 +14866,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexEnvxvOES(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13315,11 +14903,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameterxOES(target, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13348,11 +14940,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexParameterxvOES(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13381,11 +14977,15 @@
arg_z->add_intvalue(z);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTranslatexOES(x, y, z);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13402,9 +15002,11 @@
arg_renderbuffer->add_intvalue(renderbuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsRenderbufferOES(renderbuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13412,7 +15014,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -13437,11 +15041,15 @@
arg_renderbuffer->add_intvalue(renderbuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindRenderbufferOES(target, renderbuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13464,11 +15072,15 @@
arg_renderbuffers->add_intvalue((int)renderbuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteRenderbuffersOES(n, renderbuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13491,11 +15103,15 @@
arg_renderbuffers->add_intvalue((int)renderbuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenRenderbuffersOES(n, renderbuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13530,11 +15146,15 @@
arg_height->add_intvalue(height);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glRenderbufferStorageOES(target, internalformat, width, height);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13563,11 +15183,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetRenderbufferParameterivOES(target, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13584,9 +15208,11 @@
arg_framebuffer->add_intvalue(framebuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLboolean retValue = glContext->hooks->gl.glIsFramebufferOES(framebuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13594,7 +15220,9 @@
rt->set_type(GLMessage::DataType::BOOL);
rt->add_boolvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -13619,11 +15247,15 @@
arg_framebuffer->add_intvalue(framebuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glBindFramebufferOES(target, framebuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13646,11 +15278,15 @@
arg_framebuffers->add_intvalue((int)framebuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDeleteFramebuffersOES(n, framebuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13673,11 +15309,15 @@
arg_framebuffers->add_intvalue((int)framebuffers);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenFramebuffersOES(n, framebuffers);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13694,9 +15334,11 @@
arg_target->add_intvalue((int)target);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLenum retValue = glContext->hooks->gl.glCheckFramebufferStatusOES(target);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13704,7 +15346,9 @@
rt->set_type(GLMessage::DataType::ENUM);
rt->add_intvalue((int)retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -13741,11 +15385,15 @@
arg_renderbuffer->add_intvalue(renderbuffer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferRenderbufferOES(target, attachment, renderbuffertarget, renderbuffer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13786,11 +15434,15 @@
arg_level->add_intvalue(level);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFramebufferTexture2DOES(target, attachment, textarget, texture, level);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13825,11 +15477,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetFramebufferAttachmentParameterivOES(target, attachment, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13846,11 +15502,15 @@
arg_target->add_intvalue((int)target);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGenerateMipmapOES(target);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13867,11 +15527,15 @@
arg_matrixpaletteindex->add_intvalue(matrixpaletteindex);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glCurrentPaletteMatrixOES(matrixpaletteindex);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13882,11 +15546,15 @@
glmsg.set_function(GLMessage::glLoadPaletteFromModelViewMatrixOES);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glLoadPaletteFromModelViewMatrixOES();
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13921,11 +15589,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glMatrixIndexPointerOES(size, type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13960,11 +15632,15 @@
arg_pointer->add_intvalue((int)pointer);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glWeightPointerOES(size, type, stride, pointer);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -13987,9 +15663,11 @@
arg_exponent->add_intvalue((int)exponent);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
GLbitfield retValue = glContext->hooks->gl.glQueryMatrixxOES(mantissa, exponent);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
// set return value
GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13997,7 +15675,9 @@
rt->set_type(GLMessage::DataType::INT);
rt->add_intvalue(retValue);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
return retValue;
@@ -14022,11 +15702,15 @@
arg_zFar->add_floatvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glDepthRangefOES(zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14073,11 +15757,15 @@
arg_zFar->add_floatvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glFrustumfOES(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14124,11 +15812,15 @@
arg_zFar->add_floatvalue(zFar);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glOrthofOES(left, right, bottom, top, zNear, zFar);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14151,11 +15843,15 @@
arg_equation->add_intvalue((int)equation);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClipPlanefOES(plane, equation);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14178,11 +15874,15 @@
arg_eqn->add_intvalue((int)eqn);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetClipPlanefOES(pname, eqn);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14199,11 +15899,15 @@
arg_depth->add_floatvalue(depth);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClearDepthfOES(depth);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14232,11 +15936,15 @@
arg_param->add_floatvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexGenfOES(coord, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14265,11 +15973,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexGenfvOES(coord, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14298,11 +16010,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexGeniOES(coord, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14331,11 +16047,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexGenivOES(coord, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14364,11 +16084,15 @@
arg_param->add_intvalue(param);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexGenxOES(coord, pname, param);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14397,11 +16121,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glTexGenxvOES(coord, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14430,11 +16158,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexGenfvOES(coord, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14463,11 +16195,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexGenivOES(coord, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14496,11 +16232,15 @@
arg_params->add_intvalue((int)params);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glGetTexGenxvOES(coord, pname, params);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14523,11 +16263,15 @@
arg_eqn->add_intvalue((int)eqn);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClipPlanefIMG(p, eqn);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
@@ -14550,11 +16294,15 @@
arg_eqn->add_intvalue((int)eqn);
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
glContext->hooks->gl.glClipPlanexIMG(p, eqn);
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
}
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 871b5dc..6c4feb5 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -15,9 +15,13 @@
*/
#include <cutils/log.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#include "gltrace.pb.h"
+#include "gltrace_api.h"
#include "gltrace_context.h"
#include "gltrace_fixup.h"
@@ -198,6 +202,20 @@
arg_strpp->add_charvalue(src);
}
+void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg) {
+ /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
+ GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex);
+ GLint *src = (GLint*)arg_values->intvalue(0);
+
+ arg_values->set_type(GLMessage::DataType::INT);
+ arg_values->set_isarray(true);
+ arg_values->clear_intvalue();
+
+ for (int i = 0; i < nIntegers; i++) {
+ arg_values->add_intvalue(*src++);
+ }
+}
+
void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg) {
GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex);
GLfloat *src = (GLfloat*)arg_values->intvalue(0);
@@ -223,6 +241,10 @@
GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex);
GLint *intp = (GLint *)arg_intarray->intvalue(0);
+ if (intp == NULL) {
+ return;
+ }
+
arg_intarray->set_type(GLMessage::DataType::INT);
arg_intarray->set_isarray(true);
arg_intarray->clear_intvalue();
@@ -232,6 +254,15 @@
}
}
+void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg) {
+ // fixup as if they were ints
+ fixup_GenericIntArray(argIndex, nEnums, glmsg);
+
+ // and then set the data type to be enum
+ GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex);
+ arg_enumarray->set_type(GLMessage::DataType::ENUM);
+}
+
void fixup_glGenGeneric(GLMessage *glmsg) {
/* void glGen*(GLsizei n, GLuint * buffers); */
GLMessage_DataType arg_n = glmsg->args(0);
@@ -270,13 +301,94 @@
arg_params->add_floatvalue(*src);
}
-void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) {
+void fixup_glLinkProgram(GLMessage *glmsg) {
+ /* void glLinkProgram(GLuint program); */
+ GLuint program = glmsg->args(0).intvalue(0);
+
+ /* We don't have to fixup this call, but as soon as a program is linked,
+ we obtain information about all active attributes and uniforms to
+ pass on to the debugger. Note that in order to pass this info to
+ the debugger, all we need to do is call the trace versions of the
+ necessary calls. */
+
+ GLint n, maxNameLength;
+ GLchar *name;
+ GLint size;
+ GLenum type;
+
+ // obtain info regarding active attributes
+ GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
+ GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
+
+ name = (GLchar *) malloc(maxNameLength);
+ for (int i = 0; i < n; i++) {
+ GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name);
+ }
+ free(name);
+
+ // obtain info regarding active uniforms
+ GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
+ GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
+
+ name = (GLchar *) malloc(maxNameLength);
+ for (int i = 0; i < n; i++) {
+ GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name);
+ }
+ free(name);
+}
+
+/** Given a glGetActive[Uniform|Attrib] call, obtain the location
+ * of the variable in the call.
+ */
+int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg) {
+ GLMessage_Function func = glmsg->function();
+ if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) {
+ return -1;
+ }
+
+ int program = glmsg->args(0).intvalue(0);
+ GLchar *name = (GLchar*) glmsg->args(6).intvalue(0);
+
+ if (func == GLMessage::glGetActiveAttrib) {
+ return context->hooks->gl.glGetAttribLocation(program, name);
+ } else {
+ return context->hooks->gl.glGetUniformLocation(program, name);
+ }
+}
+
+void fixup_glGetActiveAttribOrUniform(GLMessage *glmsg, int location) {
+ /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
+ GLsizei* length, GLint* size, GLenum* type, GLchar* name); */
+ /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
+ GLsizei* length, GLint* size, GLenum* type, GLchar* name) */
+
+ fixup_GenericIntArray(3, 1, glmsg); // length
+ fixup_GenericIntArray(4, 1, glmsg); // size
+ fixup_GenericEnumArray(5, 1, glmsg); // type
+ fixup_CStringPtr(6, glmsg); // name
+
+ // The index argument in the glGetActive[Attrib|Uniform] functions
+ // does not correspond to the actual location index as used in
+ // glUniform*() or glVertexAttrib*() to actually upload the data.
+ // In order to make things simpler for the debugger, we also pass
+ // a hidden location argument that stores the actual location.
+ // append the location value to the end of the argument list
+ GLMessage_DataType *arg_location = glmsg->add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+}
+
+void fixupGLMessage(GLTraceContext *context, nsecs_t wallStart, nsecs_t wallEnd,
+ nsecs_t threadStart, nsecs_t threadEnd,
+ GLMessage *glmsg) {
// for all messages, set the current context id
glmsg->set_context_id(context->getId());
// set start time and duration
- glmsg->set_start_time(start);
- glmsg->set_duration((unsigned)(end - start));
+ glmsg->set_start_time(wallStart);
+ glmsg->set_duration((unsigned)(wallEnd - wallStart));
+ glmsg->set_threadtime((unsigned)(threadEnd - threadStart));
// do any custom message dependent processing
switch (glmsg->function()) {
@@ -292,6 +404,19 @@
case GLMessage::glGenTextures: /* void glGenTextures(GLsizei n, GLuint *textures); */
fixup_glGenGeneric(glmsg);
break;
+ case GLMessage::glLinkProgram: /* void glLinkProgram(GLuint program); */
+ fixup_glLinkProgram(glmsg);
+ break;
+ case GLMessage::glGetActiveAttrib:
+ fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg));
+ break;
+ case GLMessage::glGetActiveUniform:
+ fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg));
+ break;
+ case GLMessage::glBindAttribLocation:
+ /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */
+ fixup_CStringPtr(2, glmsg);
+ break;
case GLMessage::glGetAttribLocation:
case GLMessage::glGetUniformLocation:
/* int glGetAttribLocation(GLuint program, const GLchar* name) */
@@ -331,6 +456,38 @@
case GLMessage::glShaderSource:
fixup_glShaderSource(glmsg);
break;
+ case GLMessage::glUniform1iv:
+ /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */
+ fixup_glUniformGenericInteger(2, 1, glmsg);
+ break;
+ case GLMessage::glUniform2iv:
+ /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */
+ fixup_glUniformGenericInteger(2, 2, glmsg);
+ break;
+ case GLMessage::glUniform3iv:
+ /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */
+ fixup_glUniformGenericInteger(2, 3, glmsg);
+ break;
+ case GLMessage::glUniform4iv:
+ /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */
+ fixup_glUniformGenericInteger(2, 4, glmsg);
+ break;
+ case GLMessage::glUniform1fv:
+ /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */
+ fixup_glUniformGeneric(2, 1, glmsg);
+ break;
+ case GLMessage::glUniform2fv:
+ /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */
+ fixup_glUniformGeneric(2, 2, glmsg);
+ break;
+ case GLMessage::glUniform3fv:
+ /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */
+ fixup_glUniformGeneric(2, 3, glmsg);
+ break;
+ case GLMessage::glUniform4fv:
+ /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */
+ fixup_glUniformGeneric(2, 4, glmsg);
+ break;
case GLMessage::glUniformMatrix2fv:
/* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
const GLfloat* value) */
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.h b/opengl/libs/GLES_trace/src/gltrace_fixup.h
index 64f7545..f63b056 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.h
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.h
@@ -25,7 +25,9 @@
namespace android {
namespace gltrace {
-void fixupGLMessage(GLTraceContext *curContext, nsecs_t start, nsecs_t end, GLMessage *message);
+void fixupGLMessage(GLTraceContext *curContext, nsecs_t wallStart, nsecs_t wallEnd,
+ nsecs_t threadStart, nsecs_t threadEnd,
+ GLMessage *message);
void fixup_addFBContents(GLTraceContext *curContext, GLMessage *message, FBBinding fbToRead);
};
diff --git a/opengl/libs/GLES_trace/tools/genapi.py b/opengl/libs/GLES_trace/tools/genapi.py
index 557e407..e1660be 100755
--- a/opengl/libs/GLES_trace/tools/genapi.py
+++ b/opengl/libs/GLES_trace/tools/genapi.py
@@ -162,13 +162,15 @@
<!--(end)-->
// call function
- nsecs_t start_time = systemTime();
+ nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
<!--(if retType != "void")-->
$!retType!$ retValue = glContext->hooks->gl.$!callsite!$;
<!--(else)-->
glContext->hooks->gl.$!callsite!$;
<!--(end)-->
- nsecs_t end_time = systemTime();
+ nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+ nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
<!--(if retType != "void")-->
// set return value
@@ -178,7 +180,9 @@
rt->$!retDataType.getProtobufCall()!$retValue);
<!--(end)-->
- fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ fixupGLMessage(glContext, wallStartTime, wallEndTime,
+ threadStartTime, threadEndTime,
+ &glmsg);
glContext->traceGLMessage(&glmsg);
<!--(if retType != "void")-->
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 8ff51ec..cb0e908 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -30,7 +30,6 @@
// ----------------------------------------------------------------------------
EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
-EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index 9be40cf..4d8334f 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -37,12 +37,6 @@
#printf("%s", $line);
my $prefix = "";
- if ($name eq "glEGLImageTargetTexture2DOES") {
- $prefix = "__";
- }
- if ($name eq "glEGLImageTargetRenderbufferStorageOES") {
- $prefix = "__";
- }
if ($name eq "glGetString") {
$prefix = "__";
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 4ea2c31..3a8e3fc 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -43,6 +43,7 @@
<bool name="assisted_gps_enabled">true</bool>
<!-- 0 == mobile, 1 == wifi. -->
<integer name="def_network_preference">1</integer>
+ <bool name="def_netstats_enabled">true</bool>
<bool name="def_usb_mass_storage_enabled">true</bool>
<bool name="def_wifi_on">false</bool>
<bool name="def_networks_available_notification_on">true</bool>
@@ -70,6 +71,8 @@
<integer name="def_lockscreen_sounds_enabled">1</integer>
<string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
<string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+ <bool name="def_lockscreen_disabled">false</bool>
+ <bool name="def_device_provisioned">false</bool>
<!-- Notifications use ringer volume -->
<bool name="def_notifications_use_ring_volume">true</bool>
@@ -141,4 +144,11 @@
<bool name="def_dtmf_tones_enabled">true</bool>
<!-- Default for UI touch sounds enabled -->
<bool name="def_sound_effects_enabled">true</bool>
+
+ <!-- Development settings -->
+ <bool name="def_stay_on_while_plugged_in">false</bool>
+
+ <!-- Number of retries for connecting to DHCP.
+ Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES -->
+ <integer name="def_max_dhcp_retries">9</integer>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6e9ea52..330a189 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 75;
+ private static final int DATABASE_VERSION = 76;
private Context mContext;
@@ -1006,6 +1006,29 @@
}
upgradeVersion = 75;
}
+ if (upgradeVersion == 75) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ Cursor c = null;
+ try {
+ c = db.query("secure", new String[] {"_id", "value"},
+ "name='lockscreen.disabled'",
+ null, null, null, null);
+ // only set default if it has not yet been set
+ if (c == null || c.getCount() == 0) {
+ stmt = db.compileStatement("INSERT INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Settings.System.LOCKSCREEN_DISABLED,
+ R.bool.def_lockscreen_disabled);
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (c != null) c.close();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 76;
+ }
// *** Remember to update DATABASE_VERSION above!
@@ -1352,7 +1375,9 @@
loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
R.bool.def_dim_screen);
loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
- "1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
+ ("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
+ mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in))
+ ? 1 : 0);
loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
R.integer.def_screen_off_timeout);
@@ -1568,6 +1593,18 @@
loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
R.string.def_accessibility_screen_reader_url);
+
+ loadBooleanSetting(stmt, Settings.System.LOCKSCREEN_DISABLED,
+ R.bool.def_lockscreen_disabled);
+
+ loadBooleanSetting(stmt, Settings.Secure.DEVICE_PROVISIONED,
+ R.bool.def_device_provisioned);
+
+ loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED,
+ R.bool.def_netstats_enabled);
+
+ loadIntegerSetting(stmt, Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
+ R.integer.def_max_dhcp_retries);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 2d76455..aa27861 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -58,6 +58,7 @@
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:scaleType="centerInside"
android:adjustViewBounds="true"
+ android:visibility="invisible"
/>
<TextView android:id="@+id/app_label"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index b653fcd..bc389f9 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -81,6 +81,7 @@
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:scaleType="centerInside"
android:adjustViewBounds="true"
+ android:visibility="invisible"
/>
<TextView android:id="@+id/app_description"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index cb26db00..333fcda 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -65,6 +65,7 @@
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:scaleType="centerInside"
android:adjustViewBounds="true"
+ android:visibility="invisible"
/>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 14ce266..cd8bd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -236,6 +236,10 @@
public void onAnimationEnd(Animator animation) {
mCallback.onChildDismissed(view);
animView.setLayerType(View.LAYER_TYPE_NONE, null);
+ // Restore the alpha/translation parameters to what they were before swiping
+ // (for when these items are recycled)
+ animView.setAlpha(1f);
+ setTranslation(animView, 0f);
}
});
anim.addUpdateListener(new AnimatorUpdateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index ad38a11..dc2f0be 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -134,6 +134,9 @@
void jumpTo(boolean appearing) {
mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
+ if (mScrimView.getBackground() != null) {
+ mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
+ }
}
public void setPanelHeight(int h) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 4145fc4..92f4ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -16,12 +16,6 @@
package com.android.systemui.recent;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -36,15 +30,17 @@
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Process;
-import android.os.SystemClock;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.LruCache;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
public class RecentTasksLoader {
static final String TAG = "RecentTasksLoader";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -55,11 +51,14 @@
private Context mContext;
private RecentsPanelView mRecentsPanel;
- private AsyncTask<Void, Integer, Void> mThumbnailLoader;
+ private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
+ private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
private final Handler mHandler;
private int mIconDpi;
private Bitmap mDefaultThumbnailBackground;
+ private Bitmap mDefaultIconBackground;
+ private int mNumTasksInFirstScreenful;
public RecentTasksLoader(Context context) {
mContext = context;
@@ -76,12 +75,20 @@
mIconDpi = res.getDisplayMetrics().densityDpi;
}
+ // Render default icon (just a blank image)
+ int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
+ int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
+ mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+
// Render the default thumbnail background
- int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+ int thumbnailWidth =
+ (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+ int thumbnailHeight =
+ (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
- mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mDefaultThumbnailBackground =
+ Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
@@ -95,12 +102,17 @@
public void setRecentsPanel(RecentsPanelView recentsPanel) {
mRecentsPanel = recentsPanel;
+ mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
}
public Bitmap getDefaultThumbnail() {
return mDefaultThumbnailBackground;
}
+ public Bitmap getDefaultIcon() {
+ return mDefaultIconBackground;
+ }
+
// Create an TaskDescription, returning null if the title or icon is null, or if it's the
// home activity
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
@@ -114,6 +126,12 @@
homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
}
+ // Don't load the current home activity.
+ if (homeInfo != null
+ && homeInfo.packageName.equals(intent.getComponent().getPackageName())
+ && homeInfo.name.equals(intent.getComponent().getClassName())) {
+ return null;
+ }
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -121,9 +139,8 @@
if (resolveInfo != null) {
final ActivityInfo info = resolveInfo.activityInfo;
final String title = info.loadLabel(pm).toString();
- Drawable icon = getFullResIcon(resolveInfo, pm);
- if (title != null && title.length() > 0 && icon != null) {
+ if (title != null && title.length() > 0) {
if (DEBUG) Log.v(TAG, "creating activity desc for id="
+ persistentTaskId + ", label=" + title);
@@ -131,14 +148,6 @@
persistentTaskId, resolveInfo, baseIntent, info.packageName,
description);
item.setLabel(title);
- item.setIcon(icon);
-
- // Don't load the current home activity.
- if (homeInfo != null
- && homeInfo.packageName.equals(intent.getComponent().getPackageName())
- && homeInfo.name.equals(intent.getComponent().getClassName())) {
- return null;
- }
return item;
} else {
@@ -148,10 +157,12 @@
return null;
}
- void loadThumbnail(TaskDescription td) {
+ void loadThumbnailAndIcon(TaskDescription td) {
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ final PackageManager pm = mContext.getPackageManager();
ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId);
+ Drawable icon = getFullResIcon(td.resolveInfo, pm);
if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
+ td + ": " + thumbs.mainThumbnail);
@@ -161,6 +172,10 @@
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
+ if (icon != null) {
+ td.setIcon(icon);
+ }
+ td.setLoaded(true);
}
}
@@ -194,111 +209,149 @@
return getFullResDefaultActivityIcon();
}
- public void cancelLoadingThumbnails() {
+ public void cancelLoadingThumbnailsAndIcons() {
+ if (mTaskLoader != null) {
+ mTaskLoader.cancel(false);
+ mTaskLoader = null;
+ }
if (mThumbnailLoader != null) {
mThumbnailLoader.cancel(false);
mThumbnailLoader = null;
}
}
- // return a snapshot of the current list of recent apps
- ArrayList<TaskDescription> getRecentTasks() {
- cancelLoadingThumbnails();
-
- ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
- final PackageManager pm = mContext.getPackageManager();
- final ActivityManager am = (ActivityManager)
+ public void loadTasksInBackground() {
+ // cancel all previous loading of tasks and thumbnails
+ cancelLoadingThumbnailsAndIcons();
+ final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
+ new LinkedBlockingQueue<TaskDescription>();
+ final ArrayList<TaskDescription> taskDescriptionsWaitingToLoad =
+ new ArrayList<TaskDescription>();
+ mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
+ @Override
+ protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
+ if (!isCancelled()) {
+ ArrayList<TaskDescription> newTasks = values[0];
+ // do a callback to RecentsPanelView to let it know we have more values
+ // how do we let it know we're all done? just always call back twice
+ mRecentsPanel.onTasksLoaded(newTasks);
+ }
+ }
+ @Override
+ protected Void doInBackground(Void... params) {
+ // We load in two stages: first, we update progress with just the first screenful
+ // of items. Then, we update with the rest of the items
+ final int origPri = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ final PackageManager pm = mContext.getPackageManager();
+ final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ final List<ActivityManager.RecentTaskInfo> recentTasks =
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ int numTasks = recentTasks.size();
+ ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
- ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
+ boolean firstScreenful = true;
+ ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
- HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>();
- int numTasks = recentTasks.size();
-
- // skip the first task - assume it's either the home screen or the current activity.
- final int first = 1;
- recentTasksToKeepInCache.add(recentTasks.get(0).persistentId);
- for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
- final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
-
- TaskDescription item = createTaskDescription(recentInfo.id,
- recentInfo.persistentId, recentInfo.baseIntent,
- recentInfo.origActivity, recentInfo.description, homeInfo);
-
- if (item != null) {
- tasks.add(item);
- ++index;
- }
- }
-
- // when we're not using the TaskDescription cache, we load the thumbnails in the
- // background
- loadThumbnailsInBackground(new ArrayList<TaskDescription>(tasks));
- return tasks;
- }
-
- private void loadThumbnailsInBackground(final ArrayList<TaskDescription> descriptions) {
- if (descriptions.size() > 0) {
- if (DEBUG) Log.v(TAG, "Showing " + descriptions.size() + " tasks");
- loadThumbnail(descriptions.get(0));
- if (descriptions.size() > 1) {
- mThumbnailLoader = new AsyncTask<Void, Integer, Void>() {
- @Override
- protected void onProgressUpdate(Integer... values) {
- final TaskDescription td = descriptions.get(values[0]);
- if (!isCancelled()) {
- mRecentsPanel.onTaskThumbnailLoaded(td);
- }
- // This is to prevent the loader thread from getting ahead
- // of our UI updates.
- mHandler.post(new Runnable() {
- @Override public void run() {
- synchronized (td) {
- td.notifyAll();
- }
- }
- });
+ // skip the first task - assume it's either the home screen or the current activity.
+ final int first = 1;
+ for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
+ if (isCancelled()) {
+ break;
}
+ final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+ TaskDescription item = createTaskDescription(recentInfo.id,
+ recentInfo.persistentId, recentInfo.baseIntent,
+ recentInfo.origActivity, recentInfo.description, homeInfo);
- @Override
- protected Void doInBackground(Void... params) {
- final int origPri = Process.getThreadPriority(Process.myTid());
- Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
- long nextTime = SystemClock.uptimeMillis();
- for (int i=1; i<descriptions.size(); i++) {
- TaskDescription td = descriptions.get(i);
- loadThumbnail(td);
- long now = SystemClock.uptimeMillis();
- nextTime += 0;
- if (nextTime > now) {
- try {
- Thread.sleep(nextTime-now);
- } catch (InterruptedException e) {
- }
- }
-
- if (isCancelled()) {
+ if (item != null) {
+ while (true) {
+ try {
+ tasksWaitingForThumbnails.put(item);
break;
- }
- synchronized (td) {
- publishProgress(i);
- try {
- td.wait(500);
- } catch (InterruptedException e) {
- }
+ } catch (InterruptedException e) {
}
}
- Process.setThreadPriority(origPri);
- return null;
+ tasks.add(item);
+ if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
+ publishProgress(tasks);
+ tasks = new ArrayList<TaskDescription>();
+ firstScreenful = false;
+ //break;
+ }
+ ++index;
}
- };
- mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ if (!isCancelled()) {
+ publishProgress(tasks);
+ if (firstScreenful) {
+ // always should publish two updates
+ publishProgress(new ArrayList<TaskDescription>());
+ }
+ }
+
+ while (true) {
+ try {
+ tasksWaitingForThumbnails.put(new TaskDescription());
+ break;
+ } catch (InterruptedException e) {
+ }
+ }
+
+ Process.setThreadPriority(origPri);
+ return null;
}
- }
+ };
+ mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
}
+ private void loadThumbnailsAndIconsInBackground(
+ final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
+ // continually read items from tasksWaitingForThumbnails and load
+ // thumbnails and icons for them. finish thread when cancelled or there
+ // is a null item in tasksWaitingForThumbnails
+ mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
+ @Override
+ protected void onProgressUpdate(TaskDescription... values) {
+ if (!isCancelled()) {
+ TaskDescription td = values[0];
+ mRecentsPanel.onTaskThumbnailLoaded(td);
+ }
+ }
+ @Override
+ protected Void doInBackground(Void... params) {
+ final int origPri = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+
+ while (true) {
+ if (isCancelled()) {
+ break;
+ }
+ TaskDescription td = null;
+ while (td == null) {
+ try {
+ td = tasksWaitingForThumbnails.take();
+ } catch (InterruptedException e) {
+ }
+ }
+ if (td.isNull()) {
+ break;
+ }
+ loadThumbnailAndIcon(td);
+ synchronized(td) {
+ publishProgress(td);
+ }
+ }
+
+ Process.setThreadPriority(origPri);
+ return null;
+ }
+ };
+ mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index f971d2d..4718a17 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -22,11 +22,18 @@
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
+import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
@@ -34,6 +41,8 @@
import com.android.systemui.SwipeHelper;
import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
+import java.util.ArrayList;
+
public class RecentsHorizontalScrollView extends HorizontalScrollView
implements SwipeHelper.Callback {
private static final String TAG = RecentsPanelView.TAG;
@@ -44,6 +53,8 @@
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private ArrayList<View> mRecycledViews;
+ private int mNumItemsInOneScreenful;
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -51,6 +62,7 @@
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+ mRecycledViews = new ArrayList<View>();
}
private int scrollPositionOfMostRecent() {
@@ -58,9 +70,23 @@
}
private void update() {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ mRecycledViews.add(v);
+ mAdapter.recycleView(v);
+ }
+ LayoutTransition transitioner = getLayoutTransition();
+ setLayoutTransition(null);
+
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- final View view = mAdapter.getView(i, null, mLinearLayout);
+ View old = null;
+ if (mRecycledViews.size() != 0) {
+ old = mRecycledViews.remove(mRecycledViews.size() - 1);
+ old.setVisibility(VISIBLE);
+ }
+
+ final View view = mAdapter.getView(i, old, mLinearLayout);
if (mPerformanceHelper != null) {
mPerformanceHelper.addViewCallback(view);
@@ -87,7 +113,8 @@
}
};
- final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
+ final View thumbnailView = holder.thumbnailView;
OnLongClickListener longClickListener = new OnLongClickListener() {
public boolean onLongClick(View v) {
final View anchorView = view.findViewById(R.id.app_description);
@@ -107,13 +134,21 @@
appTitle.setOnTouchListener(noOpListener);
mLinearLayout.addView(view);
}
+ setLayoutTransition(transitioner);
+
// Scroll to end after layout.
- post(new Runnable() {
- public void run() {
- mLastScrollPosition = scrollPositionOfMostRecent();
- scrollTo(mLastScrollPosition, 0);
- }
- });
+ final ViewTreeObserver observer = getViewTreeObserver();
+
+ final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(mLastScrollPosition, 0);
+ if (observer.isAlive()) {
+ observer.removeOnGlobalLayoutListener(this);
+ }
+ }
+ };
+ observer.addOnGlobalLayoutListener(updateScroll);
}
@Override
@@ -142,8 +177,10 @@
}
public void onChildDismissed(View v) {
+ mRecycledViews.add(v);
mLinearLayout.removeView(v);
mCallback.handleSwipe(v);
+ v.setActivated(false);
}
public void onBeginDrag(View v) {
@@ -315,6 +352,24 @@
update();
}
});
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+ int childWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
+ int childheightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
+ View child = mAdapter.createView(mLinearLayout);
+ child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ mNumItemsInOneScreenful =
+ (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth());
+ mRecycledViews.add(child);
+
+ for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
+ mRecycledViews.add(mAdapter.createView(mLinearLayout));
+ }
+ }
+
+ public int numItemsInOneScreenful() {
+ return mNumItemsInOneScreenful;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index a10e363..7896720 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -27,6 +27,7 @@
import android.graphics.Matrix;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.Settings;
import android.util.AttributeSet;
@@ -36,18 +37,18 @@
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.PopupMenu;
-import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
@@ -59,7 +60,7 @@
import java.util.ArrayList;
-public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback,
+public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -71,6 +72,10 @@
private StatusBarTouchProxy mStatusBarTouchProxy;
private boolean mShowing;
+ private boolean mWaitingToShow;
+ private boolean mWaitingToShowAnimated;
+ private boolean mReadyToShow;
+ private int mNumItemsWaitingForThumbnailsAndIcons;
private Choreographer mChoreo;
OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
@@ -104,6 +109,7 @@
TextView labelView;
TextView descriptionView;
TaskDescription taskDescription;
+ boolean loadedThumbnailAndIcon;
}
/* package */ final class TaskDescriptionAdapter extends BaseAdapter {
@@ -125,42 +131,82 @@
return position; // we just need something unique for this position
}
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
- if (convertView == null) {
- convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
- holder = new ViewHolder();
- holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
- holder.thumbnailViewImage = (ImageView) convertView.findViewById(
- R.id.app_thumbnail_image);
- // If we set the default thumbnail now, we avoid an onLayout when we update
- // the thumbnail later (if they both have the same dimensions)
+ public View createView(ViewGroup parent) {
+ View convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
+ ViewHolder holder = new ViewHolder();
+ holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
+ holder.thumbnailViewImage =
+ (ImageView) convertView.findViewById(R.id.app_thumbnail_image);
+ // If we set the default thumbnail now, we avoid an onLayout when we update
+ // the thumbnail later (if they both have the same dimensions)
+ if (mRecentTasksLoader != null) {
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-
- holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
- holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
-
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
}
+ holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
+ if (mRecentTasksLoader != null) {
+ holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ }
+ holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
+ holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
+
+ convertView.setTag(holder);
+ return convertView;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = createView(parent);
+ }
+ ViewHolder holder = (ViewHolder) convertView.getTag();
// index is reverse since most recent appears at the bottom...
final int index = mRecentTaskDescriptions.size() - position - 1;
final TaskDescription td = mRecentTaskDescriptions.get(index);
- holder.iconView.setImageDrawable(td.getIcon());
+
holder.labelView.setText(td.getLabel());
holder.thumbnailView.setContentDescription(td.getLabel());
- updateThumbnail(holder, td.getThumbnail(), true, false);
+ holder.loadedThumbnailAndIcon = td.isLoaded();
+ if (td.isLoaded()) {
+ updateThumbnail(holder, td.getThumbnail(), true, false);
+ updateIcon(holder, td.getIcon(), true, false);
+ mNumItemsWaitingForThumbnailsAndIcons--;
+ }
holder.thumbnailView.setTag(td);
holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
holder.taskDescription = td;
-
return convertView;
}
+
+ public void recycleView(View v) {
+ ViewHolder holder = (ViewHolder) v.getTag();
+ updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
+ holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setVisibility(INVISIBLE);
+ holder.labelView.setText(null);
+ holder.thumbnailView.setContentDescription(null);
+ holder.thumbnailView.setTag(null);
+ holder.thumbnailView.setOnLongClickListener(null);
+ holder.thumbnailView.setVisibility(INVISIBLE);
+ holder.taskDescription = null;
+ holder.loadedThumbnailAndIcon = false;
+ }
+ }
+
+ public int numItemsInOneScreenful() {
+ if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+ RecentsHorizontalScrollView scrollView
+ = (RecentsHorizontalScrollView) mRecentsContainer;
+ return scrollView.numItemsInOneScreenful();
+ } else if (mRecentsContainer instanceof RecentsVerticalScrollView){
+ RecentsVerticalScrollView scrollView
+ = (RecentsVerticalScrollView) mRecentsContainer;
+ return scrollView.numItemsInOneScreenful();
+ }
+ else {
+ throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
+ }
}
@Override
@@ -192,15 +238,32 @@
}
public void show(boolean show, boolean animate) {
- show(show, animate, null);
+ if (show) {
+ refreshRecentTasksList(null, true);
+ mWaitingToShow = true;
+ mWaitingToShowAnimated = animate;
+ showIfReady();
+ } else {
+ show(show, animate, null, false);
+ }
+ }
+
+ private void showIfReady() {
+ // mWaitingToShow = there was a touch up on the recents button
+ // mReadyToShow = we've created views for the first screenful of items
+ if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0
+ show(true, mWaitingToShowAnimated, null, false);
+ }
}
public void show(boolean show, boolean animate,
- ArrayList<TaskDescription> recentTaskDescriptions) {
+ ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
+ // For now, disable animations. We may want to re-enable in the future
+ animate = false;
if (show) {
// Need to update list of recent apps before we set visibility so this view's
// content description is updated before it gets focus for TalkBack mode
- refreshRecentTasksList(recentTaskDescriptions);
+ refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
// if there are no apps, either bring up a "No recent apps" message, or just
// quit early
@@ -209,19 +272,24 @@
mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
} else {
if (noApps) {
- if (DEBUG) Log.v(TAG, "Nothing to show");
+ if (DEBUG) Log.v(TAG, "Nothing to show");
// Need to set recent tasks to dirty so that next time we load, we
// refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnails();
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTasksDirty = true;
+
+ mWaitingToShow = false;
+ mReadyToShow = false;
return;
}
}
} else {
// Need to set recent tasks to dirty so that next time we load, we
// refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnails();
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTasksDirty = true;
+ mWaitingToShow = false;
+ mReadyToShow = false;
}
if (animate) {
if (mShowing != show) {
@@ -385,7 +453,6 @@
throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
}
-
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
@@ -425,6 +492,20 @@
}
}
+
+ private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
+ if (icon != null) {
+ h.iconView.setImageDrawable(icon);
+ if (show && h.iconView.getVisibility() != View.VISIBLE) {
+ if (anim) {
+ h.iconView.setAnimation(
+ AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
+ }
+ h.iconView.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
if (thumbnail != null) {
// Should remove the default image in the frame
@@ -458,31 +539,36 @@
}
}
- void onTaskThumbnailLoaded(TaskDescription ad) {
- synchronized (ad) {
+ void onTaskThumbnailLoaded(TaskDescription td) {
+ synchronized (td) {
if (mRecentsContainer != null) {
ViewGroup container = mRecentsContainer;
if (container instanceof HorizontalScrollView
|| container instanceof ScrollView) {
- container = (ViewGroup)container.findViewById(
+ container = (ViewGroup) container.findViewById(
R.id.recents_linear_layout);
}
// Look for a view showing this thumbnail, to update.
- for (int i=0; i<container.getChildCount(); i++) {
+ for (int i=0; i < container.getChildCount(); i++) {
View v = container.getChildAt(i);
if (v.getTag() instanceof ViewHolder) {
ViewHolder h = (ViewHolder)v.getTag();
- if (h.taskDescription == ad) {
+ if (!h.loadedThumbnailAndIcon && h.taskDescription == td) {
// only fade in the thumbnail if recents is already visible-- we
// show it immediately otherwise
- boolean animateShow = mShowing &&
- mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
- updateThumbnail(h, ad.getThumbnail(), true, animateShow);
+ //boolean animateShow = mShowing &&
+ // mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
+ boolean animateShow = false;
+ updateIcon(h, td.getIcon(), true, animateShow);
+ updateThumbnail(h, td.getThumbnail(), true, animateShow);
+ h.loadedThumbnailAndIcon = true;
+ mNumItemsWaitingForThumbnailsAndIcons--;
}
}
}
}
- }
+ }
+ showIfReady();
}
// additional optimization when we have sofware system buttons - start loading the recent
@@ -516,7 +602,7 @@
public void clearRecentTasksList() {
// Clear memory used by screenshots
if (mRecentTaskDescriptions != null) {
- mRecentTasksLoader.cancelLoadingThumbnails();
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTaskDescriptions.clear();
mListAdapter.notifyDataSetInvalidated();
mRecentTasksDirty = true;
@@ -524,26 +610,50 @@
}
public void refreshRecentTasksList() {
- refreshRecentTasksList(null);
+ refreshRecentTasksList(null, false);
}
- private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) {
+ private void refreshRecentTasksList(
+ ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
if (mRecentTasksDirty) {
if (recentTasksList != null) {
- mRecentTaskDescriptions = recentTasksList;
+ mFirstScreenful = true;
+ onTasksLoaded(recentTasksList);
} else {
- mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
+ mFirstScreenful = true;
+ mRecentTasksLoader.loadTasksInBackground();
}
- mListAdapter.notifyDataSetInvalidated();
- updateUiElements(getResources().getConfiguration());
mRecentTasksDirty = false;
}
}
+ boolean mFirstScreenful;
+ public void onTasksLoaded(ArrayList<TaskDescription> tasks) {
+ if (!mFirstScreenful && tasks.size() == 0) {
+ return;
+ }
+ mNumItemsWaitingForThumbnailsAndIcons =
+ mFirstScreenful ? tasks.size() : mRecentTaskDescriptions.size();
+ if (mRecentTaskDescriptions == null) {
+ mRecentTaskDescriptions = new ArrayList(tasks);
+ } else {
+ mRecentTaskDescriptions.addAll(tasks);
+ }
+ mListAdapter.notifyDataSetInvalidated();
+ updateUiElements(getResources().getConfiguration());
+ mReadyToShow = true;
+ mFirstScreenful = false;
+ showIfReady();
+ }
+
public ArrayList<TaskDescription> getRecentTasksList() {
return mRecentTaskDescriptions;
}
+ public boolean getFirstScreenful() {
+ return mFirstScreenful;
+ }
+
private void updateUiElements(Configuration config) {
final int items = mRecentTaskDescriptions.size();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index dc13092..0605c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -22,10 +22,18 @@
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.LinearLayout;
import android.widget.ScrollView;
@@ -33,6 +41,8 @@
import com.android.systemui.SwipeHelper;
import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
+import java.util.ArrayList;
+
public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper.Callback {
private static final String TAG = RecentsPanelView.TAG;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -42,6 +52,8 @@
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private ArrayList<View> mRecycledViews;
+ private int mNumItemsInOneScreenful;
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -50,6 +62,7 @@
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+ mRecycledViews = new ArrayList<View>();
}
private int scrollPositionOfMostRecent() {
@@ -57,77 +70,91 @@
}
private void update() {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ mRecycledViews.add(v);
+ mAdapter.recycleView(v);
+ }
+ LayoutTransition transitioner = getLayoutTransition();
+ setLayoutTransition(null);
+
mLinearLayout.removeAllViews();
// Once we can clear the data associated with individual item views,
// we can get rid of the removeAllViews() and the code below will
// recycle them.
for (int i = 0; i < mAdapter.getCount(); i++) {
View old = null;
- if (i < mLinearLayout.getChildCount()) {
- old = mLinearLayout.getChildAt(i);
- old.setVisibility(View.VISIBLE);
+ if (mRecycledViews.size() != 0) {
+ old = mRecycledViews.remove(mRecycledViews.size() - 1);
+ old.setVisibility(VISIBLE);
}
+
final View view = mAdapter.getView(i, old, mLinearLayout);
if (mPerformanceHelper != null) {
mPerformanceHelper.addViewCallback(view);
}
- if (old == null) {
- OnTouchListener noOpListener = new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return true;
- }
- };
+ OnTouchListener noOpListener = new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return true;
+ }
+ };
- view.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- mCallback.dismiss();
- }
- });
- // We don't want a click sound when we dimiss recents
- view.setSoundEffectsEnabled(false);
+ view.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ mCallback.dismiss();
+ }
+ });
+ // We don't want a click sound when we dimiss recents
+ view.setSoundEffectsEnabled(false);
- OnClickListener launchAppListener = new OnClickListener() {
- public void onClick(View v) {
- mCallback.handleOnClick(view);
- }
- };
+ OnClickListener launchAppListener = new OnClickListener() {
+ public void onClick(View v) {
+ mCallback.handleOnClick(view);
+ }
+ };
- final View thumbnailView = view.findViewById(R.id.app_thumbnail);
- OnLongClickListener longClickListener = new OnLongClickListener() {
- public boolean onLongClick(View v) {
- final View anchorView = view.findViewById(R.id.app_description);
- mCallback.handleLongPress(view, anchorView, thumbnailView);
- return true;
- }
- };
- thumbnailView.setClickable(true);
- thumbnailView.setOnClickListener(launchAppListener);
- thumbnailView.setOnLongClickListener(longClickListener);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
+ final View thumbnailView = holder.thumbnailView;
+ OnLongClickListener longClickListener = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = view.findViewById(R.id.app_description);
+ mCallback.handleLongPress(view, anchorView, thumbnailView);
+ return true;
+ }
+ };
+ thumbnailView.setClickable(true);
+ thumbnailView.setOnClickListener(launchAppListener);
+ thumbnailView.setOnLongClickListener(longClickListener);
- // We don't want to dismiss recents if a user clicks on the app title
- // (we also don't want to launch the app either, though, because the
- // app title is a small target and doesn't have great click feedback)
- final View appTitle = view.findViewById(R.id.app_label);
- appTitle.setContentDescription(" ");
- appTitle.setOnTouchListener(noOpListener);
- final View calloutLine = view.findViewById(R.id.recents_callout_line);
- calloutLine.setOnTouchListener(noOpListener);
- mLinearLayout.addView(view);
- }
+ // We don't want to dismiss recents if a user clicks on the app title
+ // (we also don't want to launch the app either, though, because the
+ // app title is a small target and doesn't have great click feedback)
+ final View appTitle = view.findViewById(R.id.app_label);
+ appTitle.setContentDescription(" ");
+ appTitle.setOnTouchListener(noOpListener);
+ final View calloutLine = view.findViewById(R.id.recents_callout_line);
+ calloutLine.setOnTouchListener(noOpListener);
+
+ mLinearLayout.addView(view);
}
- for (int i = mAdapter.getCount(); i < mLinearLayout.getChildCount(); i++) {
- mLinearLayout.getChildAt(i).setVisibility(View.GONE);
- }
+ setLayoutTransition(transitioner);
+
// Scroll to end after layout.
- post(new Runnable() {
- public void run() {
- mLastScrollPosition = scrollPositionOfMostRecent();
- scrollTo(0, mLastScrollPosition);
- }
- });
+ final ViewTreeObserver observer = getViewTreeObserver();
+
+ final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(0, mLastScrollPosition);
+ if (observer.isAlive()) {
+ observer.removeOnGlobalLayoutListener(this);
+ }
+ }
+ };
+ observer.addOnGlobalLayoutListener(updateScroll);
}
@Override
@@ -156,8 +183,10 @@
}
public void onChildDismissed(View v) {
+ mRecycledViews.add(v);
mLinearLayout.removeView(v);
mCallback.handleSwipe(v);
+ v.setActivated(false);
}
public void onBeginDrag(View v) {
@@ -330,6 +359,25 @@
update();
}
});
+
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+ int childWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
+ int childheightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
+ View child = mAdapter.createView(mLinearLayout);
+ child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ mNumItemsInOneScreenful =
+ (int) FloatMath.ceil(dm.heightPixels / (float) child.getMeasuredHeight());
+ mRecycledViews.add(child);
+
+ for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
+ mRecycledViews.add(mAdapter.createView(mLinearLayout));
+ }
+ }
+
+ public int numItemsInOneScreenful() {
+ return mNumItemsInOneScreenful;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index dcfd6d8..7e979b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -32,6 +32,7 @@
private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
private Drawable mIcon; // application package icon
private CharSequence mLabel; // application package label
+ private boolean mLoaded;
public TaskDescription(int _taskId, int _persistentTaskId,
ResolveInfo _resolveInfo, Intent _intent,
@@ -45,6 +46,28 @@
packageName = _packageName;
}
+ public TaskDescription() {
+ resolveInfo = null;
+ intent = null;
+ taskId = -1;
+ persistentTaskId = -1;
+
+ description = null;
+ packageName = null;
+ }
+
+ public void setLoaded(boolean loaded) {
+ mLoaded = loaded;
+ }
+
+ public boolean isLoaded() {
+ return mLoaded;
+ }
+
+ public boolean isNull() {
+ return resolveInfo == null;
+ }
+
// mark all these as locked?
public CharSequence getLabel() {
return mLabel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5a1e3f4..b3cef90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -393,7 +393,7 @@
}
lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
lp.setTitle("RecentsPanel");
- lp.windowAnimations = R.style.Animation_RecentPanel;
+ lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
return lp;
@@ -403,11 +403,13 @@
// Recents Panel
boolean visible = false;
ArrayList<TaskDescription> recentTasksList = null;
+ boolean firstScreenful = false;
if (mRecentsPanel != null) {
visible = mRecentsPanel.isShowing();
WindowManagerImpl.getDefault().removeView(mRecentsPanel);
if (visible) {
recentTasksList = mRecentsPanel.getRecentTasksList();
+ firstScreenful = mRecentsPanel.getFirstScreenful();
}
}
@@ -425,7 +427,7 @@
WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
mRecentsPanel.setBar(this);
if (visible) {
- mRecentsPanel.show(true, false, recentTasksList);
+ mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index d787e10..c59290c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -88,6 +88,7 @@
int mLastSignalLevel;
boolean mShowPhoneRSSIForData = false;
boolean mShowAtLeastThreeGees = false;
+ boolean mAlwaysShowCdmaRssi = false;
String mContentDescriptionPhoneSignal;
String mContentDescriptionWifi;
@@ -156,7 +157,7 @@
IBatteryStats mBatteryStats;
public interface SignalCluster {
- void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
+ void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
String contentDescription);
void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
int typeIcon, String contentDescription, String typeContentDescription);
@@ -176,6 +177,8 @@
mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
+ mAlwaysShowCdmaRssi = res.getBoolean(
+ com.android.internal.R.bool.config_alwaysUseCdmaRssi);
// set up the default wifi icon, used when no radios have ever appeared
updateWifiIcons();
@@ -287,7 +290,7 @@
// wimax is special
cluster.setMobileDataIndicators(
true,
- mWimaxIconId,
+ mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
mMobileActivityIconId,
mDataTypeIconId,
mContentDescriptionWimax,
@@ -351,7 +354,7 @@
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
if (DEBUG) {
- Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+ Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
}
mSignalStrength = signalStrength;
@@ -469,7 +472,15 @@
} else {
int iconLevel;
int[] iconList;
- mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+ if (isCdma() && mAlwaysShowCdmaRssi) {
+ mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
+ if(DEBUG) Slog.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+ + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
+ + " instead of level=" + mSignalStrength.getLevel());
+ } else {
+ mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+ }
+
if (isCdma()) {
if (isCdmaEri()) {
iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
@@ -487,7 +498,6 @@
mPhoneSignalIconId = iconList[iconLevel];
mContentDescriptionPhoneSignal = mContext.getString(
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
-
mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
}
}
@@ -914,7 +924,7 @@
mobileLabel = "";
}
} else {
- mobileLabel
+ mobileLabel
= context.getString(R.string.status_bar_settings_signal_meter_disconnected);
}
@@ -1190,7 +1200,7 @@
v.setText(wifiLabel);
}
}
-
+
// mobile label
N = mMobileLabelViews.size();
for (int i=0; i<N; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 6287408..5151cad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -456,8 +456,7 @@
// Sanity-check that someone hasn't set up the config wrong and asked for a navigation
// bar on a tablet that has only the system bar
if (mWindowManager.hasNavigationBar()) {
- throw new RuntimeException(
- "Tablet device cannot show navigation bar and system bar");
+ Slog.e(TAG, "Tablet device cannot show navigation bar and system bar");
}
} catch (RemoteException ex) {
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index abed18f..83f7788 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -52,8 +52,7 @@
}
public void preDispatchKeyEvent(KeyEvent event) {
- getAudioManager().preDispatchKeyEvent(event.getKeyCode(),
- AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
}
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -79,7 +78,7 @@
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
return true;
}
@@ -197,8 +196,7 @@
AudioManager audioManager = (AudioManager)mContext.getSystemService(
Context.AUDIO_SERVICE);
if (audioManager != null) {
- getAudioManager().handleKeyUp(keyCode,
- AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
}
}
return true;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index f1fe43b..b87b8c3 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1416,7 +1416,7 @@
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType);
+ getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
return true;
}
@@ -1478,7 +1478,7 @@
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType);
+ getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
return true;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index d34ed177..c12a4b7e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -286,7 +286,8 @@
/** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
boolean mEnableShiftMenuBugReports = false;
-
+
+ boolean mHeadless;
boolean mSafeMode;
WindowState mStatusBar = null;
boolean mStatusBarCanHide;
@@ -686,7 +687,7 @@
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext);
}
- final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden();
+ final boolean keyguardShowing = keyguardIsShowingTq();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
// since it took two seconds of long press to bring this up,
@@ -783,7 +784,11 @@
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
mPowerManager = powerManager;
- mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+ mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
+ if (!mHeadless) {
+ // don't create KeyguardViewMediator if headless
+ mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+ }
mHandler = new Handler();
mOrientationListener = new MyOrientationListener(mContext);
try {
@@ -1511,12 +1516,8 @@
}
static ITelephony getTelephonyService() {
- ITelephony telephonyService = ITelephony.Stub.asInterface(
+ return ITelephony.Stub.asInterface(
ServiceManager.checkService(Context.TELEPHONY_SERVICE));
- if (telephonyService == null) {
- Log.w(TAG, "Unable to find ITelephony interface.");
- }
- return telephonyService;
}
static IAudioService getAudioService() {
@@ -1839,7 +1840,7 @@
* given the situation with the keyguard.
*/
void launchHomeFromHotKey() {
- if (mKeyguardMediator.isShowingAndNotHidden()) {
+ if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
// don't launch home if keyguard showing
} else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
@@ -2580,6 +2581,9 @@
/** {@inheritDoc} */
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+ // do nothing if headless
+ if (mHeadless) return;
+
// lid changed state
mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED;
updateKeyboardVisibility();
@@ -2776,9 +2780,10 @@
// the same as if it were open and in front.
// This will prevent any keys other than the power button from waking the screen
// when the keyguard is hidden by another activity.
- final boolean keyguardActive = (isScreenOn ?
- mKeyguardMediator.isShowingAndNotHidden() :
- mKeyguardMediator.isShowing());
+ final boolean keyguardActive = (mKeyguardMediator == null ? false :
+ (isScreenOn ?
+ mKeyguardMediator.isShowingAndNotHidden() :
+ mKeyguardMediator.isShowing()));
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
@@ -2810,7 +2815,7 @@
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
- if (isScreenOn || (isInjected && !isWakeKey)) {
+ if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
} else {
@@ -3046,7 +3051,7 @@
final boolean isWakeMotion = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isWakeMotion) {
- if (mKeyguardMediator.isShowing()) {
+ if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) {
// If the keyguard is showing, let it decide what to do with the wake motion.
mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
} else {
@@ -3114,7 +3119,9 @@
mScreenOnEarly = false;
mScreenOnFully = false;
}
- mKeyguardMediator.onScreenTurnedOff(why);
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.onScreenTurnedOff(why);
+ }
synchronized (mLock) {
updateOrientationListenerLp();
updateLockScreenTimeout();
@@ -3131,31 +3138,33 @@
Slog.i(TAG, "Screen turning on...", here);
}
if (screenOnListener != null) {
- mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
- @Override public void onShown(IBinder windowToken) {
- if (windowToken != null) {
- try {
- mWindowManager.waitForWindowDrawn(windowToken,
- new IRemoteCallback.Stub() {
- @Override public void sendResult(Bundle data) {
- Slog.i(TAG, "Lock screen displayed!");
- screenOnListener.onScreenOn();
- synchronized (mLock) {
- mScreenOnFully = true;
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
+ @Override public void onShown(IBinder windowToken) {
+ if (windowToken != null) {
+ try {
+ mWindowManager.waitForWindowDrawn(windowToken,
+ new IRemoteCallback.Stub() {
+ @Override public void sendResult(Bundle data) {
+ Slog.i(TAG, "Lock screen displayed!");
+ screenOnListener.onScreenOn();
+ synchronized (mLock) {
+ mScreenOnFully = true;
+ }
}
- }
- });
- } catch (RemoteException e) {
- }
- } else {
- Slog.i(TAG, "No lock screen!");
- screenOnListener.onScreenOn();
- synchronized (mLock) {
- mScreenOnFully = true;
+ });
+ } catch (RemoteException e) {
+ }
+ } else {
+ Slog.i(TAG, "No lock screen!");
+ screenOnListener.onScreenOn();
+ synchronized (mLock) {
+ mScreenOnFully = true;
+ }
}
}
- }
- });
+ });
+ }
} else {
synchronized (mLock) {
mScreenOnFully = true;
@@ -3181,15 +3190,20 @@
/** {@inheritDoc} */
public void enableKeyguard(boolean enabled) {
- mKeyguardMediator.setKeyguardEnabled(enabled);
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.setKeyguardEnabled(enabled);
+ }
}
/** {@inheritDoc} */
public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
- mKeyguardMediator.verifyUnlock(callback);
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.verifyUnlock(callback);
+ }
}
private boolean keyguardIsShowingTq() {
+ if (mKeyguardMediator == null) return false;
return mKeyguardMediator.isShowingAndNotHidden();
}
@@ -3201,11 +3215,13 @@
/** {@inheritDoc} */
public boolean isKeyguardSecure() {
+ if (mKeyguardMediator == null) return false;
return mKeyguardMediator.isSecure();
}
/** {@inheritDoc} */
public boolean inKeyguardRestrictedKeyInputMode() {
+ if (mKeyguardMediator == null) return false;
return mKeyguardMediator.isInputRestricted();
}
@@ -3461,8 +3477,10 @@
/** {@inheritDoc} */
public void systemReady() {
- // tell the keyguard
- mKeyguardMediator.onSystemReady();
+ if (mKeyguardMediator != null) {
+ // tell the keyguard
+ mKeyguardMediator.onSystemReady();
+ }
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -3485,6 +3503,7 @@
/** {@inheritDoc} */
public void showBootMessage(final CharSequence msg, final boolean always) {
+ if (mHeadless) return;
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
@@ -3648,7 +3667,9 @@
public void run() {
synchronized (this) {
if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
- mKeyguardMediator.doKeyguardTimeout();
+ if (mKeyguardMediator != null) {
+ mKeyguardMediator.doKeyguardTimeout();
+ }
mLockScreenTimerActive = false;
}
}
@@ -3662,7 +3683,8 @@
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
- boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && mKeyguardMediator.isSecure());
+ boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly &&
+ mKeyguardMediator != null && mKeyguardMediator.isSecure());
if (mLockScreenTimerActive != enable) {
if (enable) {
if (localLOGV) Log.v(TAG, "setting lockscreen timer");
@@ -3862,7 +3884,7 @@
public void screenOnStoppedLw() {
if (mPowerManager.isScreenOn()) {
- if (!mKeyguardMediator.isShowingAndNotHidden()) {
+ if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
}
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 52834db..22fa752 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -6,9 +6,11 @@
AudioFlinger.cpp \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
- AudioResamplerSinc.cpp.arm \
- AudioResamplerCubic.cpp.arm \
- AudioPolicyService.cpp
+ AudioPolicyService.cpp \
+ AudioBufferProvider.cpp \
+ ServiceUtilities.cpp
+# AudioResamplerSinc.cpp.arm
+# AudioResamplerCubic.cpp.arm
LOCAL_C_INCLUDES := \
system/media/audio_effects/include \
@@ -16,6 +18,7 @@
LOCAL_SHARED_LIBRARIES := \
libaudioutils \
+ libcommon_time_client \
libcutils \
libutils \
libbinder \
diff --git a/include/ui/PowerManager.h b/services/audioflinger/AudioBufferProvider.cpp
similarity index 61%
copy from include/ui/PowerManager.h
copy to services/audioflinger/AudioBufferProvider.cpp
index dd80318..678fd58 100644
--- a/include/ui/PowerManager.h
+++ b/services/audioflinger/AudioBufferProvider.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -14,20 +14,15 @@
* limitations under the License.
*/
-#ifndef _UI_POWER_MANAGER_H
-#define _UI_POWER_MANAGER_H
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+#include "AudioBufferProvider.h"
namespace android {
-enum {
- POWER_MANAGER_OTHER_EVENT = 0,
- POWER_MANAGER_BUTTON_EVENT = 1,
- POWER_MANAGER_TOUCH_EVENT = 2,
+const int64_t AudioBufferProvider::kInvalidPTS = INT64_MAX;
- POWER_MANAGER_LAST_EVENT = POWER_MANAGER_TOUCH_EVENT, // Last valid event code.
-};
-
-} // namespace android
-
-#endif // _UI_POWER_MANAGER_H
+}; // namespace android
diff --git a/services/audioflinger/AudioBufferProvider.h b/services/audioflinger/AudioBufferProvider.h
index 81c5c39..62ad6bd 100644
--- a/services/audioflinger/AudioBufferProvider.h
+++ b/services/audioflinger/AudioBufferProvider.h
@@ -38,8 +38,15 @@
};
virtual ~AudioBufferProvider() {}
-
- virtual status_t getNextBuffer(Buffer* buffer) = 0;
+
+ // value representing an invalid presentation timestamp
+ static const int64_t kInvalidPTS;
+
+ // pts is the local time when the next sample yielded by getNextBuffer
+ // will be rendered.
+ // Pass kInvalidPTS if the PTS is unknown or not applicable.
+ virtual status_t getNextBuffer(Buffer* buffer, int64_t pts) = 0;
+
virtual void releaseBuffer(Buffer* buffer) = 0;
};
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 93c91fb..2e2834c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -48,6 +48,7 @@
#include "AudioMixer.h"
#include "AudioFlinger.h"
+#include "ServiceUtilities.h"
#include <media/EffectsFactoryApi.h>
#include <audio_effects/effect_visualizer.h>
@@ -60,6 +61,9 @@
#include <powermanager/PowerManager.h>
// #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds
+#include <common_time/cc_helper.h>
+#include <common_time/local_clock.h>
+
// ----------------------------------------------------------------------------
@@ -68,7 +72,6 @@
static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
static const char kHardwareLockedString[] = "Hardware lock is taken\n";
-//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
static const float MAX_GAIN = 4096.0f;
static const uint32_t MAX_GAIN_INT = 0x1000;
@@ -98,23 +101,10 @@
// maximum divider applied to the active sleep time in the mixer thread loop
static const uint32_t kMaxThreadSleepTimeShift = 2;
+nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
// ----------------------------------------------------------------------------
-static bool recordingAllowed() {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
- if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
- return ok;
-}
-
-static bool settingsAllowed() {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
- if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
- return ok;
-}
-
// To collect the amplifier usage
static void addBatteryData(uint32_t params) {
sp<IMediaPlayerService> service = IMediaDeathNotifier::getMediaPlayerService();
@@ -160,11 +150,14 @@
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
- mPrimaryHardwareDev(NULL),
- mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
- mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
- mMode(AUDIO_MODE_INVALID),
- mBtNrecIsOff(false)
+ mPrimaryHardwareDev(NULL),
+ mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
+ mMasterVolume(1.0f),
+ mMasterVolumeSupportLvl(MVS_NONE),
+ mMasterMute(false),
+ mNextUniqueId(1),
+ mMode(AUDIO_MODE_INVALID),
+ mBtNrecIsOff(false)
{
}
@@ -175,6 +168,18 @@
Mutex::Autolock _l(mLock);
/* TODO: move all this work into an Init() function */
+ char val_str[PROPERTY_VALUE_MAX] = { 0 };
+ if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) {
+ uint32_t int_val;
+ if (1 == sscanf(val_str, "%u", &int_val)) {
+ mStandbyTimeInNsecs = milliseconds(int_val);
+ ALOGI("Using %u mSec as standby time.", int_val);
+ } else {
+ mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
+ ALOGI("Using default %u mSec as standby time.",
+ (uint32_t)(mStandbyTimeInNsecs / 1000000));
+ }
+ }
for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
const hw_module_t *mod;
@@ -188,49 +193,80 @@
mod->name, mod->id);
mAudioHwDevs.push(dev);
- if (!mPrimaryHardwareDev) {
+ if (mPrimaryHardwareDev == NULL) {
mPrimaryHardwareDev = dev;
ALOGI("Using '%s' (%s.%s) as the primary audio interface",
mod->name, mod->id, audio_interfaces[i]);
}
}
- mHardwareStatus = AUDIO_HW_INIT;
-
- if (!mPrimaryHardwareDev || mAudioHwDevs.size() == 0) {
+ if (mPrimaryHardwareDev == NULL) {
ALOGE("Primary audio interface not found");
- return;
+ // proceed, all later accesses to mPrimaryHardwareDev verify it's safe with initCheck()
}
+ // Currently (mPrimaryHardwareDev == NULL) == (mAudioHwDevs.size() == 0), but the way the
+ // primary HW dev is selected can change so these conditions might not always be equivalent.
+ // When that happens, re-visit all the code that assumes this.
+
+ AutoMutex lock(mHardwareLock);
+
+ // Determine the level of master volume support the primary audio HAL has,
+ // and set the initial master volume at the same time.
+ float initialVolume = 1.0;
+ mMasterVolumeSupportLvl = MVS_NONE;
+ if (0 == mPrimaryHardwareDev->init_check(mPrimaryHardwareDev)) {
+ audio_hw_device_t *dev = mPrimaryHardwareDev;
+
+ mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+ if ((NULL != dev->get_master_volume) &&
+ (NO_ERROR == dev->get_master_volume(dev, &initialVolume))) {
+ mMasterVolumeSupportLvl = MVS_FULL;
+ } else {
+ mMasterVolumeSupportLvl = MVS_SETONLY;
+ initialVolume = 1.0;
+ }
+
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if ((NULL == dev->set_master_volume) ||
+ (NO_ERROR != dev->set_master_volume(dev, initialVolume))) {
+ mMasterVolumeSupportLvl = MVS_NONE;
+ }
+ mHardwareStatus = AUDIO_HW_INIT;
+ }
+
+ // Set the mode for each audio HAL, and try to set the initial volume (if
+ // supported) for all of the non-primary audio HALs.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
audio_hw_device_t *dev = mAudioHwDevs[i];
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->init_check(dev);
+ mHardwareStatus = AUDIO_HW_IDLE;
if (rc == 0) {
- AutoMutex lock(mHardwareLock);
-
- mMode = AUDIO_MODE_NORMAL;
+ mMode = AUDIO_MODE_NORMAL; // assigned multiple times with same value
mHardwareStatus = AUDIO_HW_SET_MODE;
dev->set_mode(dev, mMode);
- mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- dev->set_master_volume(dev, 1.0f);
- mHardwareStatus = AUDIO_HW_IDLE;
+
+ if ((dev != mPrimaryHardwareDev) &&
+ (NULL != dev->set_master_volume)) {
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ dev->set_master_volume(dev, initialVolume);
+ }
+
+ mHardwareStatus = AUDIO_HW_INIT;
}
}
-}
-status_t AudioFlinger::initCheck() const
-{
- Mutex::Autolock _l(mLock);
- if (mPrimaryHardwareDev == NULL || mAudioHwDevs.size() == 0)
- return NO_INIT;
- return NO_ERROR;
+ mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
+ ? initialVolume
+ : 1.0;
+ mMasterVolume = initialVolume;
+ mHardwareStatus = AUDIO_HW_IDLE;
}
AudioFlinger::~AudioFlinger()
{
- int num_devs = mAudioHwDevs.size();
while (!mRecordThreads.isEmpty()) {
// closeInput() will remove first entry from mRecordThreads
@@ -241,9 +277,9 @@
closeOutput(mPlaybackThreads.keyAt(0));
}
- for (int i = 0; i < num_devs; i++) {
- audio_hw_device_t *dev = mAudioHwDevs[i];
- audio_hw_device_close(dev);
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ // no mHardwareLock needed, as there are no other references to this
+ audio_hw_device_close(mAudioHwDevs[i]);
}
}
@@ -292,7 +328,10 @@
String8 result;
hardware_call_state hardwareStatus = mHardwareStatus;
- snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
+ snprintf(buffer, SIZE, "Hardware status: %d\n"
+ "Standby Time mSec: %u\n",
+ hardwareStatus,
+ (uint32_t)(mStandbyTimeInNsecs / 1000000));
result.append(buffer);
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -327,7 +366,7 @@
status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
{
- if (!checkCallingPermission(String16("android.permission.DUMP"))) {
+ if (!dumpAllowed()) {
dumpPermissionDenial(fd, args);
} else {
// get state of hardware lock
@@ -396,6 +435,7 @@
uint32_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ bool isTimed,
int *sessionId,
status_t *status)
{
@@ -454,7 +494,7 @@
ALOGV("createTrack() lSessionId: %d", lSessionId);
track = thread->createTrack_l(client, streamType, sampleRate, format,
- channelMask, frameCount, sharedBuffer, lSessionId, &lStatus);
+ channelMask, frameCount, sharedBuffer, lSessionId, isTimed, &lStatus);
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
@@ -547,20 +587,29 @@
return PERMISSION_DENIED;
}
+ float swmv = value;
+
// when hw supports master volume, don't scale in sw mixer
- { // scope for the lock
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- if (mPrimaryHardwareDev->set_master_volume(mPrimaryHardwareDev, value) == NO_ERROR) {
- value = 1.0f;
+ if (MVS_NONE != mMasterVolumeSupportLvl) {
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ AutoMutex lock(mHardwareLock);
+ audio_hw_device_t *dev = mAudioHwDevs[i];
+
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if (NULL != dev->set_master_volume) {
+ dev->set_master_volume(dev, value);
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
}
- mHardwareStatus = AUDIO_HW_IDLE;
+
+ swmv = 1.0;
}
Mutex::Autolock _l(mLock);
- mMasterVolume = value;
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
- mPlaybackThreads.valueAt(i)->setMasterVolume(value);
+ mMasterVolume = value;
+ mMasterVolumeSW = swmv;
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setMasterVolume(swmv);
return NO_ERROR;
}
@@ -591,7 +640,7 @@
if (NO_ERROR == ret) {
Mutex::Autolock _l(mLock);
mMode = mode;
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMode(mode);
}
@@ -625,6 +674,7 @@
}
bool state = AUDIO_MODE_INVALID;
+ AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
mHardwareStatus = AUDIO_HW_IDLE;
@@ -639,8 +689,9 @@
}
Mutex::Autolock _l(mLock);
+ // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger
mMasterMute = muted;
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterMute(muted);
return NO_ERROR;
@@ -652,12 +703,36 @@
return masterVolume_l();
}
+float AudioFlinger::masterVolumeSW() const
+{
+ Mutex::Autolock _l(mLock);
+ return masterVolumeSW_l();
+}
+
bool AudioFlinger::masterMute() const
{
Mutex::Autolock _l(mLock);
return masterMute_l();
}
+float AudioFlinger::masterVolume_l() const
+{
+ if (MVS_FULL == mMasterVolumeSupportLvl) {
+ float ret_val;
+ AutoMutex lock(mHardwareLock);
+
+ mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+ assert(NULL != mPrimaryHardwareDev);
+ assert(NULL != mPrimaryHardwareDev->get_master_volume);
+
+ mPrimaryHardwareDev->get_master_volume(mPrimaryHardwareDev, &ret_val);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret_val;
+ }
+
+ return mMasterVolume;
+}
+
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
@@ -683,7 +758,7 @@
mStreamTypes[stream].volume = value;
if (thread == NULL) {
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
}
} else {
@@ -729,7 +804,7 @@
}
volume = thread->streamVolume(stream);
} else {
- volume = mStreamTypes[stream].volume;
+ volume = streamVolume_l(stream);
}
return volume;
@@ -741,14 +816,15 @@
return true;
}
- return mStreamTypes[stream].mute;
+ AutoMutex lock(mLock);
+ return streamMute_l(stream);
}
status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
{
status_t result;
- ALOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d",
+ ALOGV("setParameters(): io %d, keyvalue %s, tid %d, calling pid %d",
ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
// check calling permissions
if (!settingsAllowed()) {
@@ -821,7 +897,7 @@
String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& keys) const
{
-// ALOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
+// ALOGV("getParameters() io %d, keys %s, tid %d, calling pid %d",
// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
if (ioHandle == 0) {
@@ -830,7 +906,7 @@
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
audio_hw_device_t *dev = mAudioHwDevs[i];
char *s = dev->get_parameters(dev, keys.string());
- out_s8 += String8(s);
+ out_s8 += String8(s ? s : "");
free(s);
}
return out_s8;
@@ -856,7 +932,11 @@
return 0;
}
- return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
+ size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return size;
}
unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
@@ -942,7 +1022,7 @@
{
Mutex::Autolock _l(mLock);
- int index = mNotificationClients.indexOfKey(pid);
+ ssize_t index = mNotificationClients.indexOfKey(pid);
if (index >= 0) {
sp <NotificationClient> client = mNotificationClients.valueFor(pid);
ALOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
@@ -950,9 +1030,9 @@
}
ALOGV("%d died, releasing its sessions", pid);
- int num = mAudioSessionRefs.size();
+ size_t num = mAudioSessionRefs.size();
bool removed = false;
- for (int i = 0; i< num; i++) {
+ for (size_t i = 0; i< num; ) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
ALOGV(" pid %d @ %d", ref->pid, i);
if (ref->pid == pid) {
@@ -960,8 +1040,9 @@
mAudioSessionRefs.removeAt(i);
delete ref;
removed = true;
- i--;
num--;
+ } else {
+ i++;
}
}
if (removed) {
@@ -998,7 +1079,7 @@
mChannelCount(0),
mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
mParamStatus(NO_ERROR),
- mStandby(false), mId(id), mExiting(false),
+ mStandby(false), mId(id),
mDevice(device),
mDeathRecipient(new PMDeathRecipient(this))
{
@@ -1017,17 +1098,23 @@
void AudioFlinger::ThreadBase::exit()
{
- // keep a strong ref on ourself so that we won't get
- // destroyed in the middle of requestExitAndWait()
- sp <ThreadBase> strongMe = this;
-
ALOGV("ThreadBase::exit");
{
+ // This lock prevents the following race in thread (uniprocessor for illustration):
+ // if (!exitPending()) {
+ // // context switch from here to exit()
+ // // exit() calls requestExit(), what exitPending() observes
+ // // exit() calls signal(), which is dropped since no waiters
+ // // context switch back from exit() to here
+ // mWaitWorkCV.wait(...);
+ // // now thread is hung
+ // }
AutoMutex lock(mLock);
- mExiting = true;
requestExit();
mWaitWorkCV.signal();
}
+ // When Thread::requestExitAndWait is made virtual and this method is renamed to
+ // "virtual status_t requestExitAndWait()", replace by "return Thread::requestExitAndWait();"
requestExitAndWait();
}
@@ -1246,7 +1333,7 @@
void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain)
{
- int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+ ssize_t index = mSuspendedSessions.indexOfKey(chain->sessionId());
if (index < 0) {
return;
}
@@ -1272,7 +1359,7 @@
bool suspend,
int sessionId)
{
- int index = mSuspendedSessions.indexOfKey(sessionId);
+ ssize_t index = mSuspendedSessions.indexOfKey(sessionId);
KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects;
@@ -1372,7 +1459,7 @@
mOutput(output),
// Assumes constructor is called by AudioFlinger with it's mLock held,
// but it would be safer to explicitly pass initial masterVolume as parameter
- mMasterVolume(audioFlinger->masterVolume_l()),
+ mMasterVolume(audioFlinger->masterVolumeSW_l()),
mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
{
snprintf(mName, kNameLength, "AudioOut_%d", id);
@@ -1383,11 +1470,13 @@
// There is no AUDIO_STREAM_MIN, and ++ operator does not compile
for (audio_stream_type_t stream = (audio_stream_type_t) 0; stream < AUDIO_STREAM_CNT;
stream = (audio_stream_type_t) (stream + 1)) {
- mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);
- mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);
+ mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
+ mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
// initialized by stream_type_t default constructor
// mStreamTypes[stream].valid = true;
}
+ // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here,
+ // because mAudioFlinger doesn't have one to copy from
}
AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -1488,6 +1577,7 @@
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
+ bool isTimed,
status_t *status)
{
sp<Track> track;
@@ -1524,12 +1614,11 @@
// all tracks in same audio session must share the same routing strategy otherwise
// conflicts will happen when tracks are moved from one output to another by audio policy
// manager
- uint32_t strategy =
- AudioSystem::getStrategyForStream((audio_stream_type_t)streamType);
+ uint32_t strategy = AudioSystem::getStrategyForStream(streamType);
for (size_t i = 0; i < mTracks.size(); ++i) {
sp<Track> t = mTracks[i];
if (t != 0) {
- uint32_t actual = AudioSystem::getStrategyForStream((audio_stream_type_t)t->type());
+ uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());
if (sessionId == t->sessionId() && strategy != actual) {
ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",
strategy, actual);
@@ -1539,9 +1628,14 @@
}
}
- track = new Track(this, client, streamType, sampleRate, format,
- channelMask, frameCount, sharedBuffer, sessionId);
- if (track->getCblk() == NULL || track->name() < 0) {
+ if (!isTimed) {
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelMask, frameCount, sharedBuffer, sessionId);
+ } else {
+ track = TimedTrack::create(this, client, streamType, sampleRate, format,
+ channelMask, frameCount, sharedBuffer, sessionId);
+ }
+ if (track == NULL || track->getCblk() == NULL || track->name() < 0) {
lStatus = NO_MEMORY;
goto Exit;
}
@@ -1551,7 +1645,7 @@
if (chain != 0) {
ALOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
track->setMainBuffer(chain->inBuffer());
- chain->setStrategy(AudioSystem::getStrategyForStream((audio_stream_type_t)track->type()));
+ chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
chain->incTrackCnt();
}
@@ -1582,40 +1676,36 @@
}
}
-status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
+void AudioFlinger::PlaybackThread::setMasterVolume(float value)
{
+ Mutex::Autolock _l(mLock);
mMasterVolume = value;
- return NO_ERROR;
}
-status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
+void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
{
- mMasterMute = muted;
- return NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ setMasterMute_l(muted);
}
-status_t AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
+ Mutex::Autolock _l(mLock);
mStreamTypes[stream].volume = value;
- return NO_ERROR;
}
-status_t AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
+void AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
{
+ Mutex::Autolock _l(mLock);
mStreamTypes[stream].mute = muted;
- return NO_ERROR;
}
float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) const
{
+ Mutex::Autolock _l(mLock);
return mStreamTypes[stream].volume;
}
-bool AudioFlinger::PlaybackThread::streamMute(audio_stream_type_t stream) const
-{
- return mStreamTypes[stream].mute;
-}
-
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
@@ -1781,7 +1871,7 @@
sp<Track> track = mTracks[i];
if (sessionId == track->sessionId() &&
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
- return AudioSystem::getStrategyForStream((audio_stream_type_t) track->type());
+ return AudioSystem::getStrategyForStream(track->streamType());
}
}
return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
@@ -1920,7 +2010,7 @@
if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
mSuspended)) {
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
+ ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended);
mOutput->stream->common.standby(&mOutput->stream->common);
mStandby = true;
mBytesWritten = 0;
@@ -1934,9 +2024,9 @@
releaseWakeLock_l();
// wait until we have something to do...
- ALOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
+ ALOGV("MixerThread %p TID %d going to sleep", this, gettid());
mWaitWorkCV.wait(mLock);
- ALOGV("MixerThread %p TID %d waking up\n", this, gettid());
+ ALOGV("MixerThread %p TID %d waking up", this, gettid());
acquireWakeLock_l();
mPrevMixerStatus = MIXER_IDLE;
@@ -1945,11 +2035,11 @@
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
ALOGD("Silence is golden");
- setMasterMute(true);
+ setMasterMute_l(true);
}
}
- standbyTime = systemTime() + kStandbyTimeInNsecs;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
sleepTime = idleSleepTime;
sleepTimeShift = 0;
continue;
@@ -1965,8 +2055,21 @@
}
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
+ // obtain the presentation timestamp of the next output buffer
+ int64_t pts;
+ status_t status = INVALID_OPERATION;
+
+ if (NULL != mOutput->stream->get_next_write_timestamp) {
+ status = mOutput->stream->get_next_write_timestamp(
+ mOutput->stream, &pts);
+ }
+
+ if (status != NO_ERROR) {
+ pts = AudioBufferProvider::kInvalidPTS;
+ }
+
// mix buffers...
- mAudioMixer->process();
+ mAudioMixer->process(pts);
// increase sleep time progressively when application underrun condition clears.
// Only increase sleep time if the mixer is ready for two consecutive times to avoid
// that a steady state of alternating ready/not ready conditions keeps the sleep time
@@ -1975,7 +2078,7 @@
sleepTimeShift--;
}
sleepTime = 0;
- standbyTime = systemTime() + kStandbyTimeInNsecs;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
//TODO: delay standby when effects have a tail
} else {
// If no tracks are ready, sleep once for the duration of an output
@@ -2122,7 +2225,7 @@
ALOG_ASSERT(minFrames <= cblk->frameCount);
}
}
- if ((cblk->framesReady() >= minFrames) && track->isReady() &&
+ if ((track->framesReady() >= minFrames) && track->isReady() &&
!track->isPaused() && !track->isTerminated())
{
//ALOGV("track %d u=%08x, s=%08x [OK] on thread %p", name, cblk->user, cblk->server, this);
@@ -2162,7 +2265,7 @@
// compute volume for this track
uint32_t vl, vr, va;
if (track->isMuted() || track->isPausing() ||
- mStreamTypes[track->type()].mute) {
+ mStreamTypes[track->streamType()].mute) {
vl = vr = va = 0;
if (track->isPausing()) {
track->setPaused();
@@ -2170,7 +2273,7 @@
} else {
// read original volumes with volume control
- float typeVolume = mStreamTypes[track->type()].volume;
+ float typeVolume = mStreamTypes[track->streamType()].volume;
float v = masterVolume * typeVolume;
uint32_t vlr = cblk->getVolumeLR();
vl = vlr & 0xFFFF;
@@ -2192,7 +2295,7 @@
uint16_t sendLevel = cblk->getSendLevel_U4_12();
// send level comes from shared memory and so may be corrupt
- if (sendLevel >= MAX_GAIN_INT) {
+ if (sendLevel > MAX_GAIN_INT) {
ALOGV("Track send level out of range: %04X", sendLevel);
sendLevel = MAX_GAIN_INT;
}
@@ -2213,25 +2316,21 @@
}
// Convert volumes from 8.24 to 4.12 format
- int16_t left, right, aux;
// This additional clamping is needed in case chain->setVolume_l() overshot
- uint32_t v_clamped = (vl + (1 << 11)) >> 12;
- if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
- left = int16_t(v_clamped);
- v_clamped = (vr + (1 << 11)) >> 12;
- if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
- right = int16_t(v_clamped);
+ vl = (vl + (1 << 11)) >> 12;
+ if (vl > MAX_GAIN_INT) vl = MAX_GAIN_INT;
+ vr = (vr + (1 << 11)) >> 12;
+ if (vr > MAX_GAIN_INT) vr = MAX_GAIN_INT;
- if (va > MAX_GAIN_INT) va = MAX_GAIN_INT;
- aux = int16_t(va);
+ if (va > MAX_GAIN_INT) va = MAX_GAIN_INT; // va is uint32_t, so no need to check for -
// XXX: these things DON'T need to be done each time
mAudioMixer->setBufferProvider(name, track);
mAudioMixer->enable(name);
- mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)left);
- mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)right);
- mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)aux);
+ mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)vl);
+ mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)vr);
+ mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)va);
mAudioMixer->setParameter(
name,
AudioMixer::TRACK,
@@ -2331,7 +2430,7 @@
size_t size = mTracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (t->type() == streamType) {
+ if (t->streamType() == streamType) {
android_atomic_or(CBLK_INVALID_ON, &t->mCblk->flags);
t->mCblk->cv.signal();
}
@@ -2505,21 +2604,6 @@
{
}
-static inline
-int32_t mul(int16_t in, int16_t v)
-{
-#if defined(__arm__) && !defined(__thumb__)
- int32_t out;
- asm( "smulbb %[out], %[in], %[v] \n"
- : [out]"=r"(out)
- : [in]"%r"(in), [v]"r"(v)
- : );
- return out;
-#else
- return in * int32_t(v);
-#endif
-}
-
void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
{
// Do not apply volume on compressed audio
@@ -2600,7 +2684,6 @@
sp<Track> trackToRemove;
sp<Track> activeTrack;
nsecs_t standbyTime = systemTime();
- int8_t *curBuf;
size_t mixBufferSize = mFrameCount*mFrameSize;
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
@@ -2638,7 +2721,7 @@
mSuspended)) {
// wait until we have something to do...
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p\n", this);
+ ALOGV("Audio hardware entering standby, mixer %p", this);
mOutput->stream->common.standby(&mOutput->stream->common);
mStandby = true;
mBytesWritten = 0;
@@ -2651,9 +2734,9 @@
if (exitPending()) break;
releaseWakeLock_l();
- ALOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
+ ALOGV("DirectOutputThread %p TID %d going to sleep", this, gettid());
mWaitWorkCV.wait(mLock);
- ALOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+ ALOGV("DirectOutputThread %p TID %d waking up in active mode", this, gettid());
acquireWakeLock_l();
if (!mMasterMute) {
@@ -2661,7 +2744,7 @@
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
ALOGD("Silence is golden");
- setMasterMute(true);
+ setMasterMute_l(true);
}
}
@@ -2704,13 +2787,13 @@
// compute volume for this track
float left, right;
if (track->isMuted() || mMasterMute || track->isPausing() ||
- mStreamTypes[track->type()].mute) {
+ mStreamTypes[track->streamType()].mute) {
left = right = 0;
if (track->isPausing()) {
track->setPaused();
}
} else {
- float typeVolume = mStreamTypes[track->type()].volume;
+ float typeVolume = mStreamTypes[track->streamType()].volume;
float v = mMasterVolume * typeVolume;
uint32_t vlr = cblk->getVolumeLR();
float v_clamped = v * (vlr & 0xFFFF);
@@ -2804,11 +2887,12 @@
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
AudioBufferProvider::Buffer buffer;
size_t frameCount = mFrameCount;
- curBuf = (int8_t *)mMixBuffer;
+ int8_t *curBuf = (int8_t *)mMixBuffer;
// output audio to hardware
while (frameCount) {
buffer.frameCount = frameCount;
- activeTrack->getNextBuffer(&buffer);
+ activeTrack->getNextBuffer(&buffer,
+ AudioBufferProvider::kInvalidPTS);
if (CC_UNLIKELY(buffer.raw == NULL)) {
memset(curBuf, 0, frameCount * mFrameSize);
break;
@@ -3046,9 +3130,9 @@
if (exitPending()) break;
releaseWakeLock_l();
- ALOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
+ ALOGV("DuplicatingThread %p TID %d going to sleep", this, gettid());
mWaitWorkCV.wait(mLock);
- ALOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+ ALOGV("DuplicatingThread %p TID %d waking up", this, gettid());
acquireWakeLock_l();
mPrevMixerStatus = MIXER_IDLE;
@@ -3057,11 +3141,11 @@
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
ALOGD("Silence is golden");
- setMasterMute(true);
+ setMasterMute_l(true);
}
}
- standbyTime = systemTime() + kStandbyTimeInNsecs;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
sleepTime = idleSleepTime;
continue;
}
@@ -3078,7 +3162,7 @@
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
if (outputsReady(outputTracks)) {
- mAudioMixer->process();
+ mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
} else {
memset(mMixBuffer, 0, mixBufferSize);
}
@@ -3115,7 +3199,7 @@
// enable changes in effect chain
unlockEffectChains(effectChains);
- standbyTime = systemTime() + kStandbyTimeInNsecs;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
for (size_t i = 0; i < outputTracks.size(); i++) {
outputTracks[i]->write(mMixBuffer, writeFrames);
}
@@ -3145,6 +3229,7 @@
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
+ // FIXME explain this formula
int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
this,
@@ -3164,7 +3249,7 @@
{
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mOutputTracks.size(); i++) {
- if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
+ if (mOutputTracks[i]->thread() == thread) {
mOutputTracks[i]->destroy();
mOutputTracks.removeAt(i);
updateWaitTime();
@@ -3391,7 +3476,7 @@
mName = playbackThread->getTrackName_l();
mMainBuffer = playbackThread->mixBuffer();
}
- ALOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ ALOGV("Track constructor name %d, calling pid %d", mName, IPCThreadState::self()->getCallingPid());
if (mName < 0) {
ALOGE("no more track names available");
}
@@ -3416,7 +3501,7 @@
{
// NOTE: destroyTrack_l() can remove a strong reference to this Track
// by removing it from mTracks vector, so there is a risk that this Tracks's
- // desctructor is called. As the destructor needs to lock mLock,
+ // destructor is called. As the destructor needs to lock mLock,
// we must acquire a strong reference on this Track before locking mLock
// here so that the destructor is called only when exiting this function.
// On the other hand, as long as Track::destroy() is only called by
@@ -3428,9 +3513,7 @@
if (thread != 0) {
if (!isOutputTrack()) {
if (mState == ACTIVE || mState == RESUMING) {
- AudioSystem::stopOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
// to track the speaker usage
addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
@@ -3449,7 +3532,7 @@
uint32_t vlr = mCblk->getVolumeLR();
snprintf(buffer, size, " %05d %05d %03u %03u 0x%08x %05u %04u %1d %1d %1d %05u %05u %05u 0x%08x 0x%08x 0x%08x 0x%08x\n",
mName - AudioMixer::TRACK0,
- (mClient == 0) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid_cached : mClient->pid(),
mStreamType,
mFormat,
mChannelMask,
@@ -3467,7 +3550,8 @@
(int)mAuxBuffer);
}
-status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
+ AudioBufferProvider::Buffer* buffer, int64_t pts)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
@@ -3508,10 +3592,14 @@
return NOT_ENOUGH_DATA;
}
+uint32_t AudioFlinger::PlaybackThread::Track::framesReady() const{
+ return mCblk->framesReady();
+}
+
bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) return true;
- if (mCblk->framesReady() >= mCblk->frameCount ||
+ if (framesReady() >= mCblk->frameCount ||
(mCblk->flags & CBLK_FORCEREADY_MSK)) {
mFillingUpStatus = FS_FILLED;
android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags);
@@ -3520,11 +3608,11 @@
return false;
}
-status_t AudioFlinger::PlaybackThread::Track::start()
+status_t AudioFlinger::PlaybackThread::Track::start(pid_t tid)
{
status_t status = NO_ERROR;
- ALOGV("start(%d), calling thread %d session %d",
- mName, IPCThreadState::self()->getCallingPid(), mSessionId);
+ ALOGV("start(%d), calling pid %d session %d tid %d",
+ mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid);
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -3541,9 +3629,7 @@
if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
thread->mLock.unlock();
- status = AudioSystem::startOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ status = AudioSystem::startOutput(thread->id(), mStreamType, mSessionId);
thread->mLock.lock();
// to track the speaker usage
@@ -3565,7 +3651,7 @@
void AudioFlinger::PlaybackThread::Track::stop()
{
- ALOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ ALOGV("stop(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -3581,9 +3667,7 @@
}
if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
thread->mLock.unlock();
- AudioSystem::stopOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
thread->mLock.lock();
// to track the speaker usage
@@ -3594,7 +3678,7 @@
void AudioFlinger::PlaybackThread::Track::pause()
{
- ALOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ ALOGV("pause(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -3603,9 +3687,7 @@
ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
if (!isOutputTrack()) {
thread->mLock.unlock();
- AudioSystem::stopOutput(thread->id(),
- (audio_stream_type_t)mStreamType,
- mSessionId);
+ AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
thread->mLock.lock();
// to track the speaker usage
@@ -3674,6 +3756,406 @@
mAuxBuffer = buffer;
}
+// timed audio tracks
+
+sp<AudioFlinger::PlaybackThread::TimedTrack>
+AudioFlinger::PlaybackThread::TimedTrack::create(
+ const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ audio_stream_type_t streamType,
+ uint32_t sampleRate,
+ audio_format_t format,
+ uint32_t channelMask,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ int sessionId) {
+ if (!client->reserveTimedTrack())
+ return NULL;
+
+ sp<TimedTrack> track = new TimedTrack(
+ thread, client, streamType, sampleRate, format, channelMask, frameCount,
+ sharedBuffer, sessionId);
+
+ if (track == NULL) {
+ client->releaseTimedTrack();
+ return NULL;
+ }
+
+ return track;
+}
+
+AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
+ const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ audio_stream_type_t streamType,
+ uint32_t sampleRate,
+ audio_format_t format,
+ uint32_t channelMask,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ int sessionId)
+ : Track(thread, client, streamType, sampleRate, format, channelMask,
+ frameCount, sharedBuffer, sessionId),
+ mTimedSilenceBuffer(NULL),
+ mTimedSilenceBufferSize(0),
+ mTimedAudioOutputOnTime(false),
+ mMediaTimeTransformValid(false)
+{
+ LocalClock lc;
+ mLocalTimeFreq = lc.getLocalFreq();
+
+ mLocalTimeToSampleTransform.a_zero = 0;
+ mLocalTimeToSampleTransform.b_zero = 0;
+ mLocalTimeToSampleTransform.a_to_b_numer = sampleRate;
+ mLocalTimeToSampleTransform.a_to_b_denom = mLocalTimeFreq;
+ LinearTransform::reduce(&mLocalTimeToSampleTransform.a_to_b_numer,
+ &mLocalTimeToSampleTransform.a_to_b_denom);
+}
+
+AudioFlinger::PlaybackThread::TimedTrack::~TimedTrack() {
+ mClient->releaseTimedTrack();
+ delete [] mTimedSilenceBuffer;
+}
+
+status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer(
+ size_t size, sp<IMemory>* buffer) {
+
+ Mutex::Autolock _l(mTimedBufferQueueLock);
+
+ trimTimedBufferQueue_l();
+
+ // lazily initialize the shared memory heap for timed buffers
+ if (mTimedMemoryDealer == NULL) {
+ const int kTimedBufferHeapSize = 512 << 10;
+
+ mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize,
+ "AudioFlingerTimed");
+ if (mTimedMemoryDealer == NULL)
+ return NO_MEMORY;
+ }
+
+ sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size);
+ if (newBuffer == NULL) {
+ newBuffer = mTimedMemoryDealer->allocate(size);
+ if (newBuffer == NULL)
+ return NO_MEMORY;
+ }
+
+ *buffer = newBuffer;
+ return NO_ERROR;
+}
+
+// caller must hold mTimedBufferQueueLock
+void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueue_l() {
+ int64_t mediaTimeNow;
+ {
+ Mutex::Autolock mttLock(mMediaTimeTransformLock);
+ if (!mMediaTimeTransformValid)
+ return;
+
+ int64_t targetTimeNow;
+ status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME)
+ ? mCCHelper.getCommonTime(&targetTimeNow)
+ : mCCHelper.getLocalTime(&targetTimeNow);
+
+ if (OK != res)
+ return;
+
+ if (!mMediaTimeTransform.doReverseTransform(targetTimeNow,
+ &mediaTimeNow)) {
+ return;
+ }
+ }
+
+ size_t trimIndex;
+ for (trimIndex = 0; trimIndex < mTimedBufferQueue.size(); trimIndex++) {
+ if (mTimedBufferQueue[trimIndex].pts() > mediaTimeNow)
+ break;
+ }
+
+ if (trimIndex) {
+ mTimedBufferQueue.removeItemsAt(0, trimIndex);
+ }
+}
+
+status_t AudioFlinger::PlaybackThread::TimedTrack::queueTimedBuffer(
+ const sp<IMemory>& buffer, int64_t pts) {
+
+ {
+ Mutex::Autolock mttLock(mMediaTimeTransformLock);
+ if (!mMediaTimeTransformValid)
+ return INVALID_OPERATION;
+ }
+
+ Mutex::Autolock _l(mTimedBufferQueueLock);
+
+ mTimedBufferQueue.add(TimedBuffer(buffer, pts));
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::PlaybackThread::TimedTrack::setMediaTimeTransform(
+ const LinearTransform& xform, TimedAudioTrack::TargetTimeline target) {
+
+ ALOGV("%s az=%lld bz=%lld n=%d d=%u tgt=%d", __PRETTY_FUNCTION__,
+ xform.a_zero, xform.b_zero, xform.a_to_b_numer, xform.a_to_b_denom,
+ target);
+
+ if (!(target == TimedAudioTrack::LOCAL_TIME ||
+ target == TimedAudioTrack::COMMON_TIME)) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMediaTimeTransformLock);
+ mMediaTimeTransform = xform;
+ mMediaTimeTransformTarget = target;
+ mMediaTimeTransformValid = true;
+
+ return NO_ERROR;
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+// implementation of getNextBuffer for tracks whose buffers have timestamps
+status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
+ AudioBufferProvider::Buffer* buffer, int64_t pts)
+{
+ if (pts == AudioBufferProvider::kInvalidPTS) {
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return INVALID_OPERATION;
+ }
+
+ // get ahold of the output stream that these samples will be written to
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread == NULL) {
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return INVALID_OPERATION;
+ }
+ PlaybackThread* playbackThread = static_cast<PlaybackThread*>(thread.get());
+
+ Mutex::Autolock _l(mTimedBufferQueueLock);
+
+ while (true) {
+
+ // if we have no timed buffers, then fail
+ if (mTimedBufferQueue.isEmpty()) {
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+ }
+
+ TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
+
+ // calculate the PTS of the head of the timed buffer queue expressed in
+ // local time
+ int64_t headLocalPTS;
+ {
+ Mutex::Autolock mttLock(mMediaTimeTransformLock);
+
+ assert(mMediaTimeTransformValid);
+
+ if (mMediaTimeTransform.a_to_b_denom == 0) {
+ // the transform represents a pause, so yield silence
+ timedYieldSilence(buffer->frameCount, buffer);
+ return NO_ERROR;
+ }
+
+ int64_t transformedPTS;
+ if (!mMediaTimeTransform.doForwardTransform(head.pts(),
+ &transformedPTS)) {
+ // the transform failed. this shouldn't happen, but if it does
+ // then just drop this buffer
+ ALOGW("timedGetNextBuffer transform failed");
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ mTimedBufferQueue.removeAt(0);
+ return NO_ERROR;
+ }
+
+ if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
+ if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
+ &headLocalPTS)) {
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return INVALID_OPERATION;
+ }
+ } else {
+ headLocalPTS = transformedPTS;
+ }
+ }
+
+ // adjust the head buffer's PTS to reflect the portion of the head buffer
+ // that has already been consumed
+ int64_t effectivePTS = headLocalPTS +
+ ((head.position() / mCblk->frameSize) * mLocalTimeFreq / sampleRate());
+
+ // Calculate the delta in samples between the head of the input buffer
+ // queue and the start of the next output buffer that will be written.
+ // If the transformation fails because of over or underflow, it means
+ // that the sample's position in the output stream is so far out of
+ // whack that it should just be dropped.
+ int64_t sampleDelta;
+ if (llabs(effectivePTS - pts) >= (static_cast<int64_t>(1) << 31)) {
+ ALOGV("*** head buffer is too far from PTS: dropped buffer");
+ mTimedBufferQueue.removeAt(0);
+ continue;
+ }
+ if (!mLocalTimeToSampleTransform.doForwardTransform(
+ (effectivePTS - pts) << 32, &sampleDelta)) {
+ ALOGV("*** too late during sample rate transform: dropped buffer");
+ mTimedBufferQueue.removeAt(0);
+ continue;
+ }
+
+ ALOGV("*** %s head.pts=%lld head.pos=%d pts=%lld sampleDelta=[%d.%08x]",
+ __PRETTY_FUNCTION__, head.pts(), head.position(), pts,
+ static_cast<int32_t>((sampleDelta >= 0 ? 0 : 1) + (sampleDelta >> 32)),
+ static_cast<uint32_t>(sampleDelta & 0xFFFFFFFF));
+
+ // if the delta between the ideal placement for the next input sample and
+ // the current output position is within this threshold, then we will
+ // concatenate the next input samples to the previous output
+ const int64_t kSampleContinuityThreshold =
+ (static_cast<int64_t>(sampleRate()) << 32) / 10;
+
+ // if this is the first buffer of audio that we're emitting from this track
+ // then it should be almost exactly on time.
+ const int64_t kSampleStartupThreshold = 1LL << 32;
+
+ if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) ||
+ (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) {
+ // the next input is close enough to being on time, so concatenate it
+ // with the last output
+ timedYieldSamples(buffer);
+
+ ALOGV("*** on time: head.pos=%d frameCount=%u", head.position(), buffer->frameCount);
+ return NO_ERROR;
+ } else if (sampleDelta > 0) {
+ // the gap between the current output position and the proper start of
+ // the next input sample is too big, so fill it with silence
+ uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32;
+
+ timedYieldSilence(framesUntilNextInput, buffer);
+ ALOGV("*** silence: frameCount=%u", buffer->frameCount);
+ return NO_ERROR;
+ } else {
+ // the next input sample is late
+ uint32_t lateFrames = static_cast<uint32_t>(-((sampleDelta + 0x80000000) >> 32));
+ size_t onTimeSamplePosition =
+ head.position() + lateFrames * mCblk->frameSize;
+
+ if (onTimeSamplePosition > head.buffer()->size()) {
+ // all the remaining samples in the head are too late, so
+ // drop it and move on
+ ALOGV("*** too late: dropped buffer");
+ mTimedBufferQueue.removeAt(0);
+ continue;
+ } else {
+ // skip over the late samples
+ head.setPosition(onTimeSamplePosition);
+
+ // yield the available samples
+ timedYieldSamples(buffer);
+
+ ALOGV("*** late: head.pos=%d frameCount=%u", head.position(), buffer->frameCount);
+ return NO_ERROR;
+ }
+ }
+ }
+}
+
+// Yield samples from the timed buffer queue head up to the given output
+// buffer's capacity.
+//
+// Caller must hold mTimedBufferQueueLock
+void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSamples(
+ AudioBufferProvider::Buffer* buffer) {
+
+ const TimedBuffer& head = mTimedBufferQueue[0];
+
+ buffer->raw = (static_cast<uint8_t*>(head.buffer()->pointer()) +
+ head.position());
+
+ uint32_t framesLeftInHead = ((head.buffer()->size() - head.position()) /
+ mCblk->frameSize);
+ size_t framesRequested = buffer->frameCount;
+ buffer->frameCount = min(framesLeftInHead, framesRequested);
+
+ mTimedAudioOutputOnTime = true;
+}
+
+// Yield samples of silence up to the given output buffer's capacity
+//
+// Caller must hold mTimedBufferQueueLock
+void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSilence(
+ uint32_t numFrames, AudioBufferProvider::Buffer* buffer) {
+
+ // lazily allocate a buffer filled with silence
+ if (mTimedSilenceBufferSize < numFrames * mCblk->frameSize) {
+ delete [] mTimedSilenceBuffer;
+ mTimedSilenceBufferSize = numFrames * mCblk->frameSize;
+ mTimedSilenceBuffer = new uint8_t[mTimedSilenceBufferSize];
+ memset(mTimedSilenceBuffer, 0, mTimedSilenceBufferSize);
+ }
+
+ buffer->raw = mTimedSilenceBuffer;
+ size_t framesRequested = buffer->frameCount;
+ buffer->frameCount = min(numFrames, framesRequested);
+
+ mTimedAudioOutputOnTime = false;
+}
+
+void AudioFlinger::PlaybackThread::TimedTrack::releaseBuffer(
+ AudioBufferProvider::Buffer* buffer) {
+
+ Mutex::Autolock _l(mTimedBufferQueueLock);
+
+ // If the buffer which was just released is part of the buffer at the head
+ // of the queue, be sure to update the amt of the buffer which has been
+ // consumed. If the buffer being returned is not part of the head of the
+ // queue, its either because the buffer is part of the silence buffer, or
+ // because the head of the timed queue was trimmed after the mixer called
+ // getNextBuffer but before the mixer called releaseBuffer.
+ if ((buffer->raw != mTimedSilenceBuffer) && mTimedBufferQueue.size()) {
+ TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
+
+ void* start = head.buffer()->pointer();
+ void* end = head.buffer()->pointer() + head.buffer()->size();
+
+ if ((buffer->raw >= start) && (buffer->raw <= end)) {
+ head.setPosition(head.position() +
+ (buffer->frameCount * mCblk->frameSize));
+ if (static_cast<size_t>(head.position()) >= head.buffer()->size()) {
+ mTimedBufferQueue.removeAt(0);
+ }
+ }
+ }
+
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+}
+
+uint32_t AudioFlinger::PlaybackThread::TimedTrack::framesReady() const {
+ Mutex::Autolock _l(mTimedBufferQueueLock);
+
+ uint32_t frames = 0;
+ for (size_t i = 0; i < mTimedBufferQueue.size(); i++) {
+ const TimedBuffer& tb = mTimedBufferQueue[i];
+ frames += (tb.buffer()->size() - tb.position()) / mCblk->frameSize;
+ }
+
+ return frames;
+}
+
+AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer()
+ : mPTS(0), mPosition(0) {}
+
+AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer(
+ const sp<IMemory>& buffer, int64_t pts)
+ : mBuffer(buffer), mPTS(pts), mPosition(0) {}
+
// ----------------------------------------------------------------------------
// RecordTrack constructor must be called with AudioFlinger::mLock held
@@ -3710,7 +4192,7 @@
}
}
-status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesAvail;
@@ -3749,12 +4231,12 @@
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::RecordThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start(pid_t tid)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
- return recordThread->start(this);
+ return recordThread->start(this, tid);
} else {
return BAD_VALUE;
}
@@ -3776,7 +4258,7 @@
void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x\n",
- (mClient == 0) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid_cached : mClient->pid(),
mFormat,
mChannelMask,
mSessionId,
@@ -3821,9 +4303,9 @@
clearBufferQueue();
}
-status_t AudioFlinger::PlaybackThread::OutputTrack::start()
+status_t AudioFlinger::PlaybackThread::OutputTrack::start(pid_t tid)
{
- status_t status = Track::start();
+ status_t status = Track::start(tid);
if (status != NO_ERROR) {
return status;
}
@@ -3853,7 +4335,7 @@
uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
if (!mActive && frames != 0) {
- start();
+ start(0);
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
MixerThread *mixerThread = (MixerThread *)thread.get();
@@ -4015,10 +4497,9 @@
void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
{
size_t size = mBufferQueue.size();
- Buffer *pBuffer;
for (size_t i = 0; i < size; i++) {
- pBuffer = mBufferQueue.itemAt(i);
+ Buffer *pBuffer = mBufferQueue.itemAt(i);
delete [] pBuffer->mBuffer;
delete pBuffer;
}
@@ -4030,8 +4511,10 @@
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
: RefBase(),
mAudioFlinger(audioFlinger),
+ // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
- mPid(pid)
+ mPid(pid),
+ mTimedTrackCount(0)
{
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
}
@@ -4047,6 +4530,31 @@
return mMemoryDealer;
}
+// Reserve one of the limited slots for a timed audio track associated
+// with this client
+bool AudioFlinger::Client::reserveTimedTrack()
+{
+ const int kMaxTimedTracksPerClient = 4;
+
+ Mutex::Autolock _l(mTimedTrackLock);
+
+ if (mTimedTrackCount >= kMaxTimedTracksPerClient) {
+ ALOGW("can not create timed track - pid %d has exceeded the limit",
+ mPid);
+ return false;
+ }
+
+ mTimedTrackCount++;
+ return true;
+}
+
+// Release a slot for a timed audio track
+void AudioFlinger::Client::releaseTimedTrack()
+{
+ Mutex::Autolock _l(mTimedTrackLock);
+ mTimedTrackCount--;
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
@@ -4063,9 +4571,7 @@
void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
{
sp<NotificationClient> keep(this);
- {
- mAudioFlinger->removeNotificationClient(mPid);
- }
+ mAudioFlinger->removeNotificationClient(mPid);
}
// ----------------------------------------------------------------------------
@@ -4088,8 +4594,8 @@
return mTrack->getCblk();
}
-status_t AudioFlinger::TrackHandle::start() {
- return mTrack->start();
+status_t AudioFlinger::TrackHandle::start(pid_t tid) {
+ return mTrack->start(tid);
}
void AudioFlinger::TrackHandle::stop() {
@@ -4113,6 +4619,38 @@
return mTrack->attachAuxEffect(EffectId);
}
+status_t AudioFlinger::TrackHandle::allocateTimedBuffer(size_t size,
+ sp<IMemory>* buffer) {
+ if (!mTrack->isTimedTrack())
+ return INVALID_OPERATION;
+
+ PlaybackThread::TimedTrack* tt =
+ reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
+ return tt->allocateTimedBuffer(size, buffer);
+}
+
+status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer,
+ int64_t pts) {
+ if (!mTrack->isTimedTrack())
+ return INVALID_OPERATION;
+
+ PlaybackThread::TimedTrack* tt =
+ reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
+ return tt->queueTimedBuffer(buffer, pts);
+}
+
+status_t AudioFlinger::TrackHandle::setMediaTimeTransform(
+ const LinearTransform& xform, int target) {
+
+ if (!mTrack->isTimedTrack())
+ return INVALID_OPERATION;
+
+ PlaybackThread::TimedTrack* tt =
+ reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
+ return tt->setMediaTimeTransform(
+ xform, static_cast<TimedAudioTrack::TargetTimeline>(target));
+}
+
status_t AudioFlinger::TrackHandle::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -4211,9 +4749,9 @@
return mRecordTrack->getCblk();
}
-status_t AudioFlinger::RecordHandle::start() {
+status_t AudioFlinger::RecordHandle::start(pid_t tid) {
ALOGV("RecordHandle::start()");
- return mRecordTrack->start();
+ return mRecordTrack->start(tid);
}
void AudioFlinger::RecordHandle::stop() {
@@ -4342,7 +4880,8 @@
}
buffer.frameCount = mFrameCount;
- if (CC_LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ if (CC_LIKELY(mActiveTrack->getNextBuffer(
+ &buffer, AudioBufferProvider::kInvalidPTS) == NO_ERROR)) {
size_t framesOut = buffer.frameCount;
if (mResampler == NULL) {
// no resampling
@@ -4505,9 +5044,9 @@
return track;
}
-status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
+status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack, pid_t tid)
{
- ALOGV("RecordThread::start");
+ ALOGV("RecordThread::start tid=%d", tid);
sp <ThreadBase> strongMe = this;
status_t status = NO_ERROR;
{
@@ -4540,7 +5079,7 @@
ALOGV("Signal record thread");
mWaitWorkCV.signal();
// do not wait for mStartStopCond if exiting
- if (mExiting) {
+ if (exitPending()) {
mActiveTrack.clear();
status = INVALID_OPERATION;
goto startError;
@@ -4567,7 +5106,7 @@
if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
mActiveTrack->mState = TrackBase::PAUSING;
// do not wait for mStartStopCond if exiting
- if (mExiting) {
+ if (exitPending()) {
return;
}
mStartStopCond.wait(mLock);
@@ -4620,7 +5159,7 @@
return NO_ERROR;
}
-status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts)
{
size_t framesReq = buffer->frameCount;
size_t framesReady = mFrameCount - mRsmpInIndex;
@@ -4691,7 +5230,7 @@
}
if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
// do not accept frame count changes if tracks are open as the track buffer
- // size depends on frame count and correct behavior would not be garantied
+ // size depends on frame count and correct behavior would not be guaranteed
// if frame count is changed after track creation
if (mActiveTrack != 0) {
status = INVALID_OPERATION;
@@ -5008,11 +5547,12 @@
}
}
}
- void *param2 = NULL;
- audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2);
+ audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL);
mPlaybackThreads.removeItem(output);
}
thread->exit();
+ // The thread entity (active unit of execution) is no longer running here,
+ // but the ThreadBase container still exists.
if (thread->type() != ThreadBase::DUPLICATING) {
AudioStreamOut *out = thread->clearOutput();
@@ -5151,11 +5691,12 @@
}
ALOGV("closeInput() %d", input);
- void *param2 = NULL;
- audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2);
+ audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, NULL);
mRecordThreads.removeItem(input);
}
thread->exit();
+ // The thread entity (active unit of execution) is no longer running here,
+ // but the ThreadBase container still exists.
AudioStreamIn *in = thread->clearInput();
assert(in != NULL);
@@ -5182,8 +5723,7 @@
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
- if (thread != dstThread &&
- thread->type() != ThreadBase::DIRECT) {
+ if (thread != dstThread && thread->type() != ThreadBase::DIRECT) {
MixerThread *srcThread = (MixerThread *)thread;
srcThread->setStreamValid(stream, false);
srcThread->invalidateTracks(stream);
@@ -5204,8 +5744,8 @@
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d", audioSession, caller);
- int num = mAudioSessionRefs.size();
- for (int i = 0; i< num; i++) {
+ size_t num = mAudioSessionRefs.size();
+ for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
if (ref->sessionid == audioSession && ref->pid == caller) {
ref->cnt++;
@@ -5222,8 +5762,8 @@
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("releasing %d from %d", audioSession, caller);
- int num = mAudioSessionRefs.size();
- for (int i = 0; i< num; i++) {
+ size_t num = mAudioSessionRefs.size();
+ for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
if (ref->sessionid == audioSession && ref->pid == caller) {
ref->cnt--;
@@ -5306,33 +5846,20 @@
// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
{
- PlaybackThread *thread = NULL;
- if (mPlaybackThreads.indexOfKey(output) >= 0) {
- thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
- }
- return thread;
+ return mPlaybackThreads.valueFor(output).get();
}
// checkMixerThread_l() must be called with AudioFlinger::mLock held
AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(audio_io_handle_t output) const
{
PlaybackThread *thread = checkPlaybackThread_l(output);
- if (thread != NULL) {
- if (thread->type() == ThreadBase::DIRECT) {
- thread = NULL;
- }
- }
- return (MixerThread *)thread;
+ return thread != NULL && thread->type() != ThreadBase::DIRECT ? (MixerThread *) thread : NULL;
}
// checkRecordThread_l() must be called with AudioFlinger::mLock held
AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(audio_io_handle_t input) const
{
- RecordThread *thread = NULL;
- if (mRecordThreads.indexOfKey(input) >= 0) {
- thread = (RecordThread *)mRecordThreads.valueFor(input).get();
- }
- return thread;
+ return mRecordThreads.valueFor(input).get();
}
uint32_t AudioFlinger::nextUniqueId()
@@ -5419,7 +5946,7 @@
// Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
// that can only be created by audio policy manager (running in same process)
- if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid() != pid) {
+ if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid_cached != pid) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
@@ -5695,10 +6222,7 @@
goto Exit;
}
// Only Pre processor effects are allowed on input threads and only on input threads
- if ((mType == RECORD &&
- (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) ||
- (mType != RECORD &&
- (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
+ if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d",
desc->name, desc->flags, mType);
lStatus = BAD_VALUE;
@@ -5885,13 +6409,13 @@
void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
const wp<EffectHandle>& handle,
- bool unpiniflast) {
+ bool unpinIfLast) {
Mutex::Autolock _l(mLock);
ALOGV("disconnectEffect() %p effect %p", this, effect.get());
// delete the effect module if removing last handle on it
if (effect->removeHandle(handle) == 0) {
- if (!effect->isPinned() || unpiniflast) {
+ if (!effect->isPinned() || unpinIfLast) {
removeEffect_l(effect);
AudioSystem::unregisterEffect(effect->id());
}
@@ -6135,7 +6659,6 @@
status_t status;
Mutex::Autolock _l(mLock);
- // First handle in mHandles has highest priority and controls the effect module
int priority = handle->priority();
size_t size = mHandles.size();
sp<EffectHandle> h;
@@ -6207,16 +6730,16 @@
return mHandles.size() != 0 ? mHandles[0].promote() : 0;
}
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpiniflast)
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
{
- ALOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
+ ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
// keep a strong reference on this EffectModule to avoid calling the
// destructor before we exit
sp<EffectModule> keep(this);
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
- thread->disconnectEffect(keep, handle, unpiniflast);
+ thread->disconnectEffect(keep, handle, unpinIfLast);
}
}
}
@@ -6888,13 +7411,13 @@
disconnect(true);
}
-void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
+void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
{
- ALOGV("disconnect(%s)", unpiniflast ? "true" : "false");
+ ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false");
if (mEffect == 0) {
return;
}
- mEffect->disconnect(this, unpiniflast);
+ mEffect->disconnect(this, unpinIfLast);
if (mHasControl && mEnabled) {
sp<ThreadBase> thread = mEffect->thread().promote();
@@ -7037,7 +7560,7 @@
bool locked = mCblk != NULL && tryLock(mCblk->lock);
snprintf(buffer, size, "\t\t\t%05d %05d %01u %01u %05u %05u\n",
- (mClient == 0) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid_cached : mClient->pid(),
mPriority,
mHasControl,
!locked,
@@ -7205,12 +7728,12 @@
// Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is
// already present
- int size = (int)mEffects.size();
- int idx_insert = size;
- int idx_insert_first = -1;
- int idx_insert_last = -1;
+ size_t size = mEffects.size();
+ size_t idx_insert = size;
+ ssize_t idx_insert_first = -1;
+ ssize_t idx_insert_last = -1;
- for (int i = 0; i < size; i++) {
+ for (size_t i = 0; i < size; i++) {
effect_descriptor_t d = mEffects[i]->desc();
uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK;
uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK;
@@ -7279,11 +7802,10 @@
size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
{
Mutex::Autolock _l(mLock);
- int size = (int)mEffects.size();
- int i;
+ size_t size = mEffects.size();
uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK;
- for (i = 0; i < size; i++) {
+ for (size_t i = 0; i < size; i++) {
if (effect == mEffects[i]) {
// calling stop here will remove pre-processing effect from the audio HAL.
// This is safe as we hold the EffectChain mutex which guarantees that we are not in
@@ -7430,7 +7952,7 @@
sp<SuspendedEffectDesc> desc;
// use effect type UUID timelow as key as there is no real risk of identical
// timeLow fields among effect type UUIDs.
- int index = mSuspendedEffects.indexOfKey(type->timeLow);
+ ssize_t index = mSuspendedEffects.indexOfKey(type->timeLow);
if (suspend) {
if (index >= 0) {
desc = mSuspendedEffects.valueAt(index);
@@ -7480,7 +8002,7 @@
{
sp<SuspendedEffectDesc> desc;
- int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+ ssize_t index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
if (suspend) {
if (index >= 0) {
desc = mSuspendedEffects.valueAt(index);
@@ -7562,7 +8084,7 @@
void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
bool enabled)
{
- int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+ ssize_t index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
if (enabled) {
if (index < 0) {
// if the effect is not suspend check if all effects are suspended
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 97103c4..50712cf 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioFlinger.h
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -22,11 +22,14 @@
#include <sys/types.h>
#include <limits.h>
+#include <common_time/cc_helper.h>
+
#include <media/IAudioFlinger.h>
#include <media/IAudioFlingerClient.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
@@ -55,7 +58,7 @@
// ----------------------------------------------------------------------------
-static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
class AudioFlinger :
public BinderService<AudioFlinger>,
@@ -67,7 +70,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
- // IAudioFlinger interface
+ // IAudioFlinger interface, in binder opcode order
virtual sp<IAudioTrack> createTrack(
pid_t pid,
audio_stream_type_t streamType,
@@ -78,6 +81,18 @@
uint32_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ bool isTimed,
+ int *sessionId,
+ status_t *status);
+
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ audio_io_handle_t input,
+ uint32_t sampleRate,
+ audio_format_t format,
+ uint32_t channelMask,
+ int frameCount,
+ uint32_t flags,
int *sessionId,
status_t *status);
@@ -91,6 +106,7 @@
virtual status_t setMasterMute(bool muted);
virtual float masterVolume() const;
+ virtual float masterVolumeSW() const;
virtual bool masterMute() const;
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
@@ -112,7 +128,6 @@
virtual void registerClient(const sp<IAudioFlingerClient>& client);
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
- virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const;
virtual audio_io_handle_t openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
@@ -145,6 +160,8 @@
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
audio_io_handle_t output) const;
+ virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const;
+
virtual int newAudioSessionId();
virtual void acquireAudioSessionId(int audioSession);
@@ -171,57 +188,31 @@
virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
- enum hardware_call_state {
- AUDIO_HW_IDLE = 0,
- AUDIO_HW_INIT,
- AUDIO_HW_OUTPUT_OPEN,
- AUDIO_HW_OUTPUT_CLOSE,
- AUDIO_HW_INPUT_OPEN,
- AUDIO_HW_INPUT_CLOSE,
- AUDIO_HW_STANDBY,
- AUDIO_HW_SET_MASTER_VOLUME,
- AUDIO_HW_GET_ROUTING,
- AUDIO_HW_SET_ROUTING,
- AUDIO_HW_GET_MODE,
- AUDIO_HW_SET_MODE,
- AUDIO_HW_GET_MIC_MUTE,
- AUDIO_HW_SET_MIC_MUTE,
- AUDIO_SET_VOICE_VOLUME,
- AUDIO_SET_PARAMETER,
- };
-
- // record interface
- virtual sp<IAudioRecord> openRecord(
- pid_t pid,
- audio_io_handle_t input,
- uint32_t sampleRate,
- audio_format_t format,
- uint32_t channelMask,
- int frameCount,
- uint32_t flags,
- int *sessionId,
- status_t *status);
-
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags);
+ // end of IAudioFlinger interface
+
+private:
audio_mode_t getMode() const { return mMode; }
bool btNrecIsOff() const { return mBtNrecIsOff; }
-private:
-
AudioFlinger();
virtual ~AudioFlinger();
- status_t initCheck() const;
+ // call in any IAudioFlinger method that accesses mPrimaryHardwareDev
+ status_t initCheck() const { return mPrimaryHardwareDev == NULL ? NO_INIT : NO_ERROR; }
+
virtual void onFirstRef();
audio_hw_device_t* findSuitableHwDev_l(uint32_t devices);
void purgeStaleEffects_l();
+ static nsecs_t mStandbyTimeInNsecs;
+
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
status_t dumpClients(int fd, const Vector<String16>& args);
@@ -236,12 +227,18 @@
pid_t pid() const { return mPid; }
sp<AudioFlinger> audioFlinger() const { return mAudioFlinger; }
+ bool reserveTimedTrack();
+ void releaseTimedTrack();
+
private:
Client(const Client&);
Client& operator = (const Client&);
const sp<AudioFlinger> mAudioFlinger;
const sp<MemoryDealer> mMemoryDealer;
const pid_t mPid;
+
+ Mutex mTimedTrackLock;
+ int mTimedTrackCount;
};
// --- Notification Client ---
@@ -306,6 +303,8 @@
enum track_state {
IDLE,
TERMINATED,
+ // These are order-sensitive; do not change order without reviewing the impact.
+ // In particular there are assumptions about > STOPPED.
STOPPED,
RESUMING,
ACTIVE,
@@ -330,7 +329,7 @@
int sessionId);
virtual ~TrackBase();
- virtual status_t start() = 0;
+ virtual status_t start(pid_t tid) = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const { return mCblkMemory; }
audio_track_cblk_t* cblk() const { return mCblk; }
@@ -347,7 +346,9 @@
TrackBase(const TrackBase&);
TrackBase& operator = (const TrackBase&);
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+ virtual status_t getNextBuffer(
+ AudioBufferProvider::Buffer* buffer,
+ int64_t pts) = 0;
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
audio_format_t format() const {
@@ -419,6 +420,8 @@
audio_format_t format() const { return mFormat; }
size_t frameCount() const { return mFrameCount; }
void wakeUp() { mWaitWorkCV.broadcast(); }
+ // Should be "virtual status_t requestExitAndWait()" and override same
+ // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
void exit();
virtual bool checkForNewParameters_l() = 0;
virtual status_t setParameters(const String8& keyValuePairs);
@@ -442,7 +445,7 @@
status_t *status);
void disconnectEffect(const sp< EffectModule>& effect,
const wp<EffectHandle>& handle,
- bool unpiniflast);
+ bool unpinIfLast);
// return values for hasAudioSession (bit field)
enum effect_state {
@@ -550,7 +553,6 @@
Vector<ConfigEvent> mConfigEvents;
bool mStandby;
const audio_io_handle_t mId;
- bool mExiting;
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice; // output device for PlaybackThread
// input + output devices for RecordThread
@@ -564,6 +566,18 @@
KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions;
};
+ struct stream_type_t {
+ stream_type_t()
+ : volume(1.0f),
+ mute(false),
+ valid(true)
+ {
+ }
+ float volume;
+ bool mute;
+ bool valid;
+ };
+
// --- PlaybackThread ---
class PlaybackThread : public ThreadBase {
public:
@@ -589,7 +603,7 @@
virtual ~Track();
void dump(char* buffer, size_t size);
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
void pause();
@@ -600,7 +614,7 @@
return mName;
}
- audio_stream_type_t type() const {
+ audio_stream_type_t streamType() const {
return mStreamType;
}
status_t attachAuxEffect(int EffectId);
@@ -610,7 +624,6 @@
int16_t *mainBuffer() const { return mMainBuffer; }
int auxEffectId() const { return mAuxEffectId; }
-
protected:
friend class ThreadBase;
friend class TrackHandle;
@@ -621,7 +634,11 @@
Track(const Track&);
Track& operator = (const Track&);
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual status_t getNextBuffer(
+ AudioBufferProvider::Buffer* buffer,
+ int64_t pts);
+ virtual uint32_t framesReady() const;
+
bool isMuted() const { return mMute; }
bool isPausing() const {
return mState == PAUSING;
@@ -637,6 +654,8 @@
return (mStreamType == AUDIO_STREAM_CNT);
}
+ virtual bool isTimedTrack() const { return false; }
+
// we don't really need a lock for these
volatile bool mMute;
// FILLED state is used for suppressing volume ramp at begin of playing
@@ -653,6 +672,79 @@
bool mHasVolumeController;
}; // end of Track
+ class TimedTrack : public Track {
+ public:
+ static sp<TimedTrack> create(const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ audio_stream_type_t streamType,
+ uint32_t sampleRate,
+ audio_format_t format,
+ uint32_t channelMask,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ int sessionId);
+ ~TimedTrack();
+
+ class TimedBuffer {
+ public:
+ TimedBuffer();
+ TimedBuffer(const sp<IMemory>& buffer, int64_t pts);
+ const sp<IMemory>& buffer() const { return mBuffer; }
+ int64_t pts() const { return mPTS; }
+ int position() const { return mPosition; }
+ void setPosition(int pos) { mPosition = pos; }
+ private:
+ sp<IMemory> mBuffer;
+ int64_t mPTS;
+ int mPosition;
+ };
+
+ virtual bool isTimedTrack() const { return true; }
+
+ virtual uint32_t framesReady() const;
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
+ int64_t pts);
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+ void timedYieldSamples(AudioBufferProvider::Buffer* buffer);
+ void timedYieldSilence(uint32_t numFrames,
+ AudioBufferProvider::Buffer* buffer);
+
+ status_t allocateTimedBuffer(size_t size,
+ sp<IMemory>* buffer);
+ status_t queueTimedBuffer(const sp<IMemory>& buffer,
+ int64_t pts);
+ status_t setMediaTimeTransform(const LinearTransform& xform,
+ TimedAudioTrack::TargetTimeline target);
+ void trimTimedBufferQueue_l();
+
+ private:
+ TimedTrack(const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ audio_stream_type_t streamType,
+ uint32_t sampleRate,
+ audio_format_t format,
+ uint32_t channelMask,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ int sessionId);
+
+ uint64_t mLocalTimeFreq;
+ LinearTransform mLocalTimeToSampleTransform;
+ sp<MemoryDealer> mTimedMemoryDealer;
+ Vector<TimedBuffer> mTimedBufferQueue;
+ uint8_t* mTimedSilenceBuffer;
+ uint32_t mTimedSilenceBufferSize;
+ mutable Mutex mTimedBufferQueueLock;
+ bool mTimedAudioOutputOnTime;
+ CCHelper mCCHelper;
+
+ Mutex mMediaTimeTransformLock;
+ LinearTransform mMediaTimeTransform;
+ bool mMediaTimeTransformValid;
+ TimedAudioTrack::TargetTimeline mMediaTimeTransformTarget;
+ };
+
// playback track
class OutputTrack : public Track {
@@ -671,10 +763,10 @@
int frameCount);
virtual ~OutputTrack();
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
bool write(int16_t* data, uint32_t frames);
- bool bufferQueueEmpty() const { return (mBufferQueue.size() == 0) ? true : false; }
+ bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; }
bool isActive() const { return mActive; }
const wp<ThreadBase>& thread() const { return mThread; }
@@ -710,17 +802,13 @@
virtual uint32_t latency() const;
- virtual status_t setMasterVolume(float value);
- virtual status_t setMasterMute(bool muted);
+ void setMasterVolume(float value);
+ void setMasterMute(bool muted);
- virtual float masterVolume() const { return mMasterVolume; }
- virtual bool masterMute() const { return mMasterMute; }
+ void setStreamVolume(audio_stream_type_t stream, float value);
+ void setStreamMute(audio_stream_type_t stream, bool muted);
- virtual status_t setStreamVolume(audio_stream_type_t stream, float value);
- virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
-
- virtual float streamVolume(audio_stream_type_t stream) const;
- virtual bool streamMute(audio_stream_type_t stream) const;
+ float streamVolume(audio_stream_type_t stream) const;
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
@@ -731,6 +819,7 @@
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
+ bool isTimed,
status_t *status);
AudioStreamOut* getOutput() const;
@@ -758,24 +847,16 @@
void setStreamValid(audio_stream_type_t streamType, bool valid);
- struct stream_type_t {
- stream_type_t()
- : volume(1.0f),
- mute(false),
- valid(true)
- {
- }
- float volume;
- bool mute;
- bool valid;
- };
-
protected:
int16_t* mMixBuffer;
int mSuspended;
int mBytesWritten;
private:
+ // mMasterMute is in both PlaybackThread and in AudioFlinger. When a
+ // PlaybackThread needs to find out if master-muted, it checks it's local
+ // copy rather than the one in AudioFlinger. This optimization saves a lock.
bool mMasterMute;
+ void setMasterMute_l(bool muted) { mMasterMute = muted; }
protected:
SortedVector< wp<Track> > mActiveTracks;
@@ -868,6 +949,8 @@
private:
void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
+ // volumes last sent to audio HAL with stream->set_volume()
+ // FIXME use standard representation and names
float mLeftVolFloat;
float mRightVolFloat;
uint16_t mLeftVolShort;
@@ -899,7 +982,11 @@
PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const;
MixerThread *checkMixerThread_l(audio_io_handle_t output) const;
RecordThread *checkRecordThread_l(audio_io_handle_t input) const;
- float streamVolumeInternal(audio_stream_type_t stream) const
+ // no range check, AudioFlinger::mLock held
+ bool streamMute_l(audio_stream_type_t stream) const
+ { return mStreamTypes[stream].mute; }
+ // no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
+ float streamVolume_l(audio_stream_type_t stream) const
{ return mStreamTypes[stream].volume; }
void audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2);
@@ -907,25 +994,32 @@
uint32_t nextUniqueId();
status_t moveEffectChain_l(int sessionId,
- AudioFlinger::PlaybackThread *srcThread,
- AudioFlinger::PlaybackThread *dstThread,
+ PlaybackThread *srcThread,
+ PlaybackThread *dstThread,
bool reRegister);
PlaybackThread *primaryPlaybackThread_l();
uint32_t primaryOutputDevice_l();
friend class AudioBuffer;
+ // server side of the client's IAudioTrack
class TrackHandle : public android::BnAudioTrack {
public:
TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
virtual void flush();
virtual void mute(bool);
virtual void pause();
virtual status_t attachAuxEffect(int effectId);
+ virtual status_t allocateTimedBuffer(size_t size,
+ sp<IMemory>* buffer);
+ virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
+ int64_t pts);
+ virtual status_t setMediaTimeTransform(const LinearTransform& xform,
+ int target);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
@@ -958,7 +1052,7 @@
int sessionId);
virtual ~RecordTrack();
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
@@ -973,7 +1067,9 @@
RecordTrack(const RecordTrack&);
RecordTrack& operator = (const RecordTrack&);
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual status_t getNextBuffer(
+ AudioBufferProvider::Buffer* buffer,
+ int64_t pts);
bool mOverflow;
};
@@ -1003,13 +1099,15 @@
status_t *status);
status_t start(RecordTrack* recordTrack);
+ status_t start(RecordTrack* recordTrack, pid_t tid);
void stop(RecordTrack* recordTrack);
status_t dump(int fd, const Vector<String16>& args);
AudioStreamIn* getInput() const;
AudioStreamIn* clearInput();
virtual audio_stream_t* stream();
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
+ int64_t pts);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
virtual bool checkForNewParameters_l();
virtual String8 getParameters(const String8& keys);
@@ -1038,12 +1136,13 @@
ssize_t mBytesRead;
};
+ // server side of the client's IAudioRecord
class RecordHandle : public android::BnAudioRecord {
public:
RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
@@ -1120,7 +1219,7 @@
const wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(const sp<EffectHandle>& handle);
- void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
+ void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast);
size_t removeHandle (const wp<EffectHandle>& handle);
effect_descriptor_t& desc() { return mDescriptor; }
@@ -1166,6 +1265,7 @@
status_t mStatus; // initialization status
effect_state mState; // current activation state
Vector< wp<EffectHandle> > mHandles; // list of client handles
+ // First handle in mHandles has highest priority and controls the effect module
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
@@ -1196,7 +1296,9 @@
uint32_t *replySize,
void *pReplyData);
virtual void disconnect();
- virtual void disconnect(bool unpiniflast);
+ private:
+ void disconnect(bool unpinIfLast);
+ public:
virtual sp<IMemory> getCblk() const { return mCblkMemory; }
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -1389,6 +1491,7 @@
hwDev(dev), stream(in) {}
};
+ // for mAudioSessionRefs only
struct AudioSessionRef {
// FIXME rename parameter names when fields get "m" prefix
AudioSessionRef(int sessionid_, pid_t pid_) :
@@ -1401,33 +1504,83 @@
friend class RecordThread;
friend class PlaybackThread;
+ enum master_volume_support {
+ // MVS_NONE:
+ // Audio HAL has no support for master volume, either setting or
+ // getting. All master volume control must be implemented in SW by the
+ // AudioFlinger mixing core.
+ MVS_NONE,
+
+ // MVS_SETONLY:
+ // Audio HAL has support for setting master volume, but not for getting
+ // master volume (original HAL design did not include a getter).
+ // AudioFlinger needs to keep track of the last set master volume in
+ // addition to needing to set an initial, default, master volume at HAL
+ // load time.
+ MVS_SETONLY,
+
+ // MVS_FULL:
+ // Audio HAL has support both for setting and getting master volume.
+ // AudioFlinger should send all set and get master volume requests
+ // directly to the HAL.
+ MVS_FULL,
+ };
+
mutable Mutex mLock;
DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client()
mutable Mutex mHardwareLock;
- audio_hw_device_t* mPrimaryHardwareDev;
+
+ // These two fields are immutable after onFirstRef(), so no lock needed to access
+ audio_hw_device_t* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
Vector<audio_hw_device_t*> mAudioHwDevs;
+
+ enum hardware_call_state {
+ AUDIO_HW_IDLE = 0,
+ AUDIO_HW_INIT,
+ AUDIO_HW_OUTPUT_OPEN,
+ AUDIO_HW_OUTPUT_CLOSE,
+ AUDIO_HW_INPUT_OPEN,
+ AUDIO_HW_INPUT_CLOSE,
+ AUDIO_HW_STANDBY,
+ AUDIO_HW_SET_MASTER_VOLUME,
+ AUDIO_HW_GET_ROUTING,
+ AUDIO_HW_SET_ROUTING,
+ AUDIO_HW_GET_MODE,
+ AUDIO_HW_SET_MODE,
+ AUDIO_HW_GET_MIC_MUTE,
+ AUDIO_HW_SET_MIC_MUTE,
+ AUDIO_SET_VOICE_VOLUME,
+ AUDIO_SET_PARAMETER,
+ AUDIO_HW_GET_INPUT_BUFFER_SIZE,
+ AUDIO_HW_GET_MASTER_VOLUME,
+ };
+
mutable hardware_call_state mHardwareStatus; // for dump only
DefaultKeyedVector< audio_io_handle_t, sp<PlaybackThread> > mPlaybackThreads;
- PlaybackThread::stream_type_t mStreamTypes[AUDIO_STREAM_CNT];
+ stream_type_t mStreamTypes[AUDIO_STREAM_CNT];
// both are protected by mLock
float mMasterVolume;
+ float mMasterVolumeSW;
+ master_volume_support mMasterVolumeSupportLvl;
bool mMasterMute;
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
- volatile int32_t mNextUniqueId;
+ volatile int32_t mNextUniqueId; // updated by android_atomic_inc
audio_mode_t mMode;
bool mBtNrecIsOff;
+ // protected by mLock
Vector<AudioSessionRef*> mAudioSessionRefs;
- float masterVolume_l() const { return mMasterVolume; }
+ float masterVolume_l() const;
+ float masterVolumeSW_l() const { return mMasterVolumeSW; }
bool masterMute_l() const { return mMasterMute; }
private:
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 191520a..020d62a 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioMixer.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -33,6 +33,8 @@
#include <system/audio.h>
#include <audio_utils/primitives.h>
+#include <common_time/local_clock.h>
+#include <common_time/cc_helper.h>
#include "AudioMixer.h"
@@ -45,6 +47,9 @@
{
// AudioMixer is not yet capable of multi-channel beyond stereo
assert(2 == MAX_NUM_CHANNELS);
+
+ LocalClock lc;
+
mState.enabledTracks= 0;
mState.needsChanged = 0;
mState.frameCount = frameCount;
@@ -80,6 +85,7 @@
t->sampleRate = mSampleRate;
t->mainBuffer = NULL;
t->auxBuffer = NULL;
+ t->localTimeFreq = lc.getLocalFreq();
t++;
}
}
@@ -251,6 +257,7 @@
}
break;
case AUXLEVEL:
+ //assert(0 <= valueInt && valueInt <= MAX_GAIN_INT);
if (track.auxLevel != valueInt) {
ALOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
track.prevAuxLevel = track.auxLevel << 16;
@@ -289,6 +296,7 @@
if (resampler == NULL) {
resampler = AudioResampler::create(
format, channelCount, devSampleRate);
+ resampler->setLocalTimeFreq(localTimeFreq);
}
return true;
}
@@ -333,13 +341,13 @@
-void AudioMixer::process()
+void AudioMixer::process(int64_t pts)
{
- mState.hook(&mState);
+ mState.hook(&mState, pts);
}
-void AudioMixer::process__validate(state_t* state)
+void AudioMixer::process__validate(state_t* state, int64_t pts)
{
ALOGW_IF(!state->needsChanged,
"in process__validate() but nothing's invalid");
@@ -443,7 +451,7 @@
countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp);
- state->hook(state);
+ state->hook(state, pts);
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
@@ -549,7 +557,7 @@
}
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp((aux != NULL));
+ t->adjustVolumeRamp(aux != NULL);
}
void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
@@ -558,7 +566,7 @@
const int16_t vr = t->volume[1];
if (CC_UNLIKELY(aux != NULL)) {
- const int16_t va = (int16_t)t->auxLevel;
+ const int16_t va = t->auxLevel;
do {
int16_t l = (int16_t)(*temp++ >> 12);
int16_t r = (int16_t)(*temp++ >> 12);
@@ -757,7 +765,7 @@
}
// no-op case
-void AudioMixer::process__nop(state_t* state)
+void AudioMixer::process__nop(state_t* state, int64_t pts)
{
uint32_t e0 = state->enabledTracks;
size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
@@ -787,7 +795,9 @@
size_t outFrames = state->frameCount;
while (outFrames) {
t1.buffer.frameCount = outFrames;
- t1.bufferProvider->getNextBuffer(&t1.buffer);
+ int64_t outputPTS = calculateOutputPTS(
+ t1, pts, state->frameCount - outFrames);
+ t1.bufferProvider->getNextBuffer(&t1.buffer, outputPTS);
if (t1.buffer.raw == NULL) break;
outFrames -= t1.buffer.frameCount;
t1.bufferProvider->releaseBuffer(&t1.buffer);
@@ -797,7 +807,7 @@
}
// generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state)
+void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
{
int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
@@ -809,7 +819,7 @@
e0 &= ~(1<<i);
track_t& t = state->tracks[i];
t.buffer.frameCount = state->frameCount;
- t.bufferProvider->getNextBuffer(&t.buffer);
+ t.bufferProvider->getNextBuffer(&t.buffer, pts);
t.frameCount = t.buffer.frameCount;
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
@@ -853,7 +863,7 @@
while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
if (inFrames) {
- (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
+ t.hook(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
t.frameCount -= inFrames;
outFrames -= inFrames;
if (CC_UNLIKELY(aux != NULL)) {
@@ -863,7 +873,9 @@
if (t.frameCount == 0 && outFrames) {
t.bufferProvider->releaseBuffer(&t.buffer);
t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
- t.bufferProvider->getNextBuffer(&t.buffer);
+ int64_t outputPTS = calculateOutputPTS(
+ t, pts, numFrames + (BLOCKSIZE - outFrames));
+ t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
t.in = t.buffer.raw;
if (t.in == NULL) {
enabledTracks &= ~(1<<i);
@@ -892,7 +904,7 @@
// generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state)
+void AudioMixer::process__genericResampling(state_t* state, int64_t pts)
{
// this const just means that local variable outTemp doesn't change
int32_t* const outTemp = state->outputTemp;
@@ -932,14 +944,16 @@
// acquire/release the buffers because it's done by
// the resampler.
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
- (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
+ t.resampler->setPTS(pts);
+ t.hook(&t, outTemp, numFrames, state->resampleTemp, aux);
} else {
size_t outFrames = 0;
while (outFrames < numFrames) {
t.buffer.frameCount = numFrames - outFrames;
- t.bufferProvider->getNextBuffer(&t.buffer);
+ int64_t outputPTS = calculateOutputPTS(t, pts, outFrames);
+ t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing.
@@ -948,7 +962,7 @@
if (CC_UNLIKELY(aux != NULL)) {
aux += outFrames;
}
- (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
+ t.hook(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
outFrames += t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
}
@@ -959,9 +973,15 @@
}
// one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state,
+ int64_t pts)
{
+ // This method is only called when state->enabledTracks has exactly
+ // one bit set. The asserts below would verify this, but are commented out
+ // since the whole point of this method is to optimize performance.
+ //assert(0 != state->enabledTracks);
const int i = 31 - __builtin_clz(state->enabledTracks);
+ //assert((1 << i) == state->enabledTracks);
const track_t& t = state->tracks[i];
AudioBufferProvider::Buffer& b(t.buffer);
@@ -974,7 +994,8 @@
const uint32_t vrl = t.volumeRL;
while (numFrames) {
b.frameCount = numFrames;
- t.bufferProvider->getNextBuffer(&b);
+ int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer);
+ t.bufferProvider->getNextBuffer(&b, outputPTS);
const int16_t *in = b.i16;
// in == NULL can happen if the track was flushed just after having
@@ -1018,7 +1039,8 @@
// 2 tracks is also a common case
// NEVER used in current implementation of process__validate()
// only use if the 2 tracks have the same output buffer
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state,
+ int64_t pts)
{
int i;
uint32_t en = state->enabledTracks;
@@ -1052,7 +1074,9 @@
if (frameCount0 == 0) {
b0.frameCount = numFrames;
- t0.bufferProvider->getNextBuffer(&b0);
+ int64_t outputPTS = calculateOutputPTS(t0, pts,
+ out - t0.mainBuffer);
+ t0.bufferProvider->getNextBuffer(&b0, outputPTS);
if (b0.i16 == NULL) {
if (buff == NULL) {
buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
@@ -1066,7 +1090,9 @@
}
if (frameCount1 == 0) {
b1.frameCount = numFrames;
- t1.bufferProvider->getNextBuffer(&b1);
+ int64_t outputPTS = calculateOutputPTS(t1, pts,
+ out - t0.mainBuffer);
+ t1.bufferProvider->getNextBuffer(&b1, outputPTS);
if (b1.i16 == NULL) {
if (buff == NULL) {
buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
@@ -1112,5 +1138,14 @@
}
#endif
+int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
+ int outputFrameIndex)
+{
+ if (AudioBufferProvider::kInvalidPTS == basePTS)
+ return AudioBufferProvider::kInvalidPTS;
+
+ return basePTS + ((outputFrameIndex * t.localTimeFreq) / t.sampleRate);
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index c709686..b210212 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioMixer.h
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -79,7 +79,7 @@
void setParameter(int name, int target, int param, void *value);
void setBufferProvider(int name, AudioBufferProvider* bufferProvider);
- void process();
+ void process(int64_t pts);
uint32_t trackNames() const { return mTrackNames; }
@@ -114,7 +114,6 @@
struct state_t;
struct track_t;
- typedef void (*mix_t)(state_t* state);
typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
static const int BLOCKSIZE = 16; // 4 cache lines
@@ -128,30 +127,46 @@
int32_t prevVolume[MAX_NUM_CHANNELS];
+ // 16-byte boundary
+
int32_t volumeInc[MAX_NUM_CHANNELS];
- int32_t auxLevel;
int32_t auxInc;
int32_t prevAuxLevel;
+ // 16-byte boundary
+
+ int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
uint16_t frameCount;
- uint8_t channelCount : 4;
- uint8_t enabled : 1;
- uint8_t reserved0 : 3;
- uint8_t format;
- uint32_t channelMask;
+ uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
+ uint8_t format; // always 16
+ uint16_t enabled; // actually bool
+ uint32_t channelMask; // currently under-used
AudioBufferProvider* bufferProvider;
- mutable AudioBufferProvider::Buffer buffer;
+
+ // 16-byte boundary
+
+ mutable AudioBufferProvider::Buffer buffer; // 8 bytes
hook_t hook;
const void* in; // current location in buffer
+ // 16-byte boundary
+
AudioResampler* resampler;
uint32_t sampleRate;
int32_t* mainBuffer;
int32_t* auxBuffer;
+ // 16-byte boundary
+
+ uint64_t localTimeFreq;
+
+ int64_t padding;
+
+ // 16-byte boundary
+
bool setResampler(uint32_t sampleRate, uint32_t devSampleRate);
bool doesResample() const { return resampler != NULL; }
void resetResampler() { if (resampler != NULL) resampler->reset(); }
@@ -165,7 +180,7 @@
uint32_t enabledTracks;
uint32_t needsChanged;
size_t frameCount;
- mix_t hook;
+ void (*hook)(state_t* state, int64_t pts); // one of process__*, never NULL
int32_t *outputTemp;
int32_t *resampleTemp;
int32_t reserved[2];
@@ -187,14 +202,19 @@
static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
- static void process__validate(state_t* state);
- static void process__nop(state_t* state);
- static void process__genericNoResampling(state_t* state);
- static void process__genericResampling(state_t* state);
- static void process__OneTrack16BitsStereoNoResampling(state_t* state);
+ static void process__validate(state_t* state, int64_t pts);
+ static void process__nop(state_t* state, int64_t pts);
+ static void process__genericNoResampling(state_t* state, int64_t pts);
+ static void process__genericResampling(state_t* state, int64_t pts);
+ static void process__OneTrack16BitsStereoNoResampling(state_t* state,
+ int64_t pts);
#if 0
- static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
+ static void process__TwoTracks16BitsStereoNoResampling(state_t* state,
+ int64_t pts);
#endif
+
+ static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS,
+ int outputFrameIndex);
};
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 10efd85..987b039 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -30,6 +30,7 @@
#include <utils/String16.h>
#include <utils/threads.h>
#include "AudioPolicyService.h"
+#include "ServiceUtilities.h"
#include <cutils/properties.h>
#include <hardware_legacy/power.h>
#include <media/AudioEffect.h>
@@ -49,13 +50,6 @@
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
-static bool checkPermission() {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
- if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
- return ok;
-}
-
namespace {
extern struct audio_policy_service_ops aps_ops;
};
@@ -122,19 +116,7 @@
// release audio pre processing resources
for (size_t i = 0; i < mInputSources.size(); i++) {
- InputSourceDesc *source = mInputSources.valueAt(i);
- Vector <EffectDesc *> effects = source->mEffects;
- for (size_t j = 0; j < effects.size(); j++) {
- delete effects[j]->mName;
- Vector <effect_param_t *> params = effects[j]->mParams;
- for (size_t k = 0; k < params.size(); k++) {
- delete params[k];
- }
- params.clear();
- delete effects[j];
- }
- effects.clear();
- delete source;
+ delete mInputSources.valueAt(i);
}
mInputSources.clear();
@@ -157,7 +139,7 @@
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
@@ -190,7 +172,7 @@
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(state) >= AUDIO_MODE_CNT) {
@@ -213,7 +195,7 @@
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
@@ -388,7 +370,7 @@
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
@@ -405,7 +387,7 @@
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
@@ -542,7 +524,7 @@
}
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
- ALOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
+ ALOGW("binderDied() %p, tid %d, calling pid %d", who.unsafe_get(), gettid(),
IPCThreadState::self()->getCallingPid());
}
@@ -578,7 +560,7 @@
status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
{
- if (!checkCallingPermission(String16("android.permission.DUMP"))) {
+ if (!dumpAllowed()) {
dumpPermissionDenial(fd);
} else {
bool locked = tryLock(mLock);
@@ -588,10 +570,10 @@
}
dumpInternals(fd);
- if (mAudioCommandThread != NULL) {
+ if (mAudioCommandThread != 0) {
mAudioCommandThread->dump(fd);
}
- if (mTonePlaybackThread != NULL) {
+ if (mTonePlaybackThread != 0) {
mTonePlaybackThread->dump(fd);
}
@@ -622,8 +604,7 @@
{
Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects;
for (size_t i = 0; i < fxVector.size(); i++) {
- sp<AudioEffect> fx = fxVector.itemAt(i);
- fx->setEnabled(enabled);
+ fxVector.itemAt(i)->setEnabled(enabled);
}
}
@@ -774,7 +755,7 @@
snprintf(buffer, SIZE, "- Commands:\n");
result = String8(buffer);
result.append(" Command Time Wait pParam\n");
- for (int i = 0; i < (int)mAudioCommands.size(); i++) {
+ for (size_t i = 0; i < mAudioCommands.size(); i++) {
mAudioCommands[i]->dump(buffer, SIZE);
result.append(buffer);
}
@@ -908,7 +889,7 @@
// insertCommand_l() must be called with mLock held
void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
{
- ssize_t i;
+ ssize_t i; // not size_t because i will count down to -1
Vector <AudioCommand *> removedCommands;
command->mTime = systemTime() + milliseconds(delayMs);
@@ -1249,7 +1230,7 @@
node = node->next;
continue;
}
- EffectDesc *effect = new EffectDesc(*effects[i]);
+ EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
loadEffectParameters(node, effect->mParams);
ALOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow);
source->mEffects.add(effect);
@@ -1300,11 +1281,7 @@
ALOGW("loadEffect() invalid uuid %s", node->value);
return NULL;
}
- EffectDesc *effect = new EffectDesc();
- effect->mName = strdup(root->name);
- memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t));
-
- return effect;
+ return new EffectDesc(root->name, uuid);
}
status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index fdaf576..679fd30 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -233,8 +233,33 @@
class EffectDesc {
public:
- EffectDesc() {}
- virtual ~EffectDesc() {}
+ EffectDesc(const char *name, const effect_uuid_t& uuid) :
+ mName(strdup(name)),
+ mUuid(uuid) { }
+ EffectDesc(const EffectDesc& orig) :
+ mName(strdup(orig.mName)),
+ mUuid(orig.mUuid) {
+ // deep copy mParams
+ for (size_t k = 0; k < orig.mParams.size(); k++) {
+ effect_param_t *origParam = orig.mParams[k];
+ // psize and vsize are rounded up to an int boundary for allocation
+ size_t origSize = sizeof(effect_param_t) +
+ ((origParam->psize + 3) & ~3) +
+ ((origParam->vsize + 3) & ~3);
+ effect_param_t *dupParam = (effect_param_t *) malloc(origSize);
+ memcpy(dupParam, origParam, origSize);
+ // This works because the param buffer allocation is also done by
+ // multiples of 4 bytes originally. In theory we should memcpy only
+ // the actual param size, that is without rounding vsize.
+ mParams.add(dupParam);
+ }
+ }
+ /*virtual*/ ~EffectDesc() {
+ free(mName);
+ for (size_t k = 0; k < mParams.size(); k++) {
+ free(mParams[k]);
+ }
+ }
char *mName;
effect_uuid_t mUuid;
Vector <effect_param_t *> mParams;
@@ -243,7 +268,11 @@
class InputSourceDesc {
public:
InputSourceDesc() {}
- virtual ~InputSourceDesc() {}
+ /*virtual*/ ~InputSourceDesc() {
+ for (size_t j = 0; j < mEffects.size(); j++) {
+ delete mEffects[j];
+ }
+ }
Vector <EffectDesc *> mEffects;
};
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 6e17a4a3..398ba0b 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -23,8 +23,10 @@
#include <cutils/log.h>
#include <cutils/properties.h>
#include "AudioResampler.h"
+#if 0
#include "AudioResamplerSinc.h"
#include "AudioResamplerCubic.h"
+#endif
#ifdef __arm__
#include <machine/cpu-features.h>
@@ -99,6 +101,7 @@
ALOGV("Create linear Resampler");
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
break;
+#if 0
case MED_QUALITY:
ALOGV("Create cubic Resampler");
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
@@ -107,6 +110,7 @@
ALOGV("Create sinc Resampler");
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
break;
+#endif
}
// initialize resampler
@@ -118,7 +122,8 @@
int32_t sampleRate) :
mBitDepth(bitDepth), mChannelCount(inChannelCount),
mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
- mPhaseFraction(0) {
+ mPhaseFraction(0), mLocalTimeFreq(0),
+ mPTS(AudioBufferProvider::kInvalidPTS) {
// sanity check on format
if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
@@ -146,6 +151,23 @@
mVolume[1] = right;
}
+void AudioResampler::setLocalTimeFreq(uint64_t freq) {
+ mLocalTimeFreq = freq;
+}
+
+void AudioResampler::setPTS(int64_t pts) {
+ mPTS = pts;
+}
+
+int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
+
+ if (mPTS == AudioBufferProvider::kInvalidPTS) {
+ return AudioBufferProvider::kInvalidPTS;
+ } else {
+ return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
+ }
+}
+
void AudioResampler::reset() {
mInputIndex = 0;
mPhaseFraction = 0;
@@ -184,7 +206,7 @@
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+ // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
// outFrameCount, inputIndex, phaseFraction, phaseIncrement);
while (outputIndex < outputSampleCount) {
@@ -192,12 +214,13 @@
// buffer is empty, fetch a new one
while (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer,
+ calculateOutputPTS(outputIndex / 2));
if (mBuffer.raw == NULL) {
goto resampleStereo16_exit;
}
- // ALOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
if (mBuffer.frameCount > inputIndex) break;
inputIndex -= mBuffer.frameCount;
@@ -211,7 +234,7 @@
// handle boundary case
while (inputIndex == 0) {
- // ALOGE("boundary case\n");
+ // ALOGE("boundary case");
out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
Advance(&inputIndex, &phaseFraction, phaseIncrement);
@@ -220,7 +243,7 @@
}
// process input samples
- // ALOGE("general case\n");
+ // ALOGE("general case");
#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
if (inputIndex + 2 < mBuffer.frameCount) {
@@ -242,7 +265,7 @@
Advance(&inputIndex, &phaseFraction, phaseIncrement);
}
- // ALOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
// if done with buffer, save samples
if (inputIndex >= mBuffer.frameCount) {
@@ -259,7 +282,7 @@
}
}
- // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
resampleStereo16_exit:
// save state
@@ -280,19 +303,20 @@
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+ // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
// outFrameCount, inputIndex, phaseFraction, phaseIncrement);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
while (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer,
+ calculateOutputPTS(outputIndex / 2));
if (mBuffer.raw == NULL) {
mInputIndex = inputIndex;
mPhaseFraction = phaseFraction;
goto resampleMono16_exit;
}
- // ALOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
if (mBuffer.frameCount > inputIndex) break;
inputIndex -= mBuffer.frameCount;
@@ -304,7 +328,7 @@
// handle boundary case
while (inputIndex == 0) {
- // ALOGE("boundary case\n");
+ // ALOGE("boundary case");
int32_t sample = Interp(mX0L, in[0], phaseFraction);
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
@@ -314,7 +338,7 @@
}
// process input samples
- // ALOGE("general case\n");
+ // ALOGE("general case");
#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
if (inputIndex + 2 < mBuffer.frameCount) {
@@ -337,7 +361,7 @@
}
- // ALOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
// if done with buffer, save samples
if (inputIndex >= mBuffer.frameCount) {
@@ -353,7 +377,7 @@
}
}
- // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+ // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
resampleMono16_exit:
// save state
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index ee171ff..9deb796 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -49,6 +49,10 @@
virtual void init() = 0;
virtual void setSampleRate(int32_t inSampleRate);
virtual void setVolume(int16_t left, int16_t right);
+ virtual void setLocalTimeFreq(uint64_t freq);
+
+ // set the PTS of the next buffer output by the resampler
+ virtual void setPTS(int64_t pts);
virtual void resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider) = 0;
@@ -72,9 +76,11 @@
AudioResampler(const AudioResampler&);
AudioResampler& operator=(const AudioResampler&);
- int32_t mBitDepth;
- int32_t mChannelCount;
- int32_t mSampleRate;
+ int64_t calculateOutputPTS(int outputFrameIndex);
+
+ const int32_t mBitDepth;
+ const int32_t mChannelCount;
+ const int32_t mSampleRate;
int32_t mInSampleRate;
AudioBufferProvider::Buffer mBuffer;
union {
@@ -85,6 +91,8 @@
size_t mInputIndex;
int32_t mPhaseIncrement;
uint32_t mPhaseFraction;
+ uint64_t mLocalTimeFreq;
+ int64_t mPTS;
};
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 47205ba..18e59e9 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -65,7 +65,7 @@
// fetch first buffer
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer, mPTS);
if (mBuffer.raw == NULL)
return;
// ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
@@ -95,11 +95,12 @@
inputIndex = 0;
provider->releaseBuffer(&mBuffer);
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer,
+ calculateOutputPTS(outputIndex / 2));
if (mBuffer.raw == NULL)
goto save_state; // ugly, but efficient
in = mBuffer.i16;
- // ALOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
}
// advance sample state
@@ -130,10 +131,10 @@
// fetch first buffer
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer, mPTS);
if (mBuffer.raw == NULL)
return;
- // ALOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
}
int16_t *in = mBuffer.i16;
@@ -160,7 +161,8 @@
inputIndex = 0;
provider->releaseBuffer(&mBuffer);
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer,
+ calculateOutputPTS(outputIndex / 2));
if (mBuffer.raw == NULL)
goto save_state; // ugly, but efficient
// ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
@@ -181,4 +183,3 @@
// ----------------------------------------------------------------------------
}
; // namespace android
-
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index d012433..d373c08 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -199,33 +199,33 @@
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- AudioBufferProvider::Buffer& buffer(mBuffer);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
- while (buffer.frameCount == 0) {
- buffer.frameCount = inFrameCount;
- provider->getNextBuffer(&buffer);
- if (buffer.raw == NULL) {
+ while (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
+ provider->getNextBuffer(&mBuffer,
+ calculateOutputPTS(outputIndex / 2));
+ if (mBuffer.raw == NULL) {
goto resample_exit;
}
const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
if (phaseIndex == 1) {
// read one frame
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
} else if (phaseIndex == 2) {
// read 2 frames
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
inputIndex++;
if (inputIndex >= mBuffer.frameCount) {
inputIndex -= mBuffer.frameCount;
- provider->releaseBuffer(&buffer);
+ provider->releaseBuffer(&mBuffer);
} else {
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
}
}
}
- int16_t *in = buffer.i16;
- const size_t frameCount = buffer.frameCount;
+ int16_t *in = mBuffer.i16;
+ const size_t frameCount = mBuffer.frameCount;
// Always read-in the first samples from the input buffer
int16_t* head = impulse + halfNumCoefs*CHANNELS;
@@ -264,7 +264,7 @@
// if done with buffer, save samples
if (inputIndex >= frameCount) {
inputIndex -= frameCount;
- provider->releaseBuffer(&buffer);
+ provider->releaseBuffer(&mBuffer);
}
}
@@ -355,4 +355,3 @@
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
new file mode 100644
index 0000000..6a58852
--- /dev/null
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include "ServiceUtilities.h"
+
+namespace android {
+
+// This optimization assumes mediaserver process doesn't fork, which it doesn't
+const pid_t getpid_cached = getpid();
+
+bool recordingAllowed() {
+ if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+ static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
+ // don't use PermissionCache; this is not a system permission
+ bool ok = checkCallingPermission(sRecordAudio);
+ if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
+ return ok;
+}
+
+bool settingsAllowed() {
+ if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+ static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
+ // don't use PermissionCache; this is not a system permission
+ bool ok = checkCallingPermission(sAudioSettings);
+ if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+}
+
+bool dumpAllowed() {
+ // don't optimize for same pid, since mediaserver never dumps itself
+ static const String16 sDump("android.permission.DUMP");
+ // OK to use PermissionCache; this is a system permission
+ bool ok = PermissionCache::checkCallingPermission(sDump);
+ // convention is for caller to dump an error message to fd instead of logging here
+ //if (!ok) ALOGE("Request requires android.permission.DUMP");
+ return ok;
+}
+
+} // namespace android
diff --git a/include/ui/PowerManager.h b/services/audioflinger/ServiceUtilities.h
similarity index 61%
copy from include/ui/PowerManager.h
copy to services/audioflinger/ServiceUtilities.h
index dd80318..f77ec5bc 100644
--- a/include/ui/PowerManager.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,20 +14,14 @@
* limitations under the License.
*/
-#ifndef _UI_POWER_MANAGER_H
-#define _UI_POWER_MANAGER_H
-
+#include <unistd.h>
namespace android {
-enum {
- POWER_MANAGER_OTHER_EVENT = 0,
- POWER_MANAGER_BUTTON_EVENT = 1,
- POWER_MANAGER_TOUCH_EVENT = 2,
+extern const pid_t getpid_cached;
- POWER_MANAGER_LAST_EVENT = POWER_MANAGER_TOUCH_EVENT, // Last valid event code.
-};
+bool recordingAllowed();
+bool settingsAllowed();
+bool dumpAllowed();
-} // namespace android
-
-#endif // _UI_POWER_MANAGER_H
+}
diff --git a/services/common_time/Android.mk b/services/common_time/Android.mk
new file mode 100644
index 0000000..e534d49
--- /dev/null
+++ b/services/common_time/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# common_time_service
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ common_clock_service.cpp \
+ common_time_config_service.cpp \
+ common_time_server.cpp \
+ common_time_server_api.cpp \
+ common_time_server_packets.cpp \
+ clock_recovery.cpp \
+ common_clock.cpp \
+ main.cpp
+
+# Uncomment to enable vesbose logging and debug service.
+#TIME_SERVICE_DEBUG=true
+ifeq ($(TIME_SERVICE_DEBUG), true)
+LOCAL_SRC_FILES += diag_thread.cpp
+LOCAL_CFLAGS += -DTIME_SERVICE_DEBUG
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcommon_time_client \
+ libutils
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := common_time
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/common_time/clock_recovery.cpp b/services/common_time/clock_recovery.cpp
new file mode 100644
index 0000000..6c98d32
--- /dev/null
+++ b/services/common_time/clock_recovery.cpp
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define __STDC_LIMIT_MACROS
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+#include <stdint.h>
+
+#include <common_time/local_clock.h>
+#include <assert.h>
+
+#include "clock_recovery.h"
+#include "common_clock.h"
+#ifdef TIME_SERVICE_DEBUG
+#include "diag_thread.h"
+#endif
+
+// Define log macro so we can make LOGV into LOGE when we are exclusively
+// debugging this code.
+#ifdef TIME_SERVICE_DEBUG
+#define LOG_TS ALOGE
+#else
+#define LOG_TS ALOGV
+#endif
+
+namespace android {
+
+ClockRecoveryLoop::ClockRecoveryLoop(LocalClock* local_clock,
+ CommonClock* common_clock) {
+ assert(NULL != local_clock);
+ assert(NULL != common_clock);
+
+ local_clock_ = local_clock;
+ common_clock_ = common_clock;
+
+ local_clock_can_slew_ = local_clock_->initCheck() &&
+ (local_clock_->setLocalSlew(0) == OK);
+
+ reset(true, true);
+
+#ifdef TIME_SERVICE_DEBUG
+ diag_thread_ = new DiagThread(common_clock_, local_clock_);
+ if (diag_thread_ != NULL) {
+ status_t res = diag_thread_->startWorkThread();
+ if (res != OK)
+ ALOGW("Failed to start A@H clock recovery diagnostic thread.");
+ } else
+ ALOGW("Failed to allocate diagnostic thread.");
+#endif
+}
+
+ClockRecoveryLoop::~ClockRecoveryLoop() {
+#ifdef TIME_SERVICE_DEBUG
+ diag_thread_->stopWorkThread();
+#endif
+}
+
+// Constants.
+const float ClockRecoveryLoop::dT = 1.0;
+const float ClockRecoveryLoop::Kc = 1.0f;
+const float ClockRecoveryLoop::Ti = 15.0f;
+const float ClockRecoveryLoop::Tf = 0.05;
+const float ClockRecoveryLoop::bias_Fc = 0.01;
+const float ClockRecoveryLoop::bias_RC = (dT / (2 * 3.14159f * bias_Fc));
+const float ClockRecoveryLoop::bias_Alpha = (dT / (bias_RC + dT));
+const int64_t ClockRecoveryLoop::panic_thresh_ = 50000;
+const int64_t ClockRecoveryLoop::control_thresh_ = 10000;
+const float ClockRecoveryLoop::COmin = -100.0f;
+const float ClockRecoveryLoop::COmax = 100.0f;
+
+void ClockRecoveryLoop::reset(bool position, bool frequency) {
+ Mutex::Autolock lock(&lock_);
+ reset_l(position, frequency);
+}
+
+uint32_t ClockRecoveryLoop::findMinRTTNdx(DisciplineDataPoint* data,
+ uint32_t count) {
+ uint32_t min_rtt = 0;
+ for (uint32_t i = 1; i < count; ++i)
+ if (data[min_rtt].rtt > data[i].rtt)
+ min_rtt = i;
+
+ return min_rtt;
+}
+
+bool ClockRecoveryLoop::pushDisciplineEvent(int64_t local_time,
+ int64_t nominal_common_time,
+ int64_t rtt) {
+ Mutex::Autolock lock(&lock_);
+
+ int64_t local_common_time = 0;
+ common_clock_->localToCommon(local_time, &local_common_time);
+ int64_t raw_delta = nominal_common_time - local_common_time;
+
+#ifdef TIME_SERVICE_DEBUG
+ ALOGE("local=%lld, common=%lld, delta=%lld, rtt=%lld\n",
+ local_common_time, nominal_common_time,
+ raw_delta, rtt);
+#endif
+
+ // If we have not defined a basis for common time, then we need to use these
+ // initial points to do so. In order to avoid significant initial error
+ // from a particularly bad startup data point, we collect the first N data
+ // points and choose the best of them before moving on.
+ if (!common_clock_->isValid()) {
+ if (startup_filter_wr_ < kStartupFilterSize) {
+ DisciplineDataPoint& d = startup_filter_data_[startup_filter_wr_];
+ d.local_time = local_time;
+ d.nominal_common_time = nominal_common_time;
+ d.rtt = rtt;
+ startup_filter_wr_++;
+ }
+
+ if (startup_filter_wr_ == kStartupFilterSize) {
+ uint32_t min_rtt = findMinRTTNdx(startup_filter_data_,
+ kStartupFilterSize);
+
+ common_clock_->setBasis(
+ startup_filter_data_[min_rtt].local_time,
+ startup_filter_data_[min_rtt].nominal_common_time);
+ }
+
+ return true;
+ }
+
+ int64_t observed_common;
+ int64_t delta;
+ float delta_f, dCO;
+ int32_t correction_cur;
+
+ if (OK != common_clock_->localToCommon(local_time, &observed_common)) {
+ // Since we just checked to make certain that this conversion was valid,
+ // and no one else in the system should be messing with it, if this
+ // conversion is suddenly invalid, it is a good reason to panic.
+ ALOGE("Failed to convert local time to common time in %s:%d",
+ __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+
+ // Implement a filter which should match NTP filtering behavior when a
+ // client is associated with only one peer of lower stratum. Basically,
+ // always use the best of the N last data points, where best is defined as
+ // lowest round trip time. NTP uses an N of 8; we use a value of 6.
+ //
+ // TODO(johngro) : experiment with other filter strategies. The goal here
+ // is to mitigate the effects of high RTT data points which typically have
+ // large asymmetries in the TX/RX legs. Downside of the existing NTP
+ // approach (particularly because of the PID controller we are using to
+ // produce the control signal from the filtered data) are that the rate at
+ // which discipline events are actually acted upon becomes irregular and can
+ // become drawn out (the time between actionable event can go way up). If
+ // the system receives a strong high quality data point, the proportional
+ // component of the controller can produce a strong correction which is left
+ // in place for too long causing overshoot. In addition, the integral
+ // component of the system currently is an approximation based on the
+ // assumption of a more or less homogeneous sampling of the error. Its
+ // unclear what the effect of undermining this assumption would be right
+ // now.
+
+ // Two ideas which come to mind immediately would be to...
+ // 1) Keep a history of more data points (32 or so) and ignore data points
+ // whose RTT is more than a certain number of standard deviations outside
+ // of the norm.
+ // 2) Eliminate the PID controller portion of this system entirely.
+ // Instead, move to a system which uses a very wide filter (128 data
+ // points or more) with a sum-of-least-squares line fitting approach to
+ // tracking the long term drift. This would take the place of the I
+ // component in the current PID controller. Also use a much more narrow
+ // outlier-rejector filter (as described in #1) to drive a short term
+ // correction factor similar to the P component of the PID controller.
+ assert(filter_wr_ < kFilterSize);
+ filter_data_[filter_wr_].local_time = local_time;
+ filter_data_[filter_wr_].observed_common_time = observed_common;
+ filter_data_[filter_wr_].nominal_common_time = nominal_common_time;
+ filter_data_[filter_wr_].rtt = rtt;
+ filter_data_[filter_wr_].point_used = false;
+ uint32_t current_point = filter_wr_;
+ filter_wr_ = (filter_wr_ + 1) % kFilterSize;
+ if (!filter_wr_)
+ filter_full_ = true;
+
+ uint32_t scan_end = filter_full_ ? kFilterSize : filter_wr_;
+ uint32_t min_rtt = findMinRTTNdx(filter_data_, scan_end);
+ // We only use packets with low RTTs for control. If the packet RTT
+ // is less than the panic threshold, we can probably eat the jitter with the
+ // control loop. Otherwise, take the packet only if it better than all
+ // of the packets we have in the history. That way we try to track
+ // something, even if it is noisy.
+ if (current_point == min_rtt || rtt < control_thresh_) {
+ delta_f = delta = nominal_common_time - observed_common;
+
+ // Compute the error then clamp to the panic threshold. If we ever
+ // exceed this amt of error, its time to panic and reset the system.
+ // Given that the error in the measurement of the error could be as
+ // high as the RTT of the data point, we don't actually panic until
+ // the implied error (delta) is greater than the absolute panic
+ // threashold plus the RTT. IOW - we don't panic until we are
+ // absoluely sure that our best case sync is worse than the absolute
+ // panic threshold.
+ int64_t effective_panic_thresh = panic_thresh_ + rtt;
+ if ((delta > effective_panic_thresh) ||
+ (delta < -effective_panic_thresh)) {
+ // PANIC!!!
+ reset_l(false, true);
+ return false;
+ }
+
+ } else {
+ // We do not have a good packet to look at, but we also do not want to
+ // free-run the clock at some crazy slew rate. So we guess the
+ // trajectory of the clock based on the last controller output and the
+ // estimated bias of our clock against the master.
+ // The net effect of this is that CO == CObias after some extended
+ // period of no feedback.
+ delta_f = last_delta_f_ - dT*(CO - CObias);
+ delta = delta_f;
+ }
+
+ // Velocity form PI control equation.
+ dCO = Kc * (1.0f + dT/Ti) * delta_f - Kc * last_delta_f_;
+ CO += dCO * Tf; // Filter CO by applying gain <1 here.
+
+ // Save error terms for later.
+ last_delta_f_ = delta_f;
+ last_delta_ = delta;
+
+ // Clamp CO to +/- 100ppm.
+ if (CO < COmin)
+ CO = COmin;
+ else if (CO > COmax)
+ CO = COmax;
+
+ // Update the controller bias.
+ CObias = bias_Alpha * CO + (1.0f - bias_Alpha) * lastCObias;
+ lastCObias = CObias;
+
+ // Convert PPM to 16-bit int range. Add some guard band (-0.01) so we
+ // don't get fp weirdness.
+ correction_cur = CO * 327.66;
+
+ // If there was a change in the amt of correction to use, update the
+ // system.
+ if (correction_cur_ != correction_cur) {
+ correction_cur_ = correction_cur;
+ applySlew();
+ }
+
+ LOG_TS("clock_loop %lld %f %f %f %d\n", raw_delta, delta_f, CO, CObias, correction_cur);
+
+#ifdef TIME_SERVICE_DEBUG
+ diag_thread_->pushDisciplineEvent(
+ local_time,
+ observed_common,
+ nominal_common_time,
+ correction_cur,
+ rtt);
+#endif
+
+ return true;
+}
+
+int32_t ClockRecoveryLoop::getLastErrorEstimate() {
+ Mutex::Autolock lock(&lock_);
+
+ if (last_delta_valid_)
+ return last_delta_;
+ else
+ return ICommonClock::kErrorEstimateUnknown;
+}
+
+void ClockRecoveryLoop::reset_l(bool position, bool frequency) {
+ assert(NULL != common_clock_);
+
+ if (position) {
+ common_clock_->resetBasis();
+ startup_filter_wr_ = 0;
+ }
+
+ if (frequency) {
+ last_delta_valid_ = false;
+ last_delta_ = 0;
+ last_delta_f_ = 0.0;
+ correction_cur_ = 0x0;
+ CO = 0.0f;
+ lastCObias = CObias = 0.0f;
+ applySlew();
+ }
+
+ filter_wr_ = 0;
+ filter_full_ = false;
+}
+
+void ClockRecoveryLoop::applySlew() {
+ if (local_clock_can_slew_) {
+ local_clock_->setLocalSlew(correction_cur_);
+ } else {
+ // The SW clock recovery implemented by the common clock class expects
+ // values expressed in PPM. CO is in ppm.
+ common_clock_->setSlew(local_clock_->getLocalTime(), CO);
+ }
+}
+
+} // namespace android
diff --git a/services/common_time/clock_recovery.h b/services/common_time/clock_recovery.h
new file mode 100644
index 0000000..b7362be
--- /dev/null
+++ b/services/common_time/clock_recovery.h
@@ -0,0 +1,138 @@
+/*
+ * 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 __CLOCK_RECOVERY_H__
+#define __CLOCK_RECOVERY_H__
+
+#include <stdint.h>
+#include <common_time/ICommonClock.h>
+#include <utils/LinearTransform.h>
+#include <utils/threads.h>
+
+#ifdef TIME_SERVICE_DEBUG
+#include "diag_thread.h"
+#endif
+
+namespace android {
+
+class CommonClock;
+class LocalClock;
+
+class ClockRecoveryLoop {
+ public:
+ ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock);
+ ~ClockRecoveryLoop();
+
+ void reset(bool position, bool frequency);
+ bool pushDisciplineEvent(int64_t local_time,
+ int64_t nominal_common_time,
+ int64_t data_point_rtt);
+ int32_t getLastErrorEstimate();
+
+ private:
+
+ // Tuned using the "Good Gain" method.
+ // See:
+ // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf
+
+ // Controller period (1Hz for now).
+ static const float dT;
+
+ // Controller gain, positive and unitless. Larger values converge faster,
+ // but can cause instability.
+ static const float Kc;
+
+ // Integral reset time. Smaller values cause loop to track faster, but can
+ // also cause instability.
+ static const float Ti;
+
+ // Controller output filter time constant. Range (0-1). Smaller values make
+ // output smoother, but slow convergence.
+ static const float Tf;
+
+ // Low-pass filter for bias tracker.
+ static const float bias_Fc; // HZ
+ static const float bias_RC; // Computed in constructor.
+ static const float bias_Alpha; // Computed inconstructor.
+
+ // The maximum allowed error (as indicated by a pushDisciplineEvent) before
+ // we panic.
+ static const int64_t panic_thresh_;
+
+ // The maximum allowed error rtt time for packets to be used for control
+ // feedback, unless the packet is the best in recent memory.
+ static const int64_t control_thresh_;
+
+ typedef struct {
+ int64_t local_time;
+ int64_t observed_common_time;
+ int64_t nominal_common_time;
+ int64_t rtt;
+ bool point_used;
+ } DisciplineDataPoint;
+
+ static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count);
+
+ void reset_l(bool position, bool frequency);
+ void applySlew();
+
+ // The local clock HW abstraction we use as the basis for common time.
+ LocalClock* local_clock_;
+ bool local_clock_can_slew_;
+
+ // The common clock we end up controlling along with the lock used to
+ // serialize operations.
+ CommonClock* common_clock_;
+ Mutex lock_;
+
+ // parameters maintained while running and reset during a reset
+ // of the frequency correction.
+ bool last_delta_valid_;
+ int32_t last_delta_;
+ float last_delta_f_;
+ int32_t integrated_error_;
+ int32_t correction_cur_;
+
+ // Contoller Output.
+ float CO;
+
+ // Bias tracking for trajectory estimation.
+ float CObias;
+ float lastCObias;
+
+ // Controller output bounds. The controller will not try to
+ // slew faster that +/-100ppm offset from center per interation.
+ static const float COmin;
+ static const float COmax;
+
+ // State kept for filtering the discipline data.
+ static const uint32_t kFilterSize = 16;
+ DisciplineDataPoint filter_data_[kFilterSize];
+ uint32_t filter_wr_;
+ bool filter_full_;
+
+ static const uint32_t kStartupFilterSize = 4;
+ DisciplineDataPoint startup_filter_data_[kStartupFilterSize];
+ uint32_t startup_filter_wr_;
+
+#ifdef TIME_SERVICE_DEBUG
+ sp<DiagThread> diag_thread_;
+#endif
+};
+
+} // namespace android
+
+#endif // __CLOCK_RECOVERY_H__
diff --git a/services/common_time/common_clock.cpp b/services/common_time/common_clock.cpp
new file mode 100644
index 0000000..c9eb388
--- /dev/null
+++ b/services/common_time/common_clock.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <stdint.h>
+
+#include <utils/Errors.h>
+#include <utils/LinearTransform.h>
+
+#include "common_clock.h"
+
+namespace android {
+
+CommonClock::CommonClock() {
+ cur_slew_ = 0;
+ cur_trans_valid_ = false;
+
+ cur_trans_.a_zero = 0;
+ cur_trans_.b_zero = 0;
+ cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = 1;
+ cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = 1;
+ duration_trans_ = cur_trans_;
+}
+
+bool CommonClock::init(uint64_t local_freq) {
+ Mutex::Autolock lock(&lock_);
+
+ if (!local_freq)
+ return false;
+
+ uint64_t numer = kCommonFreq;
+ uint64_t denom = local_freq;
+
+ LinearTransform::reduce(&numer, &denom);
+ if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) {
+ ALOGE("Overflow in CommonClock::init while trying to reduce %lld/%lld",
+ kCommonFreq, local_freq);
+ return false;
+ }
+
+ cur_trans_.a_to_b_numer = local_to_common_freq_numer_ =
+ static_cast<uint32_t>(numer);
+ cur_trans_.a_to_b_denom = local_to_common_freq_denom_ =
+ static_cast<uint32_t>(denom);
+ duration_trans_ = cur_trans_;
+
+ return true;
+}
+
+status_t CommonClock::localToCommon(int64_t local, int64_t *common_out) const {
+ Mutex::Autolock lock(&lock_);
+
+ if (!cur_trans_valid_)
+ return INVALID_OPERATION;
+
+ if (!cur_trans_.doForwardTransform(local, common_out))
+ return INVALID_OPERATION;
+
+ return OK;
+}
+
+status_t CommonClock::commonToLocal(int64_t common, int64_t *local_out) const {
+ Mutex::Autolock lock(&lock_);
+
+ if (!cur_trans_valid_)
+ return INVALID_OPERATION;
+
+ if (!cur_trans_.doReverseTransform(common, local_out))
+ return INVALID_OPERATION;
+
+ return OK;
+}
+
+int64_t CommonClock::localDurationToCommonDuration(int64_t localDur) const {
+ int64_t ret;
+ duration_trans_.doForwardTransform(localDur, &ret);
+ return ret;
+}
+
+void CommonClock::setBasis(int64_t local, int64_t common) {
+ Mutex::Autolock lock(&lock_);
+
+ cur_trans_.a_zero = local;
+ cur_trans_.b_zero = common;
+ cur_trans_valid_ = true;
+}
+
+void CommonClock::resetBasis() {
+ Mutex::Autolock lock(&lock_);
+
+ cur_trans_.a_zero = 0;
+ cur_trans_.b_zero = 0;
+ cur_trans_valid_ = false;
+}
+
+status_t CommonClock::setSlew(int64_t change_time, int32_t ppm) {
+ Mutex::Autolock lock(&lock_);
+
+ int64_t new_local_basis;
+ int64_t new_common_basis;
+
+ if (cur_trans_valid_) {
+ new_local_basis = change_time;
+ if (!cur_trans_.doForwardTransform(change_time, &new_common_basis)) {
+ ALOGE("Overflow when attempting to set slew rate to %d", ppm);
+ return INVALID_OPERATION;
+ }
+ } else {
+ new_local_basis = 0;
+ new_common_basis = 0;
+ }
+
+ cur_slew_ = ppm;
+ uint32_t n1 = local_to_common_freq_numer_;
+ uint32_t n2 = 1000000 + cur_slew_;
+
+ uint32_t d1 = local_to_common_freq_denom_;
+ uint32_t d2 = 1000000;
+
+ // n1/d1 has already been reduced, no need to do so here.
+ LinearTransform::reduce(&n1, &d2);
+ LinearTransform::reduce(&n2, &d1);
+ LinearTransform::reduce(&n2, &d2);
+
+ cur_trans_.a_zero = new_local_basis;
+ cur_trans_.b_zero = new_common_basis;
+ cur_trans_.a_to_b_numer = n1 * n2;
+ cur_trans_.a_to_b_denom = d1 * d2;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/services/common_time/common_clock.h b/services/common_time/common_clock.h
new file mode 100644
index 0000000..b786fdc
--- /dev/null
+++ b/services/common_time/common_clock.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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 __COMMON_CLOCK_H__
+#define __COMMON_CLOCK_H__
+
+#include <stdint.h>
+
+#include <utils/Errors.h>
+#include <utils/LinearTransform.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CommonClock {
+ public:
+ CommonClock();
+
+ bool init(uint64_t local_freq);
+
+ status_t localToCommon(int64_t local, int64_t *common_out) const;
+ status_t commonToLocal(int64_t common, int64_t *local_out) const;
+ int64_t localDurationToCommonDuration(int64_t localDur) const;
+ uint64_t getCommonFreq() const { return kCommonFreq; }
+ bool isValid() const { return cur_trans_valid_; }
+ status_t setSlew(int64_t change_time, int32_t ppm);
+ void setBasis(int64_t local, int64_t common);
+ void resetBasis();
+ private:
+ mutable Mutex lock_;
+
+ int32_t cur_slew_;
+ uint32_t local_to_common_freq_numer_;
+ uint32_t local_to_common_freq_denom_;
+
+ LinearTransform duration_trans_;
+ LinearTransform cur_trans_;
+ bool cur_trans_valid_;
+
+ static const uint64_t kCommonFreq = 1000000ull;
+};
+
+} // namespace android
+#endif // __COMMON_CLOCK_H__
diff --git a/services/common_time/common_clock_service.cpp b/services/common_time/common_clock_service.cpp
new file mode 100644
index 0000000..9ca6f35
--- /dev/null
+++ b/services/common_time/common_clock_service.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#include <common_time/local_clock.h>
+#include <utils/String8.h>
+
+#include "common_clock_service.h"
+#include "common_clock.h"
+#include "common_time_server.h"
+
+namespace android {
+
+sp<CommonClockService> CommonClockService::instantiate(
+ CommonTimeServer& timeServer) {
+ sp<CommonClockService> tcc = new CommonClockService(timeServer);
+ if (tcc == NULL)
+ return NULL;
+
+ defaultServiceManager()->addService(ICommonClock::kServiceName, tcc);
+ return tcc;
+}
+
+status_t CommonClockService::dump(int fd, const Vector<String16>& args) {
+ Mutex::Autolock lock(mRegistrationLock);
+ return mTimeServer.dumpClockInterface(fd, args, mListeners.size());
+}
+
+status_t CommonClockService::isCommonTimeValid(bool* valid,
+ uint32_t* timelineID) {
+ return mTimeServer.isCommonTimeValid(valid, timelineID);
+}
+
+status_t CommonClockService::commonTimeToLocalTime(int64_t commonTime,
+ int64_t* localTime) {
+ return mTimeServer.getCommonClock().commonToLocal(commonTime, localTime);
+}
+
+status_t CommonClockService::localTimeToCommonTime(int64_t localTime,
+ int64_t* commonTime) {
+ return mTimeServer.getCommonClock().localToCommon(localTime, commonTime);
+}
+
+status_t CommonClockService::getCommonTime(int64_t* commonTime) {
+ return localTimeToCommonTime(mTimeServer.getLocalClock().getLocalTime(), commonTime);
+}
+
+status_t CommonClockService::getCommonFreq(uint64_t* freq) {
+ *freq = mTimeServer.getCommonClock().getCommonFreq();
+ return OK;
+}
+
+status_t CommonClockService::getLocalTime(int64_t* localTime) {
+ *localTime = mTimeServer.getLocalClock().getLocalTime();
+ return OK;
+}
+
+status_t CommonClockService::getLocalFreq(uint64_t* freq) {
+ *freq = mTimeServer.getLocalClock().getLocalFreq();
+ return OK;
+}
+
+status_t CommonClockService::getEstimatedError(int32_t* estimate) {
+ *estimate = mTimeServer.getEstimatedError();
+ return OK;
+}
+
+status_t CommonClockService::getTimelineID(uint64_t* id) {
+ *id = mTimeServer.getTimelineID();
+ return OK;
+}
+
+status_t CommonClockService::getState(State* state) {
+ *state = mTimeServer.getState();
+ return OK;
+}
+
+status_t CommonClockService::getMasterAddr(struct sockaddr_storage* addr) {
+ return mTimeServer.getMasterAddr(addr);
+}
+
+status_t CommonClockService::registerListener(
+ const sp<ICommonClockListener>& listener) {
+ Mutex::Autolock lock(mRegistrationLock);
+
+ { // scoping for autolock pattern
+ Mutex::Autolock lock(mCallbackLock);
+ // check whether this is a duplicate
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ if (mListeners[i]->asBinder() == listener->asBinder())
+ return ALREADY_EXISTS;
+ }
+ }
+
+ mListeners.add(listener);
+ mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
+ return listener->asBinder()->linkToDeath(this);
+}
+
+status_t CommonClockService::unregisterListener(
+ const sp<ICommonClockListener>& listener) {
+ Mutex::Autolock lock(mRegistrationLock);
+ status_t ret_val = NAME_NOT_FOUND;
+
+ { // scoping for autolock pattern
+ Mutex::Autolock lock(mCallbackLock);
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ if (mListeners[i]->asBinder() == listener->asBinder()) {
+ mListeners[i]->asBinder()->unlinkToDeath(this);
+ mListeners.removeAt(i);
+ ret_val = OK;
+ break;
+ }
+ }
+ }
+
+ mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
+ return ret_val;
+}
+
+void CommonClockService::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock lock(mRegistrationLock);
+
+ { // scoping for autolock pattern
+ Mutex::Autolock lock(mCallbackLock);
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ if (mListeners[i]->asBinder() == who) {
+ mListeners.removeAt(i);
+ break;
+ }
+ }
+ }
+
+ mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
+}
+
+void CommonClockService::notifyOnTimelineChanged(uint64_t timelineID) {
+ Mutex::Autolock lock(mCallbackLock);
+
+ for (size_t i = 0; i < mListeners.size(); i++) {
+ mListeners[i]->onTimelineChanged(timelineID);
+ }
+}
+
+}; // namespace android
diff --git a/services/common_time/common_clock_service.h b/services/common_time/common_clock_service.h
new file mode 100644
index 0000000..a65e398
--- /dev/null
+++ b/services/common_time/common_clock_service.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#include <common_time/ICommonClock.h>
+
+#ifndef ANDROID_COMMON_CLOCK_SERVICE_H
+#define ANDROID_COMMON_CLOCK_SERVICE_H
+
+namespace android {
+
+class CommonTimeServer;
+
+class CommonClockService : public BnCommonClock,
+ public android::IBinder::DeathRecipient {
+ public:
+ static sp<CommonClockService> instantiate(CommonTimeServer& timeServer);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t isCommonTimeValid(bool* valid, uint32_t *timelineID);
+ virtual status_t commonTimeToLocalTime(int64_t common_time,
+ int64_t* local_time);
+ virtual status_t localTimeToCommonTime(int64_t local_time,
+ int64_t* common_time);
+ virtual status_t getCommonTime(int64_t* common_time);
+ virtual status_t getCommonFreq(uint64_t* freq);
+ virtual status_t getLocalTime(int64_t* local_time);
+ virtual status_t getLocalFreq(uint64_t* freq);
+ virtual status_t getEstimatedError(int32_t* estimate);
+ virtual status_t getTimelineID(uint64_t* id);
+ virtual status_t getState(ICommonClock::State* state);
+ virtual status_t getMasterAddr(struct sockaddr_storage* addr);
+
+ virtual status_t registerListener(
+ const sp<ICommonClockListener>& listener);
+ virtual status_t unregisterListener(
+ const sp<ICommonClockListener>& listener);
+
+ void notifyOnTimelineChanged(uint64_t timelineID);
+
+ private:
+ CommonClockService(CommonTimeServer& timeServer)
+ : mTimeServer(timeServer) { };
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ CommonTimeServer& mTimeServer;
+
+ // locks used to synchronize access to the list of registered listeners.
+ // The callback lock is held whenever the list is used to perform callbacks
+ // or while the list is being modified. The registration lock used to
+ // serialize access across registerListener, unregisterListener, and
+ // binderDied.
+ //
+ // The reason for two locks is that registerListener, unregisterListener,
+ // and binderDied each call into the core service and obtain the core
+ // service thread lock when they call reevaluateAutoDisableState. The core
+ // service thread obtains the main thread lock whenever its thread is
+ // running, and sometimes needs to call notifyOnTimelineChanged which then
+ // obtains the callback lock. If callers of registration functions were
+ // holding the callback lock when they called into the core service, we
+ // would have a classic A/B, B/A ordering deadlock. To avoid this, the
+ // registration functions hold the registration lock for the duration of
+ // their call, but hold the callback lock only while they mutate the list.
+ // This way, the list's size cannot change (because of the registration
+ // lock) during the call into reevaluateAutoDisableState, but the core work
+ // thread can still safely call notifyOnTimelineChanged while holding the
+ // main thread lock.
+ Mutex mCallbackLock;
+ Mutex mRegistrationLock;
+
+ Vector<sp<ICommonClockListener> > mListeners;
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMMON_CLOCK_SERVICE_H
diff --git a/services/common_time/common_time_config_service.cpp b/services/common_time/common_time_config_service.cpp
new file mode 100644
index 0000000..9585618
--- /dev/null
+++ b/services/common_time/common_time_config_service.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+
+#include "common_time_config_service.h"
+#include "common_time_server.h"
+
+namespace android {
+
+sp<CommonTimeConfigService> CommonTimeConfigService::instantiate(
+ CommonTimeServer& timeServer) {
+ sp<CommonTimeConfigService> ctcs = new CommonTimeConfigService(timeServer);
+ if (ctcs == NULL)
+ return NULL;
+
+ defaultServiceManager()->addService(ICommonTimeConfig::kServiceName, ctcs);
+ return ctcs;
+}
+
+status_t CommonTimeConfigService::dump(int fd, const Vector<String16>& args) {
+ return mTimeServer.dumpConfigInterface(fd, args);
+}
+
+status_t CommonTimeConfigService::getMasterElectionPriority(uint8_t *priority) {
+ return mTimeServer.getMasterElectionPriority(priority);
+}
+
+status_t CommonTimeConfigService::setMasterElectionPriority(uint8_t priority) {
+ return mTimeServer.setMasterElectionPriority(priority);
+}
+
+status_t CommonTimeConfigService::getMasterElectionEndpoint(
+ struct sockaddr_storage *addr) {
+ return mTimeServer.getMasterElectionEndpoint(addr);
+}
+
+status_t CommonTimeConfigService::setMasterElectionEndpoint(
+ const struct sockaddr_storage *addr) {
+ return mTimeServer.setMasterElectionEndpoint(addr);
+}
+
+status_t CommonTimeConfigService::getMasterElectionGroupId(uint64_t *id) {
+ return mTimeServer.getMasterElectionGroupId(id);
+}
+
+status_t CommonTimeConfigService::setMasterElectionGroupId(uint64_t id) {
+ return mTimeServer.setMasterElectionGroupId(id);
+}
+
+status_t CommonTimeConfigService::getInterfaceBinding(String16& ifaceName) {
+ String8 tmp;
+ status_t ret = mTimeServer.getInterfaceBinding(tmp);
+ ifaceName = String16(tmp);
+ return ret;
+}
+
+status_t CommonTimeConfigService::setInterfaceBinding(const String16& ifaceName) {
+ String8 tmp(ifaceName);
+ return mTimeServer.setInterfaceBinding(tmp);
+}
+
+status_t CommonTimeConfigService::getMasterAnnounceInterval(int *interval) {
+ return mTimeServer.getMasterAnnounceInterval(interval);
+}
+
+status_t CommonTimeConfigService::setMasterAnnounceInterval(int interval) {
+ return mTimeServer.setMasterAnnounceInterval(interval);
+}
+
+status_t CommonTimeConfigService::getClientSyncInterval(int *interval) {
+ return mTimeServer.getClientSyncInterval(interval);
+}
+
+status_t CommonTimeConfigService::setClientSyncInterval(int interval) {
+ return mTimeServer.setClientSyncInterval(interval);
+}
+
+status_t CommonTimeConfigService::getPanicThreshold(int *threshold) {
+ return mTimeServer.getPanicThreshold(threshold);
+}
+
+status_t CommonTimeConfigService::setPanicThreshold(int threshold) {
+ return mTimeServer.setPanicThreshold(threshold);
+}
+
+status_t CommonTimeConfigService::getAutoDisable(bool *autoDisable) {
+ return mTimeServer.getAutoDisable(autoDisable);
+}
+
+status_t CommonTimeConfigService::setAutoDisable(bool autoDisable) {
+ return mTimeServer.setAutoDisable(autoDisable);
+}
+
+status_t CommonTimeConfigService::forceNetworklessMasterMode() {
+ return mTimeServer.forceNetworklessMasterMode();
+}
+
+}; // namespace android
diff --git a/services/common_time/common_time_config_service.h b/services/common_time/common_time_config_service.h
new file mode 100644
index 0000000..8283c24
--- /dev/null
+++ b/services/common_time/common_time_config_service.h
@@ -0,0 +1,59 @@
+/* * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common_time/ICommonTimeConfig.h>
+
+#ifndef ANDROID_COMMON_TIME_CONFIG_SERVICE_H
+#define ANDROID_COMMON_TIME_CONFIG_SERVICE_H
+
+namespace android {
+
+class String16;
+class CommonTimeServer;
+
+class CommonTimeConfigService : public BnCommonTimeConfig {
+ public:
+ static sp<CommonTimeConfigService> instantiate(CommonTimeServer& timeServer);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t getMasterElectionPriority(uint8_t *priority);
+ virtual status_t setMasterElectionPriority(uint8_t priority);
+ virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr);
+ virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr);
+ virtual status_t getMasterElectionGroupId(uint64_t *id);
+ virtual status_t setMasterElectionGroupId(uint64_t id);
+ virtual status_t getInterfaceBinding(String16& ifaceName);
+ virtual status_t setInterfaceBinding(const String16& ifaceName);
+ virtual status_t getMasterAnnounceInterval(int *interval);
+ virtual status_t setMasterAnnounceInterval(int interval);
+ virtual status_t getClientSyncInterval(int *interval);
+ virtual status_t setClientSyncInterval(int interval);
+ virtual status_t getPanicThreshold(int *threshold);
+ virtual status_t setPanicThreshold(int threshold);
+ virtual status_t getAutoDisable(bool *autoDisable);
+ virtual status_t setAutoDisable(bool autoDisable);
+ virtual status_t forceNetworklessMasterMode();
+
+ private:
+ CommonTimeConfigService(CommonTimeServer& timeServer)
+ : mTimeServer(timeServer) { }
+ CommonTimeServer& mTimeServer;
+
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMMON_TIME_CONFIG_SERVICE_H
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
new file mode 100644
index 0000000..ef7fa168
--- /dev/null
+++ b/services/common_time/common_time_server.cpp
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/if_ether.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/ip.h>
+#include <poll.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <common_time/local_clock.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <utils/Timers.h>
+
+#include "common_clock_service.h"
+#include "common_time_config_service.h"
+#include "common_time_server.h"
+#include "common_time_server_packets.h"
+#include "clock_recovery.h"
+#include "common_clock.h"
+
+#define MAX_INT ((int)0x7FFFFFFF)
+
+namespace android {
+
+const char* CommonTimeServer::kDefaultMasterElectionAddr = "239.195.128.88";
+const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8887;
+const uint64_t CommonTimeServer::kDefaultSyncGroupID = 0;
+const uint8_t CommonTimeServer::kDefaultMasterPriority = 1;
+const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000;
+const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000;
+const uint32_t CommonTimeServer::kDefaultPanicThresholdUsec = 50000;
+const bool CommonTimeServer::kDefaultAutoDisable = true;
+const int CommonTimeServer::kSetupRetryTimeoutMs = 30000;
+const int64_t CommonTimeServer::kNoGoodDataPanicThresholdUsec = 600000000ll;
+const uint32_t CommonTimeServer::kRTTDiscardPanicThreshMultiplier = 5;
+
+// timeout value representing an infinite timeout
+const int CommonTimeServer::kInfiniteTimeout = -1;
+
+/*** Initial state constants ***/
+
+// number of WhoIsMaster attempts sent before giving up
+const int CommonTimeServer::kInitial_NumWhoIsMasterRetries = 6;
+
+// timeout used when waiting for a response to a WhoIsMaster request
+const int CommonTimeServer::kInitial_WhoIsMasterTimeoutMs = 500;
+
+/*** Client state constants ***/
+
+// number of sync requests that can fail before a client assumes its master
+// is dead
+const int CommonTimeServer::kClient_NumSyncRequestRetries = 5;
+
+/*** Master state constants ***/
+
+/*** Ronin state constants ***/
+
+// number of WhoIsMaster attempts sent before declaring ourselves master
+const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 4;
+
+// timeout used when waiting for a response to a WhoIsMaster request
+const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500;
+
+/*** WaitForElection state constants ***/
+
+// how long do we wait for an announcement from a master before
+// trying another election?
+const int CommonTimeServer::kWaitForElection_TimeoutMs = 5000;
+
+CommonTimeServer::CommonTimeServer()
+ : Thread(false)
+ , mState(ICommonClock::STATE_INITIAL)
+ , mClockRecovery(&mLocalClock, &mCommonClock)
+ , mSocket(-1)
+ , mLastPacketRxLocalTime(0)
+ , mTimelineID(ICommonClock::kInvalidTimelineID)
+ , mClockSynced(false)
+ , mCommonClockHasClients(false)
+ , mInitial_WhoIsMasterRequestTimeouts(0)
+ , mClient_MasterDeviceID(0)
+ , mClient_MasterDevicePriority(0)
+ , mRonin_WhoIsMasterRequestTimeouts(0) {
+ // zero out sync stats
+ resetSyncStats();
+
+ // Setup the master election endpoint to use the default.
+ struct sockaddr_in* meep =
+ reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP);
+ memset(&mMasterElectionEP, 0, sizeof(mMasterElectionEP));
+ inet_aton(kDefaultMasterElectionAddr, &meep->sin_addr);
+ meep->sin_family = AF_INET;
+ meep->sin_port = htons(kDefaultMasterElectionPort);
+
+ // Zero out the master endpoint.
+ memset(&mMasterEP, 0, sizeof(mMasterEP));
+ mMasterEPValid = false;
+ mBindIfaceValid = false;
+ setForceLowPriority(false);
+
+ // Set all remaining configuration parameters to their defaults.
+ mDeviceID = 0;
+ mSyncGroupID = kDefaultSyncGroupID;
+ mMasterPriority = kDefaultMasterPriority;
+ mMasterAnnounceIntervalMs = kDefaultMasterAnnounceIntervalMs;
+ mSyncRequestIntervalMs = kDefaultSyncRequestIntervalMs;
+ mPanicThresholdUsec = kDefaultPanicThresholdUsec;
+ mAutoDisable = kDefaultAutoDisable;
+
+ // Create the eventfd we will use to signal our thread to wake up when
+ // needed.
+ mWakeupThreadFD = eventfd(0, EFD_NONBLOCK);
+
+ // seed the random number generator (used to generated timeline IDs)
+ srand48(static_cast<unsigned int>(systemTime()));
+}
+
+CommonTimeServer::~CommonTimeServer() {
+ shutdownThread();
+
+ // No need to grab the lock here. We are in the destructor; if the the user
+ // has a thread in any of the APIs while the destructor is being called,
+ // there is a threading problem a the application level we cannot reasonably
+ // do anything about.
+ cleanupSocket_l();
+
+ if (mWakeupThreadFD >= 0) {
+ close(mWakeupThreadFD);
+ mWakeupThreadFD = -1;
+ }
+}
+
+bool CommonTimeServer::startServices() {
+ // start the ICommonClock service
+ mICommonClock = CommonClockService::instantiate(*this);
+ if (mICommonClock == NULL)
+ return false;
+
+ // start the ICommonTimeConfig service
+ mICommonTimeConfig = CommonTimeConfigService::instantiate(*this);
+ if (mICommonTimeConfig == NULL)
+ return false;
+
+ return true;
+}
+
+bool CommonTimeServer::threadLoop() {
+ // Register our service interfaces.
+ if (!startServices())
+ return false;
+
+ // Hold the lock while we are in the main thread loop. It will release the
+ // lock when it blocks, and hold the lock at all other times.
+ mLock.lock();
+ runStateMachine_l();
+ mLock.unlock();
+
+ IPCThreadState::self()->stopProcess();
+ return false;
+}
+
+bool CommonTimeServer::runStateMachine_l() {
+ if (!mLocalClock.initCheck())
+ return false;
+
+ if (!mCommonClock.init(mLocalClock.getLocalFreq()))
+ return false;
+
+ // Enter the initial state.
+ becomeInitial("startup");
+
+ // run the state machine
+ while (!exitPending()) {
+ struct pollfd pfds[2];
+ int rc;
+ int eventCnt = 0;
+ int64_t wakeupTime;
+
+ // We are always interested in our wakeup FD.
+ pfds[eventCnt].fd = mWakeupThreadFD;
+ pfds[eventCnt].events = POLLIN;
+ pfds[eventCnt].revents = 0;
+ eventCnt++;
+
+ // If we have a valid socket, then we are interested in what it has to
+ // say as well.
+ if (mSocket >= 0) {
+ pfds[eventCnt].fd = mSocket;
+ pfds[eventCnt].events = POLLIN;
+ pfds[eventCnt].revents = 0;
+ eventCnt++;
+ }
+
+ // Note, we were holding mLock when this function was called. We
+ // release it only while we are blocking and hold it at all other times.
+ mLock.unlock();
+ rc = poll(pfds, eventCnt, mCurTimeout.msecTillTimeout());
+ wakeupTime = mLocalClock.getLocalTime();
+ mLock.lock();
+
+ // Is it time to shutdown? If so, don't hesitate... just do it.
+ if (exitPending())
+ break;
+
+ // Did the poll fail? This should never happen and is fatal if it does.
+ if (rc < 0) {
+ ALOGE("%s:%d poll failed", __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+
+ if (rc == 0)
+ mCurTimeout.setTimeout(kInfiniteTimeout);
+
+ // Were we woken up on purpose? If so, clear the eventfd with a read.
+ if (pfds[0].revents)
+ clearPendingWakeupEvents_l();
+
+ // Is out bind address dirty? If so, clean up our socket (if any).
+ // Alternatively, do we have an active socket but should be auto
+ // disabled? If so, release the socket and enter the proper sync state.
+ bool droppedSocket = false;
+ if (mBindIfaceDirty || ((mSocket >= 0) && shouldAutoDisable())) {
+ cleanupSocket_l();
+ mBindIfaceDirty = false;
+ droppedSocket = true;
+ }
+
+ // Do we not have a socket but should have one? If so, try to set one
+ // up.
+ if ((mSocket < 0) && mBindIfaceValid && !shouldAutoDisable()) {
+ if (setupSocket_l()) {
+ // Success! We are now joining a new network (either coming
+ // from no network, or coming from a potentially different
+ // network). Force our priority to be lower so that we defer to
+ // any other masters which may already be on the network we are
+ // joining. Later, when we enter either the client or the
+ // master state, we will clear this flag and go back to our
+ // normal election priority.
+ setForceLowPriority(true);
+ switch (mState) {
+ // If we were in initial (whether we had a immediately
+ // before this network or not) we want to simply reset the
+ // system and start again. Forcing a transition from
+ // INITIAL to INITIAL should do the job.
+ case CommonClockService::STATE_INITIAL:
+ becomeInitial("bound interface");
+ break;
+
+ // If we were in the master state, then either we were the
+ // master in a no-network situation, or we were the master
+ // of a different network and have moved to a new interface.
+ // In either case, immediately send out a master
+ // announcement at low priority.
+ case CommonClockService::STATE_MASTER:
+ sendMasterAnnouncement();
+ break;
+
+ // If we were in any other state (CLIENT, RONIN, or
+ // WAIT_FOR_ELECTION) then we must be moving from one
+ // network to another. We have lost our old master;
+ // transition to RONIN in an attempt to find a new master.
+ // If there are none out there, we will just assume
+ // responsibility for the timeline we used to be a client
+ // of.
+ default:
+ becomeRonin("bound interface");
+ break;
+ }
+ } else {
+ // That's odd... we failed to set up our socket. This could be
+ // due to some transient network change which will work itself
+ // out shortly; schedule a retry attempt in the near future.
+ mCurTimeout.setTimeout(kSetupRetryTimeoutMs);
+ }
+
+ // One way or the other, we don't have any data to process at this
+ // point (since we just tried to bulid a new socket). Loop back
+ // around and wait for the next thing to do.
+ continue;
+ } else if (droppedSocket) {
+ // We just lost our socket, and for whatever reason (either no
+ // config, or auto disable engaged) we are not supposed to rebuild
+ // one at this time. We are not going to rebuild our socket until
+ // something about our config/auto-disabled status changes, so we
+ // are basically in network-less mode. If we are already in either
+ // INITIAL or MASTER, just stay there until something changes. If
+ // we are in any other state (CLIENT, RONIN or WAIT_FOR_ELECTION),
+ // then transition to either INITIAL or MASTER depending on whether
+ // or not our timeline is valid.
+ ALOGI("Entering networkless mode interface is %s, "
+ "shouldAutoDisable = %s",
+ mBindIfaceValid ? "valid" : "invalid",
+ shouldAutoDisable() ? "true" : "false");
+ if ((mState != ICommonClock::STATE_INITIAL) &&
+ (mState != ICommonClock::STATE_MASTER)) {
+ if (mTimelineID == ICommonClock::kInvalidTimelineID)
+ becomeInitial("network-less mode");
+ else
+ becomeMaster("network-less mode");
+ }
+
+ continue;
+ }
+
+ // Did we wakeup with no signalled events across all of our FDs? If so,
+ // we must have hit our timeout.
+ if (rc == 0) {
+ if (!handleTimeout())
+ ALOGE("handleTimeout failed");
+ continue;
+ }
+
+ // Does our socket have data for us (assuming we still have one, we
+ // may have RXed a packet at the same time as a config change telling us
+ // to shut our socket down)? If so, process its data.
+ if ((mSocket >= 0) && (eventCnt > 1) && (pfds[1].revents)) {
+ mLastPacketRxLocalTime = wakeupTime;
+ if (!handlePacket())
+ ALOGE("handlePacket failed");
+ }
+ }
+
+ cleanupSocket_l();
+ return true;
+}
+
+void CommonTimeServer::clearPendingWakeupEvents_l() {
+ int64_t tmp;
+ read(mWakeupThreadFD, &tmp, sizeof(tmp));
+}
+
+void CommonTimeServer::wakeupThread_l() {
+ int64_t tmp = 1;
+ write(mWakeupThreadFD, &tmp, sizeof(tmp));
+}
+
+void CommonTimeServer::cleanupSocket_l() {
+ if (mSocket >= 0) {
+ close(mSocket);
+ mSocket = -1;
+ }
+}
+
+void CommonTimeServer::shutdownThread() {
+ // Flag the work thread for shutdown.
+ this->requestExit();
+
+ // Signal the thread in case its sleeping.
+ mLock.lock();
+ wakeupThread_l();
+ mLock.unlock();
+
+ // Wait for the thread to exit.
+ this->join();
+}
+
+bool CommonTimeServer::setupSocket_l() {
+ int rc;
+ bool ret_val = false;
+ struct sockaddr_in* ipv4_addr = NULL;
+ char masterElectionEPStr[64];
+ const int one = 1;
+
+ // This should never be needed, but if we happened to have an old socket
+ // lying around, be sure to not leak it before proceeding.
+ cleanupSocket_l();
+
+ // If we don't have a valid endpoint to bind to, then how did we get here in
+ // the first place? Regardless, we know that we are going to fail to bind,
+ // so don't even try.
+ if (!mBindIfaceValid)
+ return false;
+
+ sockaddrToString(mMasterElectionEP, true, masterElectionEPStr,
+ sizeof(masterElectionEPStr));
+ ALOGI("Building socket :: bind = %s master election = %s",
+ mBindIface.string(), masterElectionEPStr);
+
+ // TODO: add proper support for IPv6. Right now, we block IPv6 addresses at
+ // the configuration interface level.
+ if (AF_INET != mMasterElectionEP.ss_family) {
+ ALOGW("TODO: add proper IPv6 support");
+ goto bailout;
+ }
+
+ // open a UDP socket for the timeline serivce
+ mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (mSocket < 0) {
+ ALOGE("Failed to create socket (errno = %d)", errno);
+ goto bailout;
+ }
+
+ // Bind to the selected interface using Linux's spiffy SO_BINDTODEVICE.
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", mBindIface.string());
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0;
+ rc = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE,
+ (void *)&ifr, sizeof(ifr));
+ if (rc) {
+ ALOGE("Failed to bind socket at to interface %s (errno = %d)",
+ ifr.ifr_name, errno);
+ goto bailout;
+ }
+
+ // Bind our socket to INADDR_ANY and the master election port. The
+ // interface binding we made using SO_BINDTODEVICE should limit us to
+ // traffic only on the interface we are interested in. We need to bind to
+ // INADDR_ANY and the specific master election port in order to be able to
+ // receive both unicast traffic and master election multicast traffic with
+ // just a single socket.
+ struct sockaddr_in bindAddr;
+ ipv4_addr = reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP);
+ memcpy(&bindAddr, ipv4_addr, sizeof(bindAddr));
+ bindAddr.sin_addr.s_addr = INADDR_ANY;
+ rc = bind(mSocket,
+ reinterpret_cast<const sockaddr *>(&bindAddr),
+ sizeof(bindAddr));
+ if (rc) {
+ ALOGE("Failed to bind socket to port %hu (errno = %d)",
+ ntohs(bindAddr.sin_port), errno);
+ goto bailout;
+ }
+
+ if (0xE0000000 == (ntohl(ipv4_addr->sin_addr.s_addr) & 0xF0000000)) {
+ // If our master election endpoint is a multicast address, be sure to join
+ // the multicast group.
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = ipv4_addr->sin_addr;
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ rc = setsockopt(mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &mreq, sizeof(mreq));
+ if (rc == -1) {
+ ALOGE("Failed to join multicast group at %s. (errno = %d)",
+ masterElectionEPStr, errno);
+ goto bailout;
+ }
+
+ // disable loopback of multicast packets
+ const int zero = 0;
+ rc = setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
+ &zero, sizeof(zero));
+ if (rc == -1) {
+ ALOGE("Failed to disable multicast loopback (errno = %d)", errno);
+ goto bailout;
+ }
+ } else
+ if (ntohl(ipv4_addr->sin_addr.s_addr) != 0xFFFFFFFF) {
+ // If the master election address is neither broadcast, nor multicast,
+ // then we are misconfigured. The config API layer should prevent this
+ // from ever happening.
+ goto bailout;
+ }
+
+ // Set the TTL of sent packets to 1. (Time protocol sync should never leave
+ // the local subnet)
+ rc = setsockopt(mSocket, IPPROTO_IP, IP_TTL, &one, sizeof(one));
+ if (rc == -1) {
+ ALOGE("Failed to set TTL to %d (errno = %d)", one, errno);
+ goto bailout;
+ }
+
+ // get the device's unique ID
+ if (!assignDeviceID())
+ goto bailout;
+
+ ret_val = true;
+
+bailout:
+ if (!ret_val)
+ cleanupSocket_l();
+ return ret_val;
+}
+
+// generate a unique device ID that can be used for arbitration
+bool CommonTimeServer::assignDeviceID() {
+ if (!mBindIfaceValid)
+ return false;
+
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_addr.sa_family = AF_INET;
+ strlcpy(ifr.ifr_name, mBindIface.string(), IFNAMSIZ);
+
+ int rc = ioctl(mSocket, SIOCGIFHWADDR, &ifr);
+ if (rc) {
+ ALOGE("%s:%d ioctl failed", __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+
+ if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) {
+ ALOGE("%s:%d got non-Ethernet address", __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+
+ mDeviceID = 0;
+ for (int i = 0; i < ETH_ALEN; i++) {
+ mDeviceID = (mDeviceID << 8) | ifr.ifr_hwaddr.sa_data[i];
+ }
+
+ return true;
+}
+
+// generate a new timeline ID
+void CommonTimeServer::assignTimelineID() {
+ do {
+ mTimelineID = (static_cast<uint64_t>(lrand48()) << 32)
+ | static_cast<uint64_t>(lrand48());
+ } while (mTimelineID == ICommonClock::kInvalidTimelineID);
+}
+
+// Select a preference between the device IDs of two potential masters.
+// Returns true if the first ID wins, or false if the second ID wins.
+bool CommonTimeServer::arbitrateMaster(
+ uint64_t deviceID1, uint8_t devicePrio1,
+ uint64_t deviceID2, uint8_t devicePrio2) {
+ return ((devicePrio1 > devicePrio2) ||
+ ((devicePrio1 == devicePrio2) && (deviceID1 > deviceID2)));
+}
+
+bool CommonTimeServer::handlePacket() {
+ uint8_t buf[256];
+ struct sockaddr_storage srcAddr;
+ socklen_t srcAddrLen = sizeof(srcAddr);
+
+ ssize_t recvBytes = recvfrom(
+ mSocket, buf, sizeof(buf), 0,
+ reinterpret_cast<const sockaddr *>(&srcAddr), &srcAddrLen);
+
+ if (recvBytes < 0) {
+ ALOGE("%s:%d recvfrom failed", __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+
+ UniversalTimeServicePacket pkt;
+ recvBytes = pkt.deserializePacket(buf, recvBytes, mSyncGroupID);
+ if (recvBytes < 0)
+ return false;
+
+ bool result;
+ switch (pkt.packetType) {
+ case TIME_PACKET_WHO_IS_MASTER_REQUEST:
+ result = handleWhoIsMasterRequest(&pkt.p.who_is_master_request,
+ srcAddr);
+ break;
+
+ case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
+ result = handleWhoIsMasterResponse(&pkt.p.who_is_master_response,
+ srcAddr);
+ break;
+
+ case TIME_PACKET_SYNC_REQUEST:
+ result = handleSyncRequest(&pkt.p.sync_request, srcAddr);
+ break;
+
+ case TIME_PACKET_SYNC_RESPONSE:
+ result = handleSyncResponse(&pkt.p.sync_response, srcAddr);
+ break;
+
+ case TIME_PACKET_MASTER_ANNOUNCEMENT:
+ result = handleMasterAnnouncement(&pkt.p.master_announcement,
+ srcAddr);
+ break;
+
+ default: {
+ ALOGD("%s:%d unknown packet type(%d)",
+ __PRETTY_FUNCTION__, __LINE__, pkt.packetType);
+ result = false;
+ } break;
+ }
+
+ return result;
+}
+
+bool CommonTimeServer::handleTimeout() {
+ // If we have no socket, then this must be a timeout to retry socket setup.
+ if (mSocket < 0)
+ return true;
+
+ switch (mState) {
+ case ICommonClock::STATE_INITIAL:
+ return handleTimeoutInitial();
+ case ICommonClock::STATE_CLIENT:
+ return handleTimeoutClient();
+ case ICommonClock::STATE_MASTER:
+ return handleTimeoutMaster();
+ case ICommonClock::STATE_RONIN:
+ return handleTimeoutRonin();
+ case ICommonClock::STATE_WAIT_FOR_ELECTION:
+ return handleTimeoutWaitForElection();
+ }
+
+ return false;
+}
+
+bool CommonTimeServer::handleTimeoutInitial() {
+ if (++mInitial_WhoIsMasterRequestTimeouts ==
+ kInitial_NumWhoIsMasterRetries) {
+ // none of our attempts to discover a master succeeded, so make
+ // this device the master
+ return becomeMaster("initial timeout");
+ } else {
+ // retry the WhoIsMaster request
+ return sendWhoIsMasterRequest();
+ }
+}
+
+bool CommonTimeServer::handleTimeoutClient() {
+ if (shouldPanicNotGettingGoodData())
+ return becomeInitial("timeout panic, no good data");
+
+ if (mClient_SyncRequestPending) {
+ mClient_SyncRequestPending = false;
+
+ if (++mClient_SyncRequestTimeouts < kClient_NumSyncRequestRetries) {
+ // a sync request has timed out, so retry
+ return sendSyncRequest();
+ } else {
+ // The master has failed to respond to a sync request for too many
+ // times in a row. Assume the master is dead and start electing
+ // a new master.
+ return becomeRonin("master not responding");
+ }
+ } else {
+ // initiate the next sync request
+ return sendSyncRequest();
+ }
+}
+
+bool CommonTimeServer::handleTimeoutMaster() {
+ // send another announcement from the master
+ return sendMasterAnnouncement();
+}
+
+bool CommonTimeServer::handleTimeoutRonin() {
+ if (++mRonin_WhoIsMasterRequestTimeouts == kRonin_NumWhoIsMasterRetries) {
+ // no other master is out there, so we won the election
+ return becomeMaster("no better masters detected");
+ } else {
+ return sendWhoIsMasterRequest();
+ }
+}
+
+bool CommonTimeServer::handleTimeoutWaitForElection() {
+ return becomeRonin("timeout waiting for election conclusion");
+}
+
+bool CommonTimeServer::handleWhoIsMasterRequest(
+ const WhoIsMasterRequestPacket* request,
+ const sockaddr_storage& srcAddr) {
+ if (mState == ICommonClock::STATE_MASTER) {
+ // is this request related to this master's timeline?
+ if (request->timelineID != ICommonClock::kInvalidTimelineID &&
+ request->timelineID != mTimelineID)
+ return true;
+
+ WhoIsMasterResponsePacket pkt;
+ pkt.initHeader(mTimelineID, mSyncGroupID);
+ pkt.deviceID = mDeviceID;
+ pkt.devicePriority = effectivePriority();
+
+ uint8_t buf[256];
+ ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+ if (bufSz < 0)
+ return false;
+
+ ssize_t sendBytes = sendto(
+ mSocket, buf, bufSz, 0,
+ reinterpret_cast<const sockaddr *>(&srcAddr),
+ sizeof(srcAddr));
+ if (sendBytes == -1) {
+ ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+ } else if (mState == ICommonClock::STATE_RONIN) {
+ // if we hear a WhoIsMaster request from another device following
+ // the same timeline and that device wins arbitration, then we will stop
+ // trying to elect ourselves master and will instead wait for an
+ // announcement from the election winner
+ if (request->timelineID != mTimelineID)
+ return true;
+
+ if (arbitrateMaster(request->senderDeviceID,
+ request->senderDevicePriority,
+ mDeviceID,
+ effectivePriority()))
+ return becomeWaitForElection("would lose election");
+
+ return true;
+ } else if (mState == ICommonClock::STATE_INITIAL) {
+ // If a group of devices booted simultaneously (e.g. after a power
+ // outage) and all of them are in the initial state and there is no
+ // master, then each device may time out and declare itself master at
+ // the same time. To avoid this, listen for
+ // WhoIsMaster(InvalidTimeline) requests from peers. If we would lose
+ // arbitration against that peer, reset our timeout count so that the
+ // peer has a chance to become master before we time out.
+ if (request->timelineID == ICommonClock::kInvalidTimelineID &&
+ arbitrateMaster(request->senderDeviceID,
+ request->senderDevicePriority,
+ mDeviceID,
+ effectivePriority())) {
+ mInitial_WhoIsMasterRequestTimeouts = 0;
+ }
+ }
+
+ return true;
+}
+
+bool CommonTimeServer::handleWhoIsMasterResponse(
+ const WhoIsMasterResponsePacket* response,
+ const sockaddr_storage& srcAddr) {
+ if (mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN) {
+ return becomeClient(srcAddr,
+ response->deviceID,
+ response->devicePriority,
+ response->timelineID,
+ "heard whois response");
+ } else if (mState == ICommonClock::STATE_CLIENT) {
+ // if we get multiple responses because there are multiple devices
+ // who believe that they are master, then follow the master that
+ // wins arbitration
+ if (arbitrateMaster(response->deviceID,
+ response->devicePriority,
+ mClient_MasterDeviceID,
+ mClient_MasterDevicePriority)) {
+ return becomeClient(srcAddr,
+ response->deviceID,
+ response->devicePriority,
+ response->timelineID,
+ "heard whois response");
+ }
+ }
+
+ return true;
+}
+
+bool CommonTimeServer::handleSyncRequest(const SyncRequestPacket* request,
+ const sockaddr_storage& srcAddr) {
+ SyncResponsePacket pkt;
+ pkt.initHeader(mTimelineID, mSyncGroupID);
+
+ if ((mState == ICommonClock::STATE_MASTER) &&
+ (mTimelineID == request->timelineID)) {
+ int64_t rxLocalTime = mLastPacketRxLocalTime;
+ int64_t rxCommonTime;
+
+ // If we are master on an actual network and have actual clients, then
+ // we are no longer low priority.
+ setForceLowPriority(false);
+
+ if (OK != mCommonClock.localToCommon(rxLocalTime, &rxCommonTime)) {
+ return false;
+ }
+
+ int64_t txLocalTime = mLocalClock.getLocalTime();;
+ int64_t txCommonTime;
+ if (OK != mCommonClock.localToCommon(txLocalTime, &txCommonTime)) {
+ return false;
+ }
+
+ pkt.nak = 0;
+ pkt.clientTxLocalTime = request->clientTxLocalTime;
+ pkt.masterRxCommonTime = rxCommonTime;
+ pkt.masterTxCommonTime = txCommonTime;
+ } else {
+ pkt.nak = 1;
+ pkt.clientTxLocalTime = 0;
+ pkt.masterRxCommonTime = 0;
+ pkt.masterTxCommonTime = 0;
+ }
+
+ uint8_t buf[256];
+ ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+ if (bufSz < 0)
+ return false;
+
+ ssize_t sendBytes = sendto(
+ mSocket, &buf, bufSz, 0,
+ reinterpret_cast<const sockaddr *>(&srcAddr),
+ sizeof(srcAddr));
+ if (sendBytes == -1) {
+ ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+bool CommonTimeServer::handleSyncResponse(
+ const SyncResponsePacket* response,
+ const sockaddr_storage& srcAddr) {
+ if (mState != ICommonClock::STATE_CLIENT)
+ return true;
+
+ assert(mMasterEPValid);
+ if (!sockaddrMatch(srcAddr, mMasterEP, true)) {
+ char srcEP[64], expectedEP[64];
+ sockaddrToString(srcAddr, true, srcEP, sizeof(srcEP));
+ sockaddrToString(mMasterEP, true, expectedEP, sizeof(expectedEP));
+ ALOGI("Dropping sync response from unexpected address."
+ " Expected %s Got %s", expectedEP, srcEP);
+ return true;
+ }
+
+ if (response->nak) {
+ // if our master is no longer accepting requests, then we need to find
+ // a new master
+ return becomeRonin("master NAK'ed");
+ }
+
+ mClient_SyncRequestPending = 0;
+ mClient_SyncRequestTimeouts = 0;
+ mClient_PacketRTTLog.logRX(response->clientTxLocalTime,
+ mLastPacketRxLocalTime);
+
+ bool result;
+ if (!(mClient_SyncRespsRXedFromCurMaster++)) {
+ // the first request/response exchange between a client and a master
+ // may take unusually long due to ARP, so discard it.
+ result = true;
+ } else {
+ int64_t clientTxLocalTime = response->clientTxLocalTime;
+ int64_t clientRxLocalTime = mLastPacketRxLocalTime;
+ int64_t masterTxCommonTime = response->masterTxCommonTime;
+ int64_t masterRxCommonTime = response->masterRxCommonTime;
+
+ int64_t rtt = (clientRxLocalTime - clientTxLocalTime);
+ int64_t avgLocal = (clientTxLocalTime + clientRxLocalTime) >> 1;
+ int64_t avgCommon = (masterTxCommonTime + masterRxCommonTime) >> 1;
+
+ // if the RTT of the packet is significantly larger than the panic
+ // threshold, we should simply discard it. Its better to do nothing
+ // than to take cues from a packet like that.
+ int rttCommon = mCommonClock.localDurationToCommonDuration(rtt);
+ if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) *
+ kRTTDiscardPanicThreshMultiplier)) {
+ ALOGV("Dropping sync response with RTT of %lld uSec", rttCommon);
+ mClient_ExpiredSyncRespsRXedFromCurMaster++;
+ if (shouldPanicNotGettingGoodData())
+ return becomeInitial("RX panic, no good data");
+ } else {
+ result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon);
+ mClient_LastGoodSyncRX = clientRxLocalTime;
+
+ if (result) {
+ // indicate to listeners that we've synced to the common timeline
+ notifyClockSync();
+ } else {
+ ALOGE("Panic! Observed clock sync error is too high to tolerate,"
+ " resetting state machine and starting over.");
+ notifyClockSyncLoss();
+ return becomeInitial("panic");
+ }
+ }
+ }
+
+ mCurTimeout.setTimeout(mSyncRequestIntervalMs);
+ return result;
+}
+
+bool CommonTimeServer::handleMasterAnnouncement(
+ const MasterAnnouncementPacket* packet,
+ const sockaddr_storage& srcAddr) {
+ uint64_t newDeviceID = packet->deviceID;
+ uint8_t newDevicePrio = packet->devicePriority;
+ uint64_t newTimelineID = packet->timelineID;
+
+ if (mState == ICommonClock::STATE_INITIAL ||
+ mState == ICommonClock::STATE_RONIN ||
+ mState == ICommonClock::STATE_WAIT_FOR_ELECTION) {
+ // if we aren't currently following a master, then start following
+ // this new master
+ return becomeClient(srcAddr,
+ newDeviceID,
+ newDevicePrio,
+ newTimelineID,
+ "heard master announcement");
+ } else if (mState == ICommonClock::STATE_CLIENT) {
+ // if the new master wins arbitration against our current master,
+ // then become a client of the new master
+ if (arbitrateMaster(newDeviceID,
+ newDevicePrio,
+ mClient_MasterDeviceID,
+ mClient_MasterDevicePriority))
+ return becomeClient(srcAddr,
+ newDeviceID,
+ newDevicePrio,
+ newTimelineID,
+ "heard master announcement");
+ } else if (mState == ICommonClock::STATE_MASTER) {
+ // two masters are competing - if the new one wins arbitration, then
+ // cease acting as master
+ if (arbitrateMaster(newDeviceID, newDevicePrio,
+ mDeviceID, effectivePriority()))
+ return becomeClient(srcAddr, newDeviceID,
+ newDevicePrio, newTimelineID,
+ "heard master announcement");
+ }
+
+ return true;
+}
+
+bool CommonTimeServer::sendWhoIsMasterRequest() {
+ assert(mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN);
+
+ // If we have no socket, then we must be in the unconfigured initial state.
+ // Don't report any errors, just don't try to send the initial who-is-master
+ // query. Eventually, our network will either become configured, or we will
+ // be forced into network-less master mode by higher level code.
+ if (mSocket < 0) {
+ assert(mState == ICommonClock::STATE_INITIAL);
+ return true;
+ }
+
+ bool ret = false;
+ WhoIsMasterRequestPacket pkt;
+ pkt.initHeader(mSyncGroupID);
+ pkt.senderDeviceID = mDeviceID;
+ pkt.senderDevicePriority = effectivePriority();
+
+ uint8_t buf[256];
+ ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+ if (bufSz >= 0) {
+ ssize_t sendBytes = sendto(
+ mSocket, buf, bufSz, 0,
+ reinterpret_cast<const sockaddr *>(&mMasterElectionEP),
+ sizeof(mMasterElectionEP));
+ if (sendBytes < 0)
+ ALOGE("WhoIsMaster sendto failed (errno %d)", errno);
+ ret = true;
+ }
+
+ if (mState == ICommonClock::STATE_INITIAL) {
+ mCurTimeout.setTimeout(kInitial_WhoIsMasterTimeoutMs);
+ } else {
+ mCurTimeout.setTimeout(kRonin_WhoIsMasterTimeoutMs);
+ }
+
+ return ret;
+}
+
+bool CommonTimeServer::sendSyncRequest() {
+ // If we are sending sync requests, then we must be in the client state and
+ // we must have a socket (when we have no network, we are only supposed to
+ // be in INITIAL or MASTER)
+ assert(mState == ICommonClock::STATE_CLIENT);
+ assert(mSocket >= 0);
+
+ bool ret = false;
+ SyncRequestPacket pkt;
+ pkt.initHeader(mTimelineID, mSyncGroupID);
+ pkt.clientTxLocalTime = mLocalClock.getLocalTime();
+
+ if (!mClient_FirstSyncTX)
+ mClient_FirstSyncTX = pkt.clientTxLocalTime;
+
+ mClient_PacketRTTLog.logTX(pkt.clientTxLocalTime);
+
+ uint8_t buf[256];
+ ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+ if (bufSz >= 0) {
+ ssize_t sendBytes = sendto(
+ mSocket, buf, bufSz, 0,
+ reinterpret_cast<const sockaddr *>(&mMasterEP),
+ sizeof(mMasterEP));
+ if (sendBytes < 0)
+ ALOGE("SyncRequest sendto failed (errno %d)", errno);
+ ret = true;
+ }
+
+ mClient_SyncsSentToCurMaster++;
+ mCurTimeout.setTimeout(mSyncRequestIntervalMs);
+ mClient_SyncRequestPending = true;
+
+ return ret;
+}
+
+bool CommonTimeServer::sendMasterAnnouncement() {
+ bool ret = false;
+ assert(mState == ICommonClock::STATE_MASTER);
+
+ // If we are being asked to send a master announcement, but we have no
+ // socket, we must be in network-less master mode. Don't bother to send the
+ // announcement, and don't bother to schedule a timeout. When the network
+ // comes up, the work thread will get poked and start the process of
+ // figuring out who the current master should be.
+ if (mSocket < 0) {
+ mCurTimeout.setTimeout(kInfiniteTimeout);
+ return true;
+ }
+
+ MasterAnnouncementPacket pkt;
+ pkt.initHeader(mTimelineID, mSyncGroupID);
+ pkt.deviceID = mDeviceID;
+ pkt.devicePriority = effectivePriority();
+
+ uint8_t buf[256];
+ ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+ if (bufSz >= 0) {
+ ssize_t sendBytes = sendto(
+ mSocket, buf, bufSz, 0,
+ reinterpret_cast<const sockaddr *>(&mMasterElectionEP),
+ sizeof(mMasterElectionEP));
+ if (sendBytes < 0)
+ ALOGE("MasterAnnouncement sendto failed (errno %d)", errno);
+ ret = true;
+ }
+
+ mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
+ return ret;
+}
+
+bool CommonTimeServer::becomeClient(const sockaddr_storage& masterEP,
+ uint64_t masterDeviceID,
+ uint8_t masterDevicePriority,
+ uint64_t timelineID,
+ const char* cause) {
+ char newEPStr[64], oldEPStr[64];
+ sockaddrToString(masterEP, true, newEPStr, sizeof(newEPStr));
+ sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr));
+
+ ALOGI("%s --> CLIENT (%s) :%s"
+ " OldMaster: %02x-%014llx::%016llx::%s"
+ " NewMaster: %02x-%014llx::%016llx::%s",
+ stateToString(mState), cause,
+ (mTimelineID != timelineID) ? " (new timeline)" : "",
+ mClient_MasterDevicePriority, mClient_MasterDeviceID,
+ mTimelineID, oldEPStr,
+ masterDevicePriority, masterDeviceID,
+ timelineID, newEPStr);
+
+ if (mTimelineID != timelineID) {
+ // start following a new timeline
+ mTimelineID = timelineID;
+ mClockRecovery.reset(true, true);
+ notifyClockSyncLoss();
+ } else {
+ // start following a new master on the existing timeline
+ mClockRecovery.reset(false, true);
+ }
+
+ mMasterEP = masterEP;
+ mMasterEPValid = true;
+ setForceLowPriority(false);
+
+ mClient_MasterDeviceID = masterDeviceID;
+ mClient_MasterDevicePriority = masterDevicePriority;
+ resetSyncStats();
+
+ setState(ICommonClock::STATE_CLIENT);
+
+ // add some jitter to when the various clients send their requests
+ // in order to reduce the likelihood that a group of clients overload
+ // the master after receiving a master announcement
+ usleep((lrand48() % 100) * 1000);
+
+ return sendSyncRequest();
+}
+
+bool CommonTimeServer::becomeMaster(const char* cause) {
+ uint64_t oldTimelineID = mTimelineID;
+ if (mTimelineID == ICommonClock::kInvalidTimelineID) {
+ // this device has not been following any existing timeline,
+ // so it will create a new timeline and declare itself master
+ assert(!mCommonClock.isValid());
+
+ // set the common time basis
+ mCommonClock.setBasis(mLocalClock.getLocalTime(), 0);
+
+ // assign an arbitrary timeline iD
+ assignTimelineID();
+
+ // notify listeners that we've created a common timeline
+ notifyClockSync();
+ }
+
+ ALOGI("%s --> MASTER (%s) : %s timeline %016llx",
+ stateToString(mState), cause,
+ (oldTimelineID == mTimelineID) ? "taking ownership of"
+ : "creating new",
+ mTimelineID);
+
+ memset(&mMasterEP, 0, sizeof(mMasterEP));
+ mMasterEPValid = false;
+ setForceLowPriority(false);
+ mClient_MasterDevicePriority = effectivePriority();
+ mClient_MasterDeviceID = mDeviceID;
+ mClockRecovery.reset(false, true);
+ resetSyncStats();
+
+ setState(ICommonClock::STATE_MASTER);
+ return sendMasterAnnouncement();
+}
+
+bool CommonTimeServer::becomeRonin(const char* cause) {
+ // If we were the client of a given timeline, but had never received even a
+ // single time sync packet, then we transition back to Initial instead of
+ // Ronin. If we transition to Ronin and end up becoming the new Master, we
+ // will be unable to service requests for other clients because we never
+ // actually knew what time it was. By going to initial, we ensure that
+ // other clients who know what time it is, but would lose master arbitration
+ // in the Ronin case, will step up and become the proper new master of the
+ // old timeline.
+
+ char oldEPStr[64];
+ sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr));
+ memset(&mMasterEP, 0, sizeof(mMasterEP));
+ mMasterEPValid = false;
+
+ if (mCommonClock.isValid()) {
+ ALOGI("%s --> RONIN (%s) : lost track of previously valid timeline "
+ "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)",
+ stateToString(mState), cause,
+ mClient_MasterDevicePriority, mClient_MasterDeviceID,
+ mTimelineID, oldEPStr,
+ mClient_SyncsSentToCurMaster,
+ mClient_SyncRespsRXedFromCurMaster,
+ mClient_ExpiredSyncRespsRXedFromCurMaster);
+
+ mRonin_WhoIsMasterRequestTimeouts = 0;
+ setState(ICommonClock::STATE_RONIN);
+ return sendWhoIsMasterRequest();
+ } else {
+ ALOGI("%s --> INITIAL (%s) : never synced timeline "
+ "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)",
+ stateToString(mState), cause,
+ mClient_MasterDevicePriority, mClient_MasterDeviceID,
+ mTimelineID, oldEPStr,
+ mClient_SyncsSentToCurMaster,
+ mClient_SyncRespsRXedFromCurMaster,
+ mClient_ExpiredSyncRespsRXedFromCurMaster);
+
+ return becomeInitial("ronin, no timeline");
+ }
+}
+
+bool CommonTimeServer::becomeWaitForElection(const char* cause) {
+ ALOGI("%s --> WAIT_FOR_ELECTION (%s) : dropping out of election,"
+ " waiting %d mSec for completion.",
+ stateToString(mState), cause, kWaitForElection_TimeoutMs);
+
+ setState(ICommonClock::STATE_WAIT_FOR_ELECTION);
+ mCurTimeout.setTimeout(kWaitForElection_TimeoutMs);
+ return true;
+}
+
+bool CommonTimeServer::becomeInitial(const char* cause) {
+ ALOGI("Entering INITIAL (%s), total reset.", cause);
+
+ setState(ICommonClock::STATE_INITIAL);
+
+ // reset clock recovery
+ mClockRecovery.reset(true, true);
+
+ // reset internal state bookkeeping.
+ mCurTimeout.setTimeout(kInfiniteTimeout);
+ memset(&mMasterEP, 0, sizeof(mMasterEP));
+ mMasterEPValid = false;
+ mLastPacketRxLocalTime = 0;
+ mTimelineID = ICommonClock::kInvalidTimelineID;
+ mClockSynced = false;
+ mInitial_WhoIsMasterRequestTimeouts = 0;
+ mClient_MasterDeviceID = 0;
+ mClient_MasterDevicePriority = 0;
+ mRonin_WhoIsMasterRequestTimeouts = 0;
+ resetSyncStats();
+
+ // send the first request to discover the master
+ return sendWhoIsMasterRequest();
+}
+
+void CommonTimeServer::notifyClockSync() {
+ if (!mClockSynced) {
+ mClockSynced = true;
+ mICommonClock->notifyOnTimelineChanged(mTimelineID);
+ }
+}
+
+void CommonTimeServer::notifyClockSyncLoss() {
+ if (mClockSynced) {
+ mClockSynced = false;
+ mICommonClock->notifyOnTimelineChanged(
+ ICommonClock::kInvalidTimelineID);
+ }
+}
+
+void CommonTimeServer::setState(ICommonClock::State s) {
+ mState = s;
+}
+
+const char* CommonTimeServer::stateToString(ICommonClock::State s) {
+ switch(s) {
+ case ICommonClock::STATE_INITIAL:
+ return "INITIAL";
+ case ICommonClock::STATE_CLIENT:
+ return "CLIENT";
+ case ICommonClock::STATE_MASTER:
+ return "MASTER";
+ case ICommonClock::STATE_RONIN:
+ return "RONIN";
+ case ICommonClock::STATE_WAIT_FOR_ELECTION:
+ return "WAIT_FOR_ELECTION";
+ default:
+ return "unknown";
+ }
+}
+
+void CommonTimeServer::sockaddrToString(const sockaddr_storage& addr,
+ bool addrValid,
+ char* buf, size_t bufLen) {
+ if (!bufLen || !buf)
+ return;
+
+ if (addrValid) {
+ switch (addr.ss_family) {
+ case AF_INET: {
+ const struct sockaddr_in* sa =
+ reinterpret_cast<const struct sockaddr_in*>(&addr);
+ unsigned long a = ntohl(sa->sin_addr.s_addr);
+ uint16_t p = ntohs(sa->sin_port);
+ snprintf(buf, bufLen, "%lu.%lu.%lu.%lu:%hu",
+ ((a >> 24) & 0xFF), ((a >> 16) & 0xFF),
+ ((a >> 8) & 0xFF), (a & 0xFF), p);
+ } break;
+
+ case AF_INET6: {
+ const struct sockaddr_in6* sa =
+ reinterpret_cast<const struct sockaddr_in6*>(&addr);
+ const uint8_t* a = sa->sin6_addr.s6_addr;
+ uint16_t p = ntohs(sa->sin6_port);
+ snprintf(buf, bufLen,
+ "%02X%02X:%02X%02X:%02X%02X:%02X%02X:"
+ "%02X%02X:%02X%02X:%02X%02X:%02X%02X port %hd",
+ a[0], a[1], a[ 2], a[ 3], a[ 4], a[ 5], a[ 6], a[ 7],
+ a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15],
+ p);
+ } break;
+
+ default:
+ snprintf(buf, bufLen,
+ "<unknown sockaddr family %d>", addr.ss_family);
+ break;
+ }
+ } else {
+ snprintf(buf, bufLen, "<none>");
+ }
+
+ buf[bufLen - 1] = 0;
+}
+
+bool CommonTimeServer::sockaddrMatch(const sockaddr_storage& a1,
+ const sockaddr_storage& a2,
+ bool matchAddressOnly) {
+ if (a1.ss_family != a2.ss_family)
+ return false;
+
+ switch (a1.ss_family) {
+ case AF_INET: {
+ const struct sockaddr_in* sa1 =
+ reinterpret_cast<const struct sockaddr_in*>(&a1);
+ const struct sockaddr_in* sa2 =
+ reinterpret_cast<const struct sockaddr_in*>(&a2);
+
+ if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr)
+ return false;
+
+ return (matchAddressOnly || (sa1->sin_port == sa2->sin_port));
+ } break;
+
+ case AF_INET6: {
+ const struct sockaddr_in6* sa1 =
+ reinterpret_cast<const struct sockaddr_in6*>(&a1);
+ const struct sockaddr_in6* sa2 =
+ reinterpret_cast<const struct sockaddr_in6*>(&a2);
+
+ if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa2->sin6_addr)))
+ return false;
+
+ return (matchAddressOnly || (sa1->sin6_port == sa2->sin6_port));
+ } break;
+
+ // Huh? We don't deal in non-IPv[46] addresses. Not sure how we got
+ // here, but we don't know how to comapre these addresses and simply
+ // default to a no-match decision.
+ default: return false;
+ }
+}
+
+void CommonTimeServer::TimeoutHelper::setTimeout(int msec) {
+ mTimeoutValid = (msec >= 0);
+ if (mTimeoutValid)
+ mEndTime = systemTime() +
+ (static_cast<nsecs_t>(msec) * 1000000);
+}
+
+int CommonTimeServer::TimeoutHelper::msecTillTimeout() {
+ if (!mTimeoutValid)
+ return kInfiniteTimeout;
+
+ nsecs_t now = systemTime();
+ if (now >= mEndTime)
+ return 0;
+
+ uint64_t deltaMsec = (((mEndTime - now) + 999999) / 1000000);
+
+ if (deltaMsec > static_cast<uint64_t>(MAX_INT))
+ return MAX_INT;
+
+ return static_cast<int>(deltaMsec);
+}
+
+bool CommonTimeServer::shouldPanicNotGettingGoodData() {
+ if (mClient_FirstSyncTX) {
+ int64_t now = mLocalClock.getLocalTime();
+ int64_t delta = now - (mClient_LastGoodSyncRX
+ ? mClient_LastGoodSyncRX
+ : mClient_FirstSyncTX);
+ int64_t deltaUsec = mCommonClock.localDurationToCommonDuration(delta);
+
+ if (deltaUsec >= kNoGoodDataPanicThresholdUsec)
+ return true;
+ }
+
+ return false;
+}
+
+void CommonTimeServer::PacketRTTLog::logTX(int64_t txTime) {
+ txTimes[wrPtr] = txTime;
+ rxTimes[wrPtr] = 0;
+ wrPtr = (wrPtr + 1) % RTT_LOG_SIZE;
+ if (!wrPtr)
+ logFull = true;
+}
+
+void CommonTimeServer::PacketRTTLog::logRX(int64_t txTime, int64_t rxTime) {
+ if (!logFull && !wrPtr)
+ return;
+
+ uint32_t i = logFull ? wrPtr : 0;
+ do {
+ if (txTimes[i] == txTime) {
+ rxTimes[i] = rxTime;
+ break;
+ }
+ i = (i + 1) % RTT_LOG_SIZE;
+ } while (i != wrPtr);
+}
+
+} // namespace android
diff --git a/services/common_time/common_time_server.h b/services/common_time/common_time_server.h
new file mode 100644
index 0000000..a0f549f
--- /dev/null
+++ b/services/common_time/common_time_server.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_COMMON_TIME_SERVER_H
+#define ANDROID_COMMON_TIME_SERVER_H
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <linux/socket.h>
+
+#include <common_time/ICommonClock.h>
+#include <common_time/local_clock.h>
+#include <utils/String8.h>
+
+#include "clock_recovery.h"
+#include "common_clock.h"
+#include "common_time_server_packets.h"
+
+#define RTT_LOG_SIZE 30
+
+namespace android {
+
+class CommonClockService;
+class CommonTimeConfigService;
+
+/***** time service implementation *****/
+
+class CommonTimeServer : public Thread {
+ public:
+ CommonTimeServer();
+ ~CommonTimeServer();
+
+ bool startServices();
+
+ // Common Clock API methods
+ CommonClock& getCommonClock() { return mCommonClock; }
+ LocalClock& getLocalClock() { return mLocalClock; }
+ uint64_t getTimelineID();
+ int32_t getEstimatedError();
+ ICommonClock::State getState();
+ status_t getMasterAddr(struct sockaddr_storage* addr);
+ status_t isCommonTimeValid(bool* valid, uint32_t* timelineID);
+
+ // Config API methods
+ status_t getMasterElectionPriority(uint8_t *priority);
+ status_t setMasterElectionPriority(uint8_t priority);
+ status_t getMasterElectionEndpoint(struct sockaddr_storage *addr);
+ status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr);
+ status_t getMasterElectionGroupId(uint64_t *id);
+ status_t setMasterElectionGroupId(uint64_t id);
+ status_t getInterfaceBinding(String8& ifaceName);
+ status_t setInterfaceBinding(const String8& ifaceName);
+ status_t getMasterAnnounceInterval(int *interval);
+ status_t setMasterAnnounceInterval(int interval);
+ status_t getClientSyncInterval(int *interval);
+ status_t setClientSyncInterval(int interval);
+ status_t getPanicThreshold(int *threshold);
+ status_t setPanicThreshold(int threshold);
+ status_t getAutoDisable(bool *autoDisable);
+ status_t setAutoDisable(bool autoDisable);
+ status_t forceNetworklessMasterMode();
+
+ // Method used by the CommonClockService to notify the core service about
+ // changes in the number of active common clock clients.
+ void reevaluateAutoDisableState(bool commonClockHasClients);
+
+ status_t dumpClockInterface(int fd, const Vector<String16>& args,
+ size_t activeClients);
+ status_t dumpConfigInterface(int fd, const Vector<String16>& args);
+
+ private:
+ class PacketRTTLog {
+ public:
+ PacketRTTLog() {
+ resetLog();
+ }
+
+ void resetLog() {
+ wrPtr = 0;
+ logFull = 0;
+ }
+
+ void logTX(int64_t txTime);
+ void logRX(int64_t txTime, int64_t rxTime);
+ void dumpLog(int fd, const CommonClock& cclk);
+
+ private:
+ uint32_t wrPtr;
+ bool logFull;
+ int64_t txTimes[RTT_LOG_SIZE];
+ int64_t rxTimes[RTT_LOG_SIZE];
+ };
+
+ class TimeoutHelper {
+ public:
+ TimeoutHelper() : mTimeoutValid(false) { }
+
+ void setTimeout(int msec);
+ int msecTillTimeout();
+
+ private:
+ bool mTimeoutValid;
+ nsecs_t mEndTime;
+ };
+
+ bool threadLoop();
+
+ bool runStateMachine_l();
+ bool setupSocket_l();
+
+ void assignTimelineID();
+ bool assignDeviceID();
+
+ static bool arbitrateMaster(uint64_t deviceID1, uint8_t devicePrio1,
+ uint64_t deviceID2, uint8_t devicePrio2);
+
+ bool handlePacket();
+ bool handleWhoIsMasterRequest (const WhoIsMasterRequestPacket* request,
+ const sockaddr_storage& srcAddr);
+ bool handleWhoIsMasterResponse(const WhoIsMasterResponsePacket* response,
+ const sockaddr_storage& srcAddr);
+ bool handleSyncRequest (const SyncRequestPacket* request,
+ const sockaddr_storage& srcAddr);
+ bool handleSyncResponse (const SyncResponsePacket* response,
+ const sockaddr_storage& srcAddr);
+ bool handleMasterAnnouncement (const MasterAnnouncementPacket* packet,
+ const sockaddr_storage& srcAddr);
+
+ bool handleTimeout();
+ bool handleTimeoutInitial();
+ bool handleTimeoutClient();
+ bool handleTimeoutMaster();
+ bool handleTimeoutRonin();
+ bool handleTimeoutWaitForElection();
+
+ bool sendWhoIsMasterRequest();
+ bool sendSyncRequest();
+ bool sendMasterAnnouncement();
+
+ bool becomeClient(const sockaddr_storage& masterAddr,
+ uint64_t masterDeviceID,
+ uint8_t masterDevicePriority,
+ uint64_t timelineID,
+ const char* cause);
+ bool becomeMaster(const char* cause);
+ bool becomeRonin(const char* cause);
+ bool becomeWaitForElection(const char* cause);
+ bool becomeInitial(const char* cause);
+
+ void notifyClockSync();
+ void notifyClockSyncLoss();
+
+ ICommonClock::State mState;
+ void setState(ICommonClock::State s);
+
+ void clearPendingWakeupEvents_l();
+ void wakeupThread_l();
+ void cleanupSocket_l();
+ void shutdownThread();
+
+ inline uint8_t effectivePriority() const {
+ return (mMasterPriority & 0x7F) |
+ (mForceLowPriority ? 0x00 : 0x80);
+ }
+
+ inline bool shouldAutoDisable() const {
+ return (mAutoDisable && !mCommonClockHasClients);
+ }
+
+ inline void resetSyncStats() {
+ mClient_SyncRequestPending = false;
+ mClient_SyncRequestTimeouts = 0;
+ mClient_SyncsSentToCurMaster = 0;
+ mClient_SyncRespsRXedFromCurMaster = 0;
+ mClient_ExpiredSyncRespsRXedFromCurMaster = 0;
+ mClient_FirstSyncTX = 0;
+ mClient_LastGoodSyncRX = 0;
+ mClient_PacketRTTLog.resetLog();
+ }
+
+ bool shouldPanicNotGettingGoodData();
+
+ // Helper to keep track of the state machine's current timeout
+ TimeoutHelper mCurTimeout;
+
+ // common clock, local clock abstraction, and clock recovery loop
+ CommonClock mCommonClock;
+ LocalClock mLocalClock;
+ ClockRecoveryLoop mClockRecovery;
+
+ // implementation of ICommonClock
+ sp<CommonClockService> mICommonClock;
+
+ // implementation of ICommonTimeConfig
+ sp<CommonTimeConfigService> mICommonTimeConfig;
+
+ // UDP socket for the time sync protocol
+ int mSocket;
+
+ // eventfd used to wakeup the work thread in response to configuration
+ // changes.
+ int mWakeupThreadFD;
+
+ // timestamp captured when a packet is received
+ int64_t mLastPacketRxLocalTime;
+
+ // ID of the timeline that this device is following
+ uint64_t mTimelineID;
+
+ // flag for whether the clock has been synced to a timeline
+ bool mClockSynced;
+
+ // flag used to indicate that clients should be considered to be lower
+ // priority than all of their peers during elections. This flag is set and
+ // cleared by the state machine. It is set when the client joins a new
+ // network. If the client had been a master in the old network (or an
+ // isolated master with no network connectivity) it should defer to any
+ // masters which may already be on the network. It will be cleared whenever
+ // the state machine transitions to the master state.
+ bool mForceLowPriority;
+ inline void setForceLowPriority(bool val) {
+ mForceLowPriority = val;
+ if (mState == ICommonClock::STATE_MASTER)
+ mClient_MasterDevicePriority = effectivePriority();
+ }
+
+ // Lock to synchronize access to internal state and configuration.
+ Mutex mLock;
+
+ // Flag updated by the common clock service to indicate that it does or does
+ // not currently have registered clients. When the the auto disable flag is
+ // cleared on the common time service, the service will participate in
+ // network synchronization whenever it has a valid network interface to bind
+ // to. When the auto disable flag is set on the common time service, it
+ // will only participate in network synchronization when it has both a valid
+ // interface AND currently active common clock clients.
+ bool mCommonClockHasClients;
+
+ // Configuration info
+ struct sockaddr_storage mMasterElectionEP; // Endpoint over which we conduct master election
+ String8 mBindIface; // Endpoint for the service to bind to.
+ bool mBindIfaceValid; // whether or not the bind Iface is valid.
+ bool mBindIfaceDirty; // whether or not the bind Iface is valid.
+ struct sockaddr_storage mMasterEP; // Endpoint of our current master (if any)
+ bool mMasterEPValid;
+ uint64_t mDeviceID; // unique ID of this device
+ uint64_t mSyncGroupID; // synchronization group ID of this device.
+ uint8_t mMasterPriority; // Priority of this device in master election.
+ uint32_t mMasterAnnounceIntervalMs;
+ uint32_t mSyncRequestIntervalMs;
+ uint32_t mPanicThresholdUsec;
+ bool mAutoDisable;
+
+ // Config defaults.
+ static const char* kDefaultMasterElectionAddr;
+ static const uint16_t kDefaultMasterElectionPort;
+ static const uint64_t kDefaultSyncGroupID;
+ static const uint8_t kDefaultMasterPriority;
+ static const uint32_t kDefaultMasterAnnounceIntervalMs;
+ static const uint32_t kDefaultSyncRequestIntervalMs;
+ static const uint32_t kDefaultPanicThresholdUsec;
+ static const bool kDefaultAutoDisable;
+
+ // Priority mask and shift fields.
+ static const uint64_t kDeviceIDMask;
+ static const uint8_t kDevicePriorityMask;
+ static const uint8_t kDevicePriorityHiLowBit;
+ static const uint32_t kDevicePriorityShift;
+
+ // Unconfgurable constants
+ static const int kSetupRetryTimeoutMs;
+ static const int64_t kNoGoodDataPanicThresholdUsec;
+ static const uint32_t kRTTDiscardPanicThreshMultiplier;
+
+ /*** status while in the Initial state ***/
+ int mInitial_WhoIsMasterRequestTimeouts;
+ static const int kInitial_NumWhoIsMasterRetries;
+ static const int kInitial_WhoIsMasterTimeoutMs;
+
+ /*** status while in the Client state ***/
+ uint64_t mClient_MasterDeviceID;
+ uint8_t mClient_MasterDevicePriority;
+ bool mClient_SyncRequestPending;
+ int mClient_SyncRequestTimeouts;
+ uint32_t mClient_SyncsSentToCurMaster;
+ uint32_t mClient_SyncRespsRXedFromCurMaster;
+ uint32_t mClient_ExpiredSyncRespsRXedFromCurMaster;
+ int64_t mClient_FirstSyncTX;
+ int64_t mClient_LastGoodSyncRX;
+ PacketRTTLog mClient_PacketRTTLog;
+ static const int kClient_NumSyncRequestRetries;
+
+
+ /*** status while in the Master state ***/
+ static const uint32_t kDefaultMaster_AnnouncementIntervalMs;
+
+ /*** status while in the Ronin state ***/
+ int mRonin_WhoIsMasterRequestTimeouts;
+ static const int kRonin_NumWhoIsMasterRetries;
+ static const int kRonin_WhoIsMasterTimeoutMs;
+
+ /*** status while in the WaitForElection state ***/
+ static const int kWaitForElection_TimeoutMs;
+
+ static const int kInfiniteTimeout;
+
+ static const char* stateToString(ICommonClock::State s);
+ static void sockaddrToString(const sockaddr_storage& addr, bool addrValid,
+ char* buf, size_t bufLen);
+ static bool sockaddrMatch(const sockaddr_storage& a1,
+ const sockaddr_storage& a2,
+ bool matchAddressOnly);
+};
+
+} // namespace android
+
+#endif // ANDROID_COMMON_TIME_SERVER_H
diff --git a/services/common_time/common_time_server_api.cpp b/services/common_time/common_time_server_api.cpp
new file mode 100644
index 0000000..fb8c261
--- /dev/null
+++ b/services/common_time/common_time_server_api.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+
+#include "common_time_server.h"
+
+namespace android {
+
+//
+// Clock API
+//
+uint64_t CommonTimeServer::getTimelineID() {
+ AutoMutex _lock(&mLock);
+ return mTimelineID;
+}
+
+ICommonClock::State CommonTimeServer::getState() {
+ AutoMutex _lock(&mLock);
+ return mState;
+}
+
+status_t CommonTimeServer::getMasterAddr(struct sockaddr_storage* addr) {
+ AutoMutex _lock(&mLock);
+ if (mMasterEPValid) {
+ memcpy(addr, &mMasterEP, sizeof(*addr));
+ return OK;
+ }
+
+ return UNKNOWN_ERROR;
+}
+
+int32_t CommonTimeServer::getEstimatedError() {
+ AutoMutex _lock(&mLock);
+
+ if (ICommonClock::STATE_MASTER == mState)
+ return 0;
+
+ if (!mClockSynced)
+ return ICommonClock::kErrorEstimateUnknown;
+
+ return mClockRecovery.getLastErrorEstimate();
+}
+
+status_t CommonTimeServer::isCommonTimeValid(bool* valid,
+ uint32_t* timelineID) {
+ AutoMutex _lock(&mLock);
+ *valid = mCommonClock.isValid();
+ *timelineID = mTimelineID;
+ return OK;
+}
+
+//
+// Config API
+//
+status_t CommonTimeServer::getMasterElectionPriority(uint8_t *priority) {
+ AutoMutex _lock(&mLock);
+ *priority = mMasterPriority;
+ return OK;
+}
+
+status_t CommonTimeServer::setMasterElectionPriority(uint8_t priority) {
+ AutoMutex _lock(&mLock);
+
+ if (priority > 0x7F)
+ return BAD_VALUE;
+
+ mMasterPriority = priority;
+ return OK;
+}
+
+status_t CommonTimeServer::getMasterElectionEndpoint(
+ struct sockaddr_storage *addr) {
+ AutoMutex _lock(&mLock);
+ memcpy(addr, &mMasterElectionEP, sizeof(*addr));
+ return OK;
+}
+
+status_t CommonTimeServer::setMasterElectionEndpoint(
+ const struct sockaddr_storage *addr) {
+ AutoMutex _lock(&mLock);
+
+ if (!addr)
+ return BAD_VALUE;
+
+ // TODO: add proper support for IPv6
+ if (addr->ss_family != AF_INET)
+ return BAD_VALUE;
+
+ // Only multicast and broadcast endpoints with explicit ports are allowed.
+ uint16_t ipv4Port = ntohs(
+ reinterpret_cast<const struct sockaddr_in*>(addr)->sin_port);
+ if (!ipv4Port)
+ return BAD_VALUE;
+
+ uint32_t ipv4Addr = ntohl(
+ reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr.s_addr);
+ if ((ipv4Addr != 0xFFFFFFFF) && (0xE0000000 != (ipv4Addr & 0xF0000000)))
+ return BAD_VALUE;
+
+ memcpy(&mMasterElectionEP, addr, sizeof(mMasterElectionEP));
+
+ // Force a rebind in order to change election enpoints.
+ mBindIfaceDirty = true;
+ wakeupThread_l();
+ return OK;
+}
+
+status_t CommonTimeServer::getMasterElectionGroupId(uint64_t *id) {
+ AutoMutex _lock(&mLock);
+ *id = mSyncGroupID;
+ return OK;
+}
+
+status_t CommonTimeServer::setMasterElectionGroupId(uint64_t id) {
+ AutoMutex _lock(&mLock);
+ mSyncGroupID = id;
+ return OK;
+}
+
+status_t CommonTimeServer::getInterfaceBinding(String8& ifaceName) {
+ AutoMutex _lock(&mLock);
+ if (!mBindIfaceValid)
+ return INVALID_OPERATION;
+ ifaceName = mBindIface;
+ return OK;
+}
+
+status_t CommonTimeServer::setInterfaceBinding(const String8& ifaceName) {
+ AutoMutex _lock(&mLock);
+
+ mBindIfaceDirty = true;
+ if (ifaceName.size()) {
+ mBindIfaceValid = true;
+ mBindIface = ifaceName;
+ } else {
+ mBindIfaceValid = false;
+ mBindIface.clear();
+ }
+
+ wakeupThread_l();
+ return OK;
+}
+
+status_t CommonTimeServer::getMasterAnnounceInterval(int *interval) {
+ AutoMutex _lock(&mLock);
+ *interval = mMasterAnnounceIntervalMs;
+ return OK;
+}
+
+status_t CommonTimeServer::setMasterAnnounceInterval(int interval) {
+ AutoMutex _lock(&mLock);
+
+ if (interval > (6 *3600000)) // Max interval is once every 6 hrs
+ return BAD_VALUE;
+
+ if (interval < 500) // Min interval is once per 0.5 seconds
+ return BAD_VALUE;
+
+ mMasterAnnounceIntervalMs = interval;
+ if (ICommonClock::STATE_MASTER == mState) {
+ int pendingTimeout = mCurTimeout.msecTillTimeout();
+ if ((kInfiniteTimeout == pendingTimeout) ||
+ (pendingTimeout > interval)) {
+ mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
+ wakeupThread_l();
+ }
+ }
+
+ return OK;
+}
+
+status_t CommonTimeServer::getClientSyncInterval(int *interval) {
+ AutoMutex _lock(&mLock);
+ *interval = mSyncRequestIntervalMs;
+ return OK;
+}
+
+status_t CommonTimeServer::setClientSyncInterval(int interval) {
+ AutoMutex _lock(&mLock);
+
+ if (interval > (3600000)) // Max interval is once every 60 min
+ return BAD_VALUE;
+
+ if (interval < 250) // Min interval is once per 0.25 seconds
+ return BAD_VALUE;
+
+ mSyncRequestIntervalMs = interval;
+ if (ICommonClock::STATE_CLIENT == mState) {
+ int pendingTimeout = mCurTimeout.msecTillTimeout();
+ if ((kInfiniteTimeout == pendingTimeout) ||
+ (pendingTimeout > interval)) {
+ mCurTimeout.setTimeout(mSyncRequestIntervalMs);
+ wakeupThread_l();
+ }
+ }
+
+ return OK;
+}
+
+status_t CommonTimeServer::getPanicThreshold(int *threshold) {
+ AutoMutex _lock(&mLock);
+ *threshold = mPanicThresholdUsec;
+ return OK;
+}
+
+status_t CommonTimeServer::setPanicThreshold(int threshold) {
+ AutoMutex _lock(&mLock);
+
+ if (threshold < 1000) // Min threshold is 1mSec
+ return BAD_VALUE;
+
+ mPanicThresholdUsec = threshold;
+ return OK;
+}
+
+status_t CommonTimeServer::getAutoDisable(bool *autoDisable) {
+ AutoMutex _lock(&mLock);
+ *autoDisable = mAutoDisable;
+ return OK;
+}
+
+status_t CommonTimeServer::setAutoDisable(bool autoDisable) {
+ AutoMutex _lock(&mLock);
+ mAutoDisable = autoDisable;
+ wakeupThread_l();
+ return OK;
+}
+
+status_t CommonTimeServer::forceNetworklessMasterMode() {
+ AutoMutex _lock(&mLock);
+
+ // Can't force networkless master mode if we are currently bound to a
+ // network.
+ if (mSocket >= 0)
+ return INVALID_OPERATION;
+
+ becomeMaster("force networkless");
+
+ return OK;
+}
+
+void CommonTimeServer::reevaluateAutoDisableState(bool commonClockHasClients) {
+ AutoMutex _lock(&mLock);
+ bool needWakeup = (mAutoDisable && mMasterEPValid &&
+ (commonClockHasClients != mCommonClockHasClients));
+
+ mCommonClockHasClients = commonClockHasClients;
+
+ if (needWakeup) {
+ ALOGI("Waking up service, auto-disable is engaged and service now has%s"
+ " clients", mCommonClockHasClients ? "" : " no");
+ wakeupThread_l();
+ }
+}
+
+#define dump_printf(a, b...) do { \
+ int res; \
+ res = snprintf(buffer, sizeof(buffer), a, b); \
+ buffer[sizeof(buffer) - 1] = 0; \
+ if (res > 0) \
+ write(fd, buffer, res); \
+} while (0)
+#define checked_percentage(a, b) ((0 == b) ? 0.0f : ((100.0f * a) / b))
+
+status_t CommonTimeServer::dumpClockInterface(int fd,
+ const Vector<String16>& args,
+ size_t activeClients) {
+ AutoMutex _lock(&mLock);
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump CommonClockService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ write(fd, buffer, strlen(buffer));
+ } else {
+ int64_t commonTime;
+ int64_t localTime;
+ bool synced;
+ char maStr[64];
+
+ localTime = mLocalClock.getLocalTime();
+ synced = (OK == mCommonClock.localToCommon(localTime, &commonTime));
+ sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr));
+
+ dump_printf("Common Clock Service Status\nLocal time : %lld\n",
+ localTime);
+
+ if (synced)
+ dump_printf("Common time : %lld\n", commonTime);
+ else
+ dump_printf("Common time : %s\n", "not synced");
+
+ dump_printf("Timeline ID : %016llx\n", mTimelineID);
+ dump_printf("State : %s\n", stateToString(mState));
+ dump_printf("Master Addr : %s\n", maStr);
+
+
+ if (synced) {
+ int32_t est = (ICommonClock::STATE_MASTER != mState)
+ ? mClockRecovery.getLastErrorEstimate()
+ : 0;
+ dump_printf("Error Est. : %.3f msec\n",
+ static_cast<float>(est) / 1000.0);
+ } else {
+ dump_printf("Error Est. : %s\n", "unknown");
+ }
+
+ dump_printf("Syncs TXes : %u\n", mClient_SyncsSentToCurMaster);
+ dump_printf("Syncs RXes : %u (%.2f%%)\n",
+ mClient_SyncRespsRXedFromCurMaster,
+ checked_percentage(
+ mClient_SyncRespsRXedFromCurMaster,
+ mClient_SyncsSentToCurMaster));
+ dump_printf("RXs Expired : %u (%.2f%%)\n",
+ mClient_ExpiredSyncRespsRXedFromCurMaster,
+ checked_percentage(
+ mClient_ExpiredSyncRespsRXedFromCurMaster,
+ mClient_SyncsSentToCurMaster));
+
+ if (!mClient_LastGoodSyncRX) {
+ dump_printf("Last Good RX : %s\n", "unknown");
+ } else {
+ int64_t localDelta, usecDelta;
+ localDelta = localTime - mClient_LastGoodSyncRX;
+ usecDelta = mCommonClock.localDurationToCommonDuration(localDelta);
+ dump_printf("Last Good RX : %lld uSec ago\n", usecDelta);
+ }
+
+ dump_printf("Active Clients : %u\n", activeClients);
+ mClient_PacketRTTLog.dumpLog(fd, mCommonClock);
+ }
+
+ return NO_ERROR;
+}
+
+status_t CommonTimeServer::dumpConfigInterface(int fd,
+ const Vector<String16>& args) {
+ AutoMutex _lock(&mLock);
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump CommonTimeConfigService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ write(fd, buffer, strlen(buffer));
+ } else {
+ char meStr[64];
+
+ sockaddrToString(mMasterElectionEP, true, meStr, sizeof(meStr));
+
+ dump_printf("Common Time Config Service Status\n"
+ "Bound Interface : %s\n",
+ mBindIfaceValid ? mBindIface.string() : "<unbound>");
+ dump_printf("Master Election Endpoint : %s\n", meStr);
+ dump_printf("Master Election Group ID : %016llx\n", mSyncGroupID);
+ dump_printf("Master Announce Interval : %d mSec\n",
+ mMasterAnnounceIntervalMs);
+ dump_printf("Client Sync Interval : %d mSec\n",
+ mSyncRequestIntervalMs);
+ dump_printf("Panic Threshold : %d uSec\n",
+ mPanicThresholdUsec);
+ dump_printf("Base ME Prio : 0x%02x\n",
+ static_cast<uint32_t>(mMasterPriority));
+ dump_printf("Effective ME Prio : 0x%02x\n",
+ static_cast<uint32_t>(effectivePriority()));
+ dump_printf("Auto Disable Allowed : %s\n",
+ mAutoDisable ? "yes" : "no");
+ dump_printf("Auto Disable Engaged : %s\n",
+ shouldAutoDisable() ? "yes" : "no");
+ }
+
+ return NO_ERROR;
+}
+
+void CommonTimeServer::PacketRTTLog::dumpLog(int fd, const CommonClock& cclk) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ uint32_t avail = !logFull ? wrPtr : RTT_LOG_SIZE;
+
+ if (!avail)
+ return;
+
+ dump_printf("\nPacket Log (%d entries)\n", avail);
+
+ uint32_t ndx = 0;
+ uint32_t i = logFull ? wrPtr : 0;
+ do {
+ if (rxTimes[i]) {
+ int64_t delta = rxTimes[i] - txTimes[i];
+ int64_t deltaUsec = cclk.localDurationToCommonDuration(delta);
+ dump_printf("pkt[%2d] : localTX %12lld localRX %12lld "
+ "(%.3f msec RTT)\n",
+ ndx, txTimes[i], rxTimes[i],
+ static_cast<float>(deltaUsec) / 1000.0);
+ } else {
+ dump_printf("pkt[%2d] : localTX %12lld localRX never\n",
+ ndx, txTimes[i]);
+ }
+ i = (i + 1) % RTT_LOG_SIZE;
+ ndx++;
+ } while (i != wrPtr);
+}
+
+#undef dump_printf
+#undef checked_percentage
+
+} // namespace android
diff --git a/services/common_time/common_time_server_packets.cpp b/services/common_time/common_time_server_packets.cpp
new file mode 100644
index 0000000..9833c37
--- /dev/null
+++ b/services/common_time/common_time_server_packets.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <stdint.h>
+
+#include "common_time_server_packets.h"
+
+namespace android {
+
+const uint32_t TimeServicePacketHeader::kMagic =
+ (static_cast<uint32_t>('c') << 24) |
+ (static_cast<uint32_t>('c') << 16) |
+ (static_cast<uint32_t>('l') << 8) |
+ static_cast<uint32_t>('k');
+
+const uint16_t TimeServicePacketHeader::kCurVersion = 1;
+
+#define SERIALIZE_FIELD(field_name, type, converter) \
+ do { \
+ if ((offset + sizeof(field_name)) > length) \
+ return -1; \
+ *((type*)(data + offset)) = converter(field_name); \
+ offset += sizeof(field_name); \
+ } while (0)
+#define SERIALIZE_INT16(field_name) SERIALIZE_FIELD(field_name, int16_t, htons)
+#define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl)
+#define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq)
+
+#define DESERIALIZE_FIELD(field_name, type, converter) \
+ do { \
+ if ((offset + sizeof(field_name)) > length) \
+ return -1; \
+ field_name = converter(*((type*)(data + offset))); \
+ offset += sizeof(field_name); \
+ } while (0)
+#define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs)
+#define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl)
+#define DESERIALIZE_INT64(field_name) DESERIALIZE_FIELD(field_name, int64_t, ntohq)
+
+#define kDevicePriorityShift 56
+#define kDeviceIDMask ((static_cast<uint64_t>(1) << kDevicePriorityShift) - 1)
+
+inline uint64_t packDeviceID(uint64_t devID, uint8_t prio) {
+ return (devID & kDeviceIDMask) |
+ (static_cast<uint64_t>(prio) << kDevicePriorityShift);
+}
+
+inline uint64_t unpackDeviceID(uint64_t packed) {
+ return (packed & kDeviceIDMask);
+}
+
+inline uint8_t unpackDevicePriority(uint64_t packed) {
+ return static_cast<uint8_t>(packed >> kDevicePriorityShift);
+}
+
+ssize_t TimeServicePacketHeader::serializeHeader(uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = 0;
+ int16_t pktType = static_cast<int16_t>(packetType);
+ SERIALIZE_INT32(magic);
+ SERIALIZE_INT16(version);
+ SERIALIZE_INT16(pktType);
+ SERIALIZE_INT64(timelineID);
+ SERIALIZE_INT64(syncGroupID);
+ return offset;
+}
+
+ssize_t TimeServicePacketHeader::deserializeHeader(const uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = 0;
+ int16_t tmp;
+ DESERIALIZE_INT32(magic);
+ DESERIALIZE_INT16(version);
+ DESERIALIZE_INT16(tmp);
+ DESERIALIZE_INT64(timelineID);
+ DESERIALIZE_INT64(syncGroupID);
+ packetType = static_cast<TimeServicePacketType>(tmp);
+ return offset;
+}
+
+ssize_t TimeServicePacketHeader::serializePacket(uint8_t* data,
+ uint32_t length) {
+ ssize_t ret, tmp;
+
+ ret = serializeHeader(data, length);
+ if (ret < 0)
+ return ret;
+
+ data += ret;
+ length -= ret;
+
+ switch (packetType) {
+ case TIME_PACKET_WHO_IS_MASTER_REQUEST:
+ tmp =((WhoIsMasterRequestPacket*)(this))->serializePacket(data,
+ length);
+ break;
+ case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
+ tmp =((WhoIsMasterResponsePacket*)(this))->serializePacket(data,
+ length);
+ break;
+ case TIME_PACKET_SYNC_REQUEST:
+ tmp =((SyncRequestPacket*)(this))->serializePacket(data, length);
+ break;
+ case TIME_PACKET_SYNC_RESPONSE:
+ tmp =((SyncResponsePacket*)(this))->serializePacket(data, length);
+ break;
+ case TIME_PACKET_MASTER_ANNOUNCEMENT:
+ tmp =((MasterAnnouncementPacket*)(this))->serializePacket(data,
+ length);
+ break;
+ default:
+ return -1;
+ }
+
+ if (tmp < 0)
+ return tmp;
+
+ return ret + tmp;
+}
+
+ssize_t UniversalTimeServicePacket::deserializePacket(
+ const uint8_t* data,
+ uint32_t length,
+ uint64_t expectedSyncGroupID) {
+ ssize_t ret;
+ TimeServicePacketHeader* header;
+ if (length < 8)
+ return -1;
+
+ packetType = ntohs(*((uint16_t*)(data + 6)));
+ switch (packetType) {
+ case TIME_PACKET_WHO_IS_MASTER_REQUEST:
+ ret = p.who_is_master_request.deserializePacket(data, length);
+ header = &p.who_is_master_request;
+ break;
+ case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
+ ret = p.who_is_master_response.deserializePacket(data, length);
+ header = &p.who_is_master_response;
+ break;
+ case TIME_PACKET_SYNC_REQUEST:
+ ret = p.sync_request.deserializePacket(data, length);
+ header = &p.sync_request;
+ break;
+ case TIME_PACKET_SYNC_RESPONSE:
+ ret = p.sync_response.deserializePacket(data, length);
+ header = &p.sync_response;
+ break;
+ case TIME_PACKET_MASTER_ANNOUNCEMENT:
+ ret = p.master_announcement.deserializePacket(data, length);
+ header = &p.master_announcement;
+ break;
+ default:
+ return -1;
+ }
+
+ if ((ret >= 0) && !header->checkPacket(expectedSyncGroupID))
+ ret = -1;
+
+ return ret;
+}
+
+ssize_t WhoIsMasterRequestPacket::serializePacket(uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = serializeHeader(data, length);
+ if (offset > 0) {
+ uint64_t packed = packDeviceID(senderDeviceID, senderDevicePriority);
+ SERIALIZE_INT64(packed);
+ }
+ return offset;
+}
+
+ssize_t WhoIsMasterRequestPacket::deserializePacket(const uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = deserializeHeader(data, length);
+ if (offset > 0) {
+ uint64_t packed;
+ DESERIALIZE_INT64(packed);
+ senderDeviceID = unpackDeviceID(packed);
+ senderDevicePriority = unpackDevicePriority(packed);
+ }
+ return offset;
+}
+
+ssize_t WhoIsMasterResponsePacket::serializePacket(uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = serializeHeader(data, length);
+ if (offset > 0) {
+ uint64_t packed = packDeviceID(deviceID, devicePriority);
+ SERIALIZE_INT64(packed);
+ }
+ return offset;
+}
+
+ssize_t WhoIsMasterResponsePacket::deserializePacket(const uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = deserializeHeader(data, length);
+ if (offset > 0) {
+ uint64_t packed;
+ DESERIALIZE_INT64(packed);
+ deviceID = unpackDeviceID(packed);
+ devicePriority = unpackDevicePriority(packed);
+ }
+ return offset;
+}
+
+ssize_t SyncRequestPacket::serializePacket(uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = serializeHeader(data, length);
+ if (offset > 0) {
+ SERIALIZE_INT64(clientTxLocalTime);
+ }
+ return offset;
+}
+
+ssize_t SyncRequestPacket::deserializePacket(const uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = deserializeHeader(data, length);
+ if (offset > 0) {
+ DESERIALIZE_INT64(clientTxLocalTime);
+ }
+ return offset;
+}
+
+ssize_t SyncResponsePacket::serializePacket(uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = serializeHeader(data, length);
+ if (offset > 0) {
+ SERIALIZE_INT64(clientTxLocalTime);
+ SERIALIZE_INT64(masterRxCommonTime);
+ SERIALIZE_INT64(masterTxCommonTime);
+ SERIALIZE_INT32(nak);
+ }
+ return offset;
+}
+
+ssize_t SyncResponsePacket::deserializePacket(const uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = deserializeHeader(data, length);
+ if (offset > 0) {
+ DESERIALIZE_INT64(clientTxLocalTime);
+ DESERIALIZE_INT64(masterRxCommonTime);
+ DESERIALIZE_INT64(masterTxCommonTime);
+ DESERIALIZE_INT32(nak);
+ }
+ return offset;
+}
+
+ssize_t MasterAnnouncementPacket::serializePacket(uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = serializeHeader(data, length);
+ if (offset > 0) {
+ uint64_t packed = packDeviceID(deviceID, devicePriority);
+ SERIALIZE_INT64(packed);
+ }
+ return offset;
+}
+
+ssize_t MasterAnnouncementPacket::deserializePacket(const uint8_t* data,
+ uint32_t length) {
+ ssize_t offset = deserializeHeader(data, length);
+ if (offset > 0) {
+ uint64_t packed;
+ DESERIALIZE_INT64(packed);
+ deviceID = unpackDeviceID(packed);
+ devicePriority = unpackDevicePriority(packed);
+ }
+ return offset;
+}
+
+} // namespace android
+
diff --git a/services/common_time/common_time_server_packets.h b/services/common_time/common_time_server_packets.h
new file mode 100644
index 0000000..57ba8a2
--- /dev/null
+++ b/services/common_time/common_time_server_packets.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_COMMON_TIME_SERVER_PACKETS_H
+#define ANDROID_COMMON_TIME_SERVER_PACKETS_H
+
+#include <stdint.h>
+#include <common_time/ICommonClock.h>
+
+namespace android {
+
+/***** time sync protocol packets *****/
+
+enum TimeServicePacketType {
+ TIME_PACKET_WHO_IS_MASTER_REQUEST = 1,
+ TIME_PACKET_WHO_IS_MASTER_RESPONSE,
+ TIME_PACKET_SYNC_REQUEST,
+ TIME_PACKET_SYNC_RESPONSE,
+ TIME_PACKET_MASTER_ANNOUNCEMENT,
+};
+
+class TimeServicePacketHeader {
+ public:
+ friend class UniversalTimeServicePacket;
+ // magic number identifying the protocol
+ uint32_t magic;
+
+ // protocol version of the packet
+ uint16_t version;
+
+ // type of the packet
+ TimeServicePacketType packetType;
+
+ // the timeline ID
+ uint64_t timelineID;
+
+ // synchronization group this packet belongs to (used to operate multiple
+ // synchronization domains which all use the same master election endpoint)
+ uint64_t syncGroupID;
+
+ ssize_t serializePacket(uint8_t* data, uint32_t length);
+
+ protected:
+ void initHeader(TimeServicePacketType type,
+ const uint64_t tlID,
+ const uint64_t groupID) {
+ magic = kMagic;
+ version = kCurVersion;
+ packetType = type;
+ timelineID = tlID;
+ syncGroupID = groupID;
+ }
+
+ bool checkPacket(uint64_t expectedSyncGroupID) const {
+ return ((magic == kMagic) &&
+ (version == kCurVersion) &&
+ (!expectedSyncGroupID || (syncGroupID == expectedSyncGroupID)));
+ }
+
+ ssize_t serializeHeader(uint8_t* data, uint32_t length);
+ ssize_t deserializeHeader(const uint8_t* data, uint32_t length);
+
+ private:
+ static const uint32_t kMagic;
+ static const uint16_t kCurVersion;
+};
+
+// packet querying for a suitable master
+class WhoIsMasterRequestPacket : public TimeServicePacketHeader {
+ public:
+ uint64_t senderDeviceID;
+ uint8_t senderDevicePriority;
+
+ void initHeader(const uint64_t groupID) {
+ TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_REQUEST,
+ ICommonClock::kInvalidTimelineID,
+ groupID);
+ }
+
+ ssize_t serializePacket(uint8_t* data, uint32_t length);
+ ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// response to a WhoIsMaster request
+class WhoIsMasterResponsePacket : public TimeServicePacketHeader {
+ public:
+ uint64_t deviceID;
+ uint8_t devicePriority;
+
+ void initHeader(const uint64_t tlID, const uint64_t groupID) {
+ TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_RESPONSE,
+ tlID, groupID);
+ }
+
+ ssize_t serializePacket(uint8_t* data, uint32_t length);
+ ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// packet sent by a client requesting correspondence between local
+// and common time
+class SyncRequestPacket : public TimeServicePacketHeader {
+ public:
+ // local time when this request was transmitted
+ int64_t clientTxLocalTime;
+
+ void initHeader(const uint64_t tlID, const uint64_t groupID) {
+ TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_REQUEST,
+ tlID, groupID);
+ }
+
+ ssize_t serializePacket(uint8_t* data, uint32_t length);
+ ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// response to a sync request sent by the master
+class SyncResponsePacket : public TimeServicePacketHeader {
+ public:
+ // local time when this request was transmitted by the client
+ int64_t clientTxLocalTime;
+
+ // common time when the master received the request
+ int64_t masterRxCommonTime;
+
+ // common time when the master transmitted the response
+ int64_t masterTxCommonTime;
+
+ // flag that is set if the recipient of the sync request is not acting
+ // as a master for the requested timeline
+ uint32_t nak;
+
+ void initHeader(const uint64_t tlID, const uint64_t groupID) {
+ TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_RESPONSE,
+ tlID, groupID);
+ }
+
+ ssize_t serializePacket(uint8_t* data, uint32_t length);
+ ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// announcement of the master's presence
+class MasterAnnouncementPacket : public TimeServicePacketHeader {
+ public:
+ // the master's device ID
+ uint64_t deviceID;
+ uint8_t devicePriority;
+
+ void initHeader(const uint64_t tlID, const uint64_t groupID) {
+ TimeServicePacketHeader::initHeader(TIME_PACKET_MASTER_ANNOUNCEMENT,
+ tlID, groupID);
+ }
+
+ ssize_t serializePacket(uint8_t* data, uint32_t length);
+ ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+class UniversalTimeServicePacket {
+ public:
+ uint16_t packetType;
+ union {
+ WhoIsMasterRequestPacket who_is_master_request;
+ WhoIsMasterResponsePacket who_is_master_response;
+ SyncRequestPacket sync_request;
+ SyncResponsePacket sync_response;
+ MasterAnnouncementPacket master_announcement;
+ } p;
+
+ ssize_t deserializePacket(const uint8_t* data,
+ uint32_t length,
+ uint64_t expectedSyncGroupID);
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMMON_TIME_SERVER_PACKETS_H
+
+
diff --git a/services/common_time/diag_thread.cpp b/services/common_time/diag_thread.cpp
new file mode 100644
index 0000000..4cb9551
--- /dev/null
+++ b/services/common_time/diag_thread.cpp
@@ -0,0 +1,323 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <fcntl.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Errors.h>
+#include <utils/misc.h>
+
+#include <common_time/local_clock.h>
+
+#include "common_clock.h"
+#include "diag_thread.h"
+
+#define kMaxEvents 16
+#define kListenPort 9876
+
+static bool setNonblocking(int fd) {
+ int flags = fcntl(fd, F_GETFL);
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+ ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
+ fd, errno);
+ return false;
+ }
+
+ return true;
+}
+
+static bool setNodelay(int fd) {
+ int tmp = 1;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)) < 0) {
+ ALOGE("Failed to set socket (%d) to no-delay mode (errno %d)",
+ fd, errno);
+ return false;
+ }
+
+ return true;
+}
+
+namespace android {
+
+DiagThread::DiagThread(CommonClock* common_clock, LocalClock* local_clock) {
+ common_clock_ = common_clock;
+ local_clock_ = local_clock;
+ listen_fd_ = -1;
+ data_fd_ = -1;
+ kernel_logID_basis_known_ = false;
+ discipline_log_ID_ = 0;
+}
+
+DiagThread::~DiagThread() {
+}
+
+status_t DiagThread::startWorkThread() {
+ status_t res;
+ stopWorkThread();
+ res = run("Diag");
+
+ if (res != OK)
+ ALOGE("Failed to start work thread (res = %d)", res);
+
+ return res;
+}
+
+void DiagThread::stopWorkThread() {
+ status_t res;
+ res = requestExitAndWait(); // block until thread exit.
+ if (res != OK)
+ ALOGE("Failed to stop work thread (res = %d)", res);
+}
+
+bool DiagThread::openListenSocket() {
+ bool ret = false;
+ int flags;
+ cleanupListenSocket();
+
+ if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ ALOGE("Socket failed.");
+ goto bailout;
+ }
+
+ // Set non-blocking operation
+ if (!setNonblocking(listen_fd_))
+ goto bailout;
+
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(kListenPort);
+
+ if (bind(listen_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ ALOGE("Bind failed.");
+ goto bailout;
+ }
+
+ if (listen(listen_fd_, 1) < 0) {
+ ALOGE("Listen failed.");
+ goto bailout;
+ }
+
+ ret = true;
+bailout:
+ if (!ret)
+ cleanupListenSocket();
+
+ return ret;
+}
+
+void DiagThread::cleanupListenSocket() {
+ if (listen_fd_ >= 0) {
+ int res;
+
+ struct linger l;
+ l.l_onoff = 1;
+ l.l_linger = 0;
+
+ setsockopt(listen_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+ shutdown(listen_fd_, SHUT_RDWR);
+ close(listen_fd_);
+ listen_fd_ = -1;
+ }
+}
+
+void DiagThread::cleanupDataSocket() {
+ if (data_fd_ >= 0) {
+ int res;
+
+ struct linger l;
+ l.l_onoff = 1;
+ l.l_linger = 0;
+
+ setsockopt(data_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+ shutdown(data_fd_, SHUT_RDWR);
+ close(data_fd_);
+ data_fd_ = -1;
+ }
+}
+
+void DiagThread::resetLogIDs() {
+ // Drain and discard all of the events from the kernel
+ struct local_time_debug_event events[kMaxEvents];
+ while(local_clock_->getDebugLog(events, kMaxEvents) > 0)
+ ;
+
+ {
+ Mutex::Autolock lock(&discipline_log_lock_);
+ discipline_log_.clear();
+ discipline_log_ID_ = 0;
+ }
+
+ kernel_logID_basis_known_ = false;
+}
+
+void DiagThread::pushDisciplineEvent(int64_t observed_local_time,
+ int64_t observed_common_time,
+ int64_t nominal_common_time,
+ int32_t total_correction,
+ int32_t rtt) {
+ Mutex::Autolock lock(&discipline_log_lock_);
+
+ DisciplineEventRecord evt;
+
+ evt.event_id = discipline_log_ID_++;
+
+ evt.action_local_time = local_clock_->getLocalTime();
+ common_clock_->localToCommon(evt.action_local_time,
+ &evt.action_common_time);
+
+ evt.observed_local_time = observed_local_time;
+ evt.observed_common_time = observed_common_time;
+ evt.nominal_common_time = nominal_common_time;
+ evt.total_correction = total_correction;
+ evt.rtt = rtt;
+
+ discipline_log_.push_back(evt);
+ while (discipline_log_.size() > kMaxDisciplineLogSize)
+ discipline_log_.erase(discipline_log_.begin());
+}
+
+bool DiagThread::threadLoop() {
+ struct pollfd poll_fds[1];
+
+ if (!openListenSocket()) {
+ ALOGE("Failed to open listen socket");
+ goto bailout;
+ }
+
+ while (!exitPending()) {
+ memset(&poll_fds, 0, sizeof(poll_fds));
+
+ if (data_fd_ < 0) {
+ poll_fds[0].fd = listen_fd_;
+ poll_fds[0].events = POLLIN;
+ } else {
+ poll_fds[0].fd = data_fd_;
+ poll_fds[0].events = POLLRDHUP | POLLIN;
+ }
+
+ int poll_res = poll(poll_fds, NELEM(poll_fds), 50);
+ if (poll_res < 0) {
+ ALOGE("Fatal error (%d,%d) while waiting on events",
+ poll_res, errno);
+ goto bailout;
+ }
+
+ if (exitPending())
+ break;
+
+ if (poll_fds[0].revents) {
+ if (poll_fds[0].fd == listen_fd_) {
+ data_fd_ = accept(listen_fd_, NULL, NULL);
+
+ if (data_fd_ < 0) {
+ ALOGW("Failed accept on socket %d with err %d",
+ listen_fd_, errno);
+ } else {
+ if (!setNonblocking(data_fd_))
+ cleanupDataSocket();
+ if (!setNodelay(data_fd_))
+ cleanupDataSocket();
+ }
+ } else
+ if (poll_fds[0].fd == data_fd_) {
+ if (poll_fds[0].revents & POLLRDHUP) {
+ // Connection hung up; time to clean up.
+ cleanupDataSocket();
+ } else
+ if (poll_fds[0].revents & POLLIN) {
+ uint8_t cmd;
+ if (read(data_fd_, &cmd, sizeof(cmd)) > 0) {
+ switch(cmd) {
+ case 'r':
+ case 'R':
+ resetLogIDs();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ struct local_time_debug_event events[kMaxEvents];
+ int amt = local_clock_->getDebugLog(events, kMaxEvents);
+
+ if (amt > 0) {
+ for (int i = 0; i < amt; i++) {
+ struct local_time_debug_event& e = events[i];
+
+ if (!kernel_logID_basis_known_) {
+ kernel_logID_basis_ = e.local_timesync_event_id;
+ kernel_logID_basis_known_ = true;
+ }
+
+ char buf[1024];
+ int64_t common_time;
+ status_t res = common_clock_->localToCommon(e.local_time,
+ &common_time);
+ snprintf(buf, sizeof(buf), "E,%lld,%lld,%lld,%d\n",
+ e.local_timesync_event_id - kernel_logID_basis_,
+ e.local_time,
+ common_time,
+ (OK == res) ? 1 : 0);
+ buf[sizeof(buf) - 1] = 0;
+
+ if (data_fd_ >= 0)
+ write(data_fd_, buf, strlen(buf));
+ }
+ }
+
+ { // scope for autolock pattern
+ Mutex::Autolock lock(&discipline_log_lock_);
+
+ while (discipline_log_.size() > 0) {
+ char buf[1024];
+ DisciplineEventRecord& e = *discipline_log_.begin();
+ snprintf(buf, sizeof(buf),
+ "D,%lld,%lld,%lld,%lld,%lld,%lld,%d,%d\n",
+ e.event_id,
+ e.action_local_time,
+ e.action_common_time,
+ e.observed_local_time,
+ e.observed_common_time,
+ e.nominal_common_time,
+ e.total_correction,
+ e.rtt);
+ buf[sizeof(buf) - 1] = 0;
+
+ if (data_fd_ >= 0)
+ write(data_fd_, buf, strlen(buf));
+
+ discipline_log_.erase(discipline_log_.begin());
+ }
+ }
+ }
+
+bailout:
+ cleanupDataSocket();
+ cleanupListenSocket();
+ return false;
+}
+
+} // namespace android
diff --git a/services/common_time/diag_thread.h b/services/common_time/diag_thread.h
new file mode 100644
index 0000000..c630e0d
--- /dev/null
+++ b/services/common_time/diag_thread.h
@@ -0,0 +1,76 @@
+/*
+ * 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 __DIAG_THREAD_H__
+#define __DIAG_THREAD_H__
+
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CommonClock;
+class LocalClock;
+
+class DiagThread : public Thread {
+ public:
+ DiagThread(CommonClock* common_clock, LocalClock* local_clock);
+ ~DiagThread();
+
+ status_t startWorkThread();
+ void stopWorkThread();
+ virtual bool threadLoop();
+
+ void pushDisciplineEvent(int64_t observed_local_time,
+ int64_t observed_common_time,
+ int64_t nominal_common_time,
+ int32_t total_correction,
+ int32_t rtt);
+
+ private:
+ typedef struct {
+ int64_t event_id;
+ int64_t action_local_time;
+ int64_t action_common_time;
+ int64_t observed_local_time;
+ int64_t observed_common_time;
+ int64_t nominal_common_time;
+ int32_t total_correction;
+ int32_t rtt;
+ } DisciplineEventRecord;
+
+ bool openListenSocket();
+ void cleanupListenSocket();
+ void cleanupDataSocket();
+ void resetLogIDs();
+
+ CommonClock* common_clock_;
+ LocalClock* local_clock_;
+ int listen_fd_;
+ int data_fd_;
+
+ int64_t kernel_logID_basis_;
+ bool kernel_logID_basis_known_;
+
+ static const size_t kMaxDisciplineLogSize = 16;
+ Mutex discipline_log_lock_;
+ List<DisciplineEventRecord> discipline_log_;
+ int64_t discipline_log_ID_;
+};
+
+} // namespace android
+
+#endif //__ DIAG_THREAD_H__
diff --git a/services/common_time/main.cpp b/services/common_time/main.cpp
new file mode 100644
index 0000000..49eb30a
--- /dev/null
+++ b/services/common_time/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include "common_time_server.h"
+
+int main(int argc, char *argv[]) {
+ using namespace android;
+
+ sp<CommonTimeServer> service = new CommonTimeServer();
+ if (service == NULL)
+ return 1;
+
+ ProcessState::self()->startThreadPool();
+ service->run("CommonTimeServer", ANDROID_PRIORITY_NORMAL);
+
+ IPCThreadState::self()->joinThreadPool();
+ return 0;
+}
+
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 296c95e..1b74aa6 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -36,9 +36,9 @@
#include <errno.h>
#include <assert.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/KeyCharacterMap.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/VirtualKeyMap.h>
#include <string.h>
#include <stdint.h>
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 8a2afd3..4eb47c6 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -18,11 +18,11 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
-#include <ui/Input.h>
-#include <ui/Keyboard.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/KeyCharacterMap.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/Input.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/VirtualKeyMap.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Log.h>
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index 67ae94b..c04a935 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -17,7 +17,7 @@
#ifndef _UI_INPUT_APPLICATION_H
#define _UI_INPUT_APPLICATION_H
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index ad64ccd..149c0d3 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -24,24 +24,15 @@
// Log detailed debug messages about each outbound event processed by the dispatcher.
#define DEBUG_OUTBOUND_EVENT_DETAILS 0
-// Log debug messages about batching.
-#define DEBUG_BATCHING 0
-
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 0
// Log debug messages about registrations.
#define DEBUG_REGISTRATION 0
-// Log debug messages about performance statistics.
-#define DEBUG_PERFORMANCE_STATISTICS 0
-
// Log debug messages about input event injection.
#define DEBUG_INJECTION 0
-// Log debug messages about input event throttling.
-#define DEBUG_THROTTLING 0
-
// Log debug messages about input focus tracking.
#define DEBUG_FOCUS 0
@@ -54,7 +45,7 @@
#include "InputDispatcher.h"
#include <cutils/log.h>
-#include <ui/PowerManager.h>
+#include <androidfw/PowerManager.h>
#include <stddef.h>
#include <unistd.h>
@@ -79,21 +70,11 @@
// before considering it stale and dropping it.
const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
-// Motion samples that are received within this amount of time are simply coalesced
-// when batched instead of being appended. This is done because some drivers update
-// the location of pointers one at a time instead of all at once.
-// For example, when there are 10 fingers down, the input dispatcher may receive 10
-// samples in quick succession with only one finger's location changed in each sample.
-//
-// This value effectively imposes an upper bound on the touch sampling rate.
-// Touch sensors typically have a 50Hz - 200Hz sampling rate, so we expect distinct
-// samples to become available 5-20ms apart but individual finger reports can trickle
-// in over a period of 2-4ms or so.
-//
-// Empirical testing shows that a 2ms coalescing interval (500Hz) is not enough,
-// a 3ms coalescing interval (333Hz) works well most of the time and doesn't introduce
-// significant quantization noise on current hardware.
-const nsecs_t MOTION_SAMPLE_COALESCE_INTERVAL = 3 * 1000000LL; // 3ms, 333Hz
+// Amount of time to allow touch events to be streamed out to a connection before requiring
+// that the first event be finished. This value extends the ANR timeout by the specified
+// amount. For example, if streaming is allowed to get ahead by one second relative to the
+// queue of waiting unfinished events, then ANRs will similarly be delayed by one second.
+const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
static inline nsecs_t now() {
@@ -203,21 +184,12 @@
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false),
- mCurrentInputTargetsValid(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
-
- mThrottleState.minTimeBetweenEvents = 1000000000LL / mConfig.maxEventsPerSecond;
- mThrottleState.lastDeviceId = -1;
-
-#if DEBUG_THROTTLING
- mThrottleState.originalSampleCount = 0;
- ALOGD("Throttling - Max events per second = %d", mConfig.maxEventsPerSecond);
-#endif
}
InputDispatcher::~InputDispatcher() {
@@ -229,8 +201,8 @@
drainInboundQueueLocked();
}
- while (mConnectionsByReceiveFd.size() != 0) {
- unregisterInputChannel(mConnectionsByReceiveFd.valueAt(0)->inputChannel);
+ while (mConnectionsByFd.size() != 0) {
+ unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
}
}
@@ -302,78 +274,21 @@
}
// Nothing to do if there is no pending event.
- if (! mPendingEvent) {
- if (mActiveConnections.isEmpty()) {
- dispatchIdleLocked();
- }
+ if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
- EventEntry* entry = mInboundQueue.head;
-
- // Throttle the entry if it is a move event and there are no
- // other events behind it in the queue. Due to movement batching, additional
- // samples may be appended to this event by the time the throttling timeout
- // expires.
- // TODO Make this smarter and consider throttling per device independently.
- if (entry->type == EventEntry::TYPE_MOTION
- && !isAppSwitchDue
- && mDispatchEnabled
- && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
- && !entry->isInjected()) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- int32_t deviceId = motionEntry->deviceId;
- uint32_t source = motionEntry->source;
- if (! isAppSwitchDue
- && !motionEntry->next // exactly one event, no successors
- && (motionEntry->action == AMOTION_EVENT_ACTION_MOVE
- || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
- && deviceId == mThrottleState.lastDeviceId
- && source == mThrottleState.lastSource) {
- nsecs_t nextTime = mThrottleState.lastEventTime
- + mThrottleState.minTimeBetweenEvents;
- if (currentTime < nextTime) {
- // Throttle it!
-#if DEBUG_THROTTLING
- ALOGD("Throttling - Delaying motion event for "
- "device %d, source 0x%08x by up to %0.3fms.",
- deviceId, source, (nextTime - currentTime) * 0.000001);
-#endif
- if (nextTime < *nextWakeupTime) {
- *nextWakeupTime = nextTime;
- }
- if (mThrottleState.originalSampleCount == 0) {
- mThrottleState.originalSampleCount =
- motionEntry->countSamples();
- }
- return;
- }
- }
-
-#if DEBUG_THROTTLING
- if (mThrottleState.originalSampleCount != 0) {
- uint32_t count = motionEntry->countSamples();
- ALOGD("Throttling - Motion event sample count grew by %d from %d to %d.",
- count - mThrottleState.originalSampleCount,
- mThrottleState.originalSampleCount, count);
- mThrottleState.originalSampleCount = 0;
- }
-#endif
-
- mThrottleState.lastEventTime = currentTime;
- mThrottleState.lastDeviceId = deviceId;
- mThrottleState.lastSource = source;
- }
-
- mInboundQueue.dequeue(entry);
- mPendingEvent = entry;
+ mPendingEvent = mInboundQueue.dequeueAtHead();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
+
+ // Get ready to dispatch the event.
+ resetANRTimeoutsLocked();
}
// Now we have an event to dispatch.
@@ -461,16 +376,6 @@
}
}
-void InputDispatcher::dispatchIdleLocked() {
-#if DEBUG_FOCUS
- ALOGD("Dispatcher idle. There are no pending events or active connections.");
-#endif
-
- // Reset targets when idle, to release input channels and other resources
- // they are holding onto.
- resetTargetsLocked();
-}
-
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
@@ -508,9 +413,9 @@
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
&& mInputTargetWaitApplicationHandle != NULL) {
- int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].
+ int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].
+ int32_t y = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
if (touchedWindowHandle != NULL
@@ -671,6 +576,7 @@
void InputDispatcher::releasePendingEventLocked() {
if (mPendingEvent) {
+ resetANRTimeoutsLocked();
releaseInboundEventLocked(mPendingEvent);
mPendingEvent = NULL;
}
@@ -793,7 +699,6 @@
}
entry->dispatchInProgress = true;
- resetTargetsLocked();
logOutboundKeyDetailsLocked("dispatchKey - ", entry);
}
@@ -832,31 +737,28 @@
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
- resetTargetsLocked();
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
// Identify targets.
- if (! mCurrentInputTargetsValid) {
- int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
-
- setInjectionResultLocked(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- return true;
- }
-
- addMonitoringTargetsLocked();
- commitTargetsLocked();
+ Vector<InputTarget> inputTargets;
+ int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
+ entry, inputTargets, nextWakeupTime);
+ if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
+ return false;
}
+ setInjectionResultLocked(entry, injectionResult);
+ if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+ return true;
+ }
+
+ addMonitoringTargetsLocked(inputTargets);
+
// Dispatch the key.
- dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
+ dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
@@ -877,14 +779,12 @@
// Preprocessing.
if (! entry->dispatchInProgress) {
entry->dispatchInProgress = true;
- resetTargetsLocked();
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
}
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
- resetTargetsLocked();
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
@@ -893,67 +793,29 @@
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
+ Vector<InputTarget> inputTargets;
+
bool conflictingPointerActions = false;
- if (! mCurrentInputTargetsValid) {
- int32_t injectionResult;
- const MotionSample* splitBatchAfterSample = NULL;
- if (isPointerEvent) {
- // Pointer event. (eg. touchscreen)
- injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime, &conflictingPointerActions, &splitBatchAfterSample);
- } else {
- // Non touch event. (eg. trackball)
- injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- }
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
-
- setInjectionResultLocked(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- return true;
- }
-
- addMonitoringTargetsLocked();
- commitTargetsLocked();
-
- // Unbatch the event if necessary by splitting it into two parts after the
- // motion sample indicated by splitBatchAfterSample.
- if (splitBatchAfterSample && splitBatchAfterSample->next) {
-#if DEBUG_BATCHING
- uint32_t originalSampleCount = entry->countSamples();
-#endif
- MotionSample* nextSample = splitBatchAfterSample->next;
- MotionEntry* nextEntry = new MotionEntry(nextSample->eventTime,
- entry->deviceId, entry->source, entry->policyFlags,
- entry->action, entry->flags,
- entry->metaState, entry->buttonState, entry->edgeFlags,
- entry->xPrecision, entry->yPrecision, entry->downTime,
- entry->pointerCount, entry->pointerProperties, nextSample->pointerCoords);
- if (nextSample != entry->lastSample) {
- nextEntry->firstSample.next = nextSample->next;
- nextEntry->lastSample = entry->lastSample;
- }
- delete nextSample;
-
- entry->lastSample = const_cast<MotionSample*>(splitBatchAfterSample);
- entry->lastSample->next = NULL;
-
- if (entry->injectionState) {
- nextEntry->injectionState = entry->injectionState;
- entry->injectionState->refCount += 1;
- }
-
-#if DEBUG_BATCHING
- ALOGD("Split batch of %d samples into two parts, first part has %d samples, "
- "second part has %d samples.", originalSampleCount,
- entry->countSamples(), nextEntry->countSamples());
-#endif
-
- mInboundQueue.enqueueAtHead(nextEntry);
- }
+ int32_t injectionResult;
+ if (isPointerEvent) {
+ // Pointer event. (eg. touchscreen)
+ injectionResult = findTouchedWindowTargetsLocked(currentTime,
+ entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
+ } else {
+ // Non touch event. (eg. trackball)
+ injectionResult = findFocusedWindowTargetsLocked(currentTime,
+ entry, inputTargets, nextWakeupTime);
}
+ if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
+ return false;
+ }
+
+ setInjectionResultLocked(entry, injectionResult);
+ if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+ return true;
+ }
+
+ addMonitoringTargetsLocked(inputTargets);
// Dispatch the motion.
if (conflictingPointerActions) {
@@ -961,7 +823,7 @@
"conflicting pointer actions");
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
- dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
+ dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
@@ -979,12 +841,6 @@
entry->edgeFlags, entry->xPrecision, entry->yPrecision,
entry->downTime);
- // Print the most recent sample that we have available, this may change due to batching.
- size_t sampleCount = 1;
- const MotionSample* sample = & entry->firstSample;
- for (; sample->next != NULL; sample = sample->next) {
- sampleCount += 1;
- }
for (uint32_t i = 0; i < entry->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
@@ -992,45 +848,36 @@
"orientation=%f",
i, entry->pointerProperties[i].id,
entry->pointerProperties[i].toolType,
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
- }
-
- // Keep in mind that due to batching, it is possible for the number of samples actually
- // dispatched to change before the application finally consumed them.
- if (entry->action == AMOTION_EVENT_ACTION_MOVE) {
- ALOGD(" ... Total movement samples currently batched %d ...", sampleCount);
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
#endif
}
-void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
- EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
+void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
+ EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("dispatchEventToCurrentInputTargets - "
- "resumeWithAppendedMotionSample=%s",
- toString(resumeWithAppendedMotionSample));
+ ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
- for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
- const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
+ for (size_t i = 0; i < inputTargets.size(); i++) {
+ const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
- resumeWithAppendedMotionSample);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
#if DEBUG_FOCUS
ALOGD("Dropping event delivery to target with channel '%s' because it "
@@ -1041,16 +888,6 @@
}
}
-void InputDispatcher::resetTargetsLocked() {
- mCurrentInputTargetsValid = false;
- mCurrentInputTargets.clear();
- resetANRTimeoutsLocked();
-}
-
-void InputDispatcher::commitTargetsLocked() {
- mCurrentInputTargetsValid = true;
-}
-
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
@@ -1135,7 +972,7 @@
if (inputChannel.get()) {
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->status == Connection::STATUS_NORMAL) {
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
"application not responding");
@@ -1165,9 +1002,7 @@
}
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, nsecs_t* nextWakeupTime) {
- mCurrentInputTargets.clear();
-
+ const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
// If there is no currently focused window and no focused application
@@ -1206,7 +1041,7 @@
}
// If the currently focused window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
+ if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) {
#if DEBUG_FOCUS
ALOGD("Waiting because focused window still processing previous input.");
#endif
@@ -1218,7 +1053,8 @@
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(mFocusedWindowHandle,
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
+ InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
+ inputTargets);
// Done.
Failed:
@@ -1235,16 +1071,14 @@
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
- const MotionSample** outSplitBatchAfterSample) {
+ const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+ bool* outConflictingPointerActions) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
INJECTION_PERMISSION_DENIED
};
- mCurrentInputTargets.clear();
-
nsecs_t startTime = now();
// For security reasons, we defer updating the touch state until we are sure that
@@ -1316,11 +1150,10 @@
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
- const MotionSample* sample = &entry->firstSample;
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- int32_t x = int32_t(sample->pointerCoords[pointerIndex].
+ int32_t x = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(sample->pointerCoords[pointerIndex].
+ int32_t y = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> newTouchedWindowHandle;
sp<InputWindowHandle> topErrorWindowHandle;
@@ -1420,21 +1253,6 @@
// Update hover state.
if (isHoverAction) {
newHoverWindowHandle = newTouchedWindowHandle;
-
- // Ensure all subsequent motion samples are also within the touched window.
- // Set *outSplitBatchAfterSample to the sample before the first one that is not
- // within the touched window.
- if (!isTouchModal) {
- while (sample->next) {
- if (!newHoverWindowHandle->getInfo()->touchableRegionContainsPoint(
- sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
- sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
- *outSplitBatchAfterSample = sample;
- break;
- }
- sample = sample->next;
- }
- }
} else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
newHoverWindowHandle = mLastHoverWindowHandle;
}
@@ -1463,9 +1281,8 @@
if (maskedAction == AMOTION_EVENT_ACTION_MOVE
&& entry->pointerCount == 1
&& mTempTouchState.isSlippery()) {
- const MotionSample* sample = &entry->firstSample;
- int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
+ int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> oldTouchedWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
@@ -1500,17 +1317,11 @@
pointerIds.markBit(entry->pointerProperties[0].id);
}
mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
-
- // Split the batch here so we send exactly one sample.
- *outSplitBatchAfterSample = &entry->firstSample;
}
}
}
if (newHoverWindowHandle != mLastHoverWindowHandle) {
- // Split the batch here so we send exactly one sample as part of ENTER or EXIT.
- *outSplitBatchAfterSample = &entry->firstSample;
-
// Let the previous window know that the hover sequence is over.
if (mLastHoverWindowHandle != NULL) {
#if DEBUG_HOVER
@@ -1593,7 +1404,7 @@
}
// If the touched window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) {
+ if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) {
#if DEBUG_FOCUS
ALOGD("Waiting because touched window still processing previous input.");
#endif
@@ -1633,7 +1444,7 @@
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
- touchedWindow.pointerIds);
+ touchedWindow.pointerIds, inputTargets);
}
// Drop the outside or hover touch windows since we will not care about them
@@ -1738,11 +1549,11 @@
}
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds) {
- mCurrentInputTargets.push();
+ int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
+ inputTargets.push();
const InputWindowInfo* windowInfo = windowHandle->getInfo();
- InputTarget& target = mCurrentInputTargets.editTop();
+ InputTarget& target = inputTargets.editTop();
target.inputChannel = windowInfo->inputChannel;
target.flags = targetFlags;
target.xOffset = - windowInfo->frameLeft;
@@ -1751,11 +1562,11 @@
target.pointerIds = pointerIds;
}
-void InputDispatcher::addMonitoringTargetsLocked() {
+void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) {
for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- mCurrentInputTargets.push();
+ inputTargets.push();
- InputTarget& target = mCurrentInputTargets.editTop();
+ InputTarget& target = inputTargets.editTop();
target.inputChannel = mMonitoringChannels[i];
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
target.xOffset = 0;
@@ -1804,15 +1615,51 @@
return false;
}
-bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
- const sp<InputWindowHandle>& windowHandle) {
+bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime,
+ const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry) {
ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- return connection->outboundQueue.isEmpty();
- } else {
- return true;
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ if (connection->inputPublisherBlocked) {
+ return false;
+ }
+ if (eventEntry->type == EventEntry::TYPE_KEY) {
+ // If the event is a key event, then we must wait for all previous events to
+ // complete before delivering it because previous events may have the
+ // side-effect of transferring focus to a different window and we want to
+ // ensure that the following keys are sent to the new window.
+ //
+ // Suppose the user touches a button in a window then immediately presses "A".
+ // If the button causes a pop-up window to appear then we want to ensure that
+ // the "A" key is delivered to the new pop-up window. This is because users
+ // often anticipate pending UI changes when typing on a keyboard.
+ // To obtain this behavior, we must serialize key events with respect to all
+ // prior input events.
+ return connection->outboundQueue.isEmpty()
+ && connection->waitQueue.isEmpty();
+ }
+ // Touch events can always be sent to a window immediately because the user intended
+ // to touch whatever was visible at the time. Even if focus changes or a new
+ // window appears moments later, the touch event was meant to be delivered to
+ // whatever window happened to be on screen at the time.
+ //
+ // Generic motion events, such as trackball or joystick events are a little trickier.
+ // Like key events, generic motion events are delivered to the focused window.
+ // Unlike key events, generic motion events don't tend to transfer focus to other
+ // windows and it is not important for them to be serialized. So we prefer to deliver
+ // generic motion events as soon as possible to improve efficiency and reduce lag
+ // through batching.
+ //
+ // The one case where we pause input event delivery is when the wait queue is piling
+ // up with lots of events because the application is not responding.
+ // This condition ensures that ANRs are detected reliably.
+ if (!connection->waitQueue.isEmpty()
+ && currentTime >= connection->waitQueue.head->eventEntry->eventTime
+ + STREAM_AHEAD_EVENT_TIMEOUT) {
+ return false;
+ }
}
+ return true;
}
String8 InputDispatcher::getApplicationWindowLabelLocked(
@@ -1865,23 +1712,16 @@
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample) {
+ const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, scaleFactor=%f, "
- "pointerIds=0x%x, "
- "resumeWithAppendedMotionSample=%s",
+ "pointerIds=0x%x",
connection->getInputChannelName(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->scaleFactor, inputTarget->pointerIds.value,
- toString(resumeWithAppendedMotionSample));
+ inputTarget->scaleFactor, inputTarget->pointerIds.value);
#endif
- // Make sure we are never called for streaming when splitting across multiple windows.
- bool isSplit = inputTarget->flags & InputTarget::FLAG_SPLIT;
- ALOG_ASSERT(! (resumeWithAppendedMotionSample && isSplit));
-
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
@@ -1893,7 +1733,7 @@
}
// Split a motion event if needed.
- if (isSplit) {
+ if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
@@ -1909,145 +1749,43 @@
logOutboundMotionDetailsLocked(" ", splitMotionEntry);
#endif
enqueueDispatchEntriesLocked(currentTime, connection,
- splitMotionEntry, inputTarget, resumeWithAppendedMotionSample);
+ splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
- enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample);
+ enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample) {
- // Resume the dispatch cycle with a freshly appended motion sample.
- // First we check that the last dispatch entry in the outbound queue is for the same
- // motion event to which we appended the motion sample. If we find such a dispatch
- // entry, and if it is currently in progress then we try to stream the new sample.
+ const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
- if (! wasEmpty && resumeWithAppendedMotionSample) {
- DispatchEntry* motionEventDispatchEntry =
- connection->findQueuedDispatchEntryForEvent(eventEntry);
- if (motionEventDispatchEntry) {
- // If the dispatch entry is not in progress, then we must be busy dispatching an
- // earlier event. Not a problem, the motion event is on the outbound queue and will
- // be dispatched later.
- if (! motionEventDispatchEntry->inProgress) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Not streaming because the motion event has "
- "not yet been dispatched. "
- "(Waiting for earlier events to be consumed.)",
- connection->getInputChannelName());
-#endif
- return;
- }
-
- // If the dispatch entry is in progress but it already has a tail of pending
- // motion samples, then it must mean that the shared memory buffer filled up.
- // Not a problem, when this dispatch cycle is finished, we will eventually start
- // a new dispatch cycle to process the tail and that tail includes the newly
- // appended motion sample.
- if (motionEventDispatchEntry->tailMotionSample) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Not streaming because no new samples can "
- "be appended to the motion event in this dispatch cycle. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
-#endif
- return;
- }
-
- // If the motion event was modified in flight, then we cannot stream the sample.
- if ((motionEventDispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_MASK)
- != InputTarget::FLAG_DISPATCH_AS_IS) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Not streaming because the motion event was not "
- "being dispatched as-is. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
-#endif
- return;
- }
-
- // The dispatch entry is in progress and is still potentially open for streaming.
- // Try to stream the new motion sample. This might fail if the consumer has already
- // consumed the motion event (or if the channel is broken).
- MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
- MotionSample* appendedMotionSample = motionEntry->lastSample;
- status_t status;
- if (motionEventDispatchEntry->scaleFactor == 1.0f) {
- status = connection->inputPublisher.appendMotionSample(
- appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
- } else {
- PointerCoords scaledCoords[MAX_POINTERS];
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = appendedMotionSample->pointerCoords[i];
- scaledCoords[i].scale(motionEventDispatchEntry->scaleFactor);
- }
- status = connection->inputPublisher.appendMotionSample(
- appendedMotionSample->eventTime, scaledCoords);
- }
- if (status == OK) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Successfully streamed new motion sample.",
- connection->getInputChannelName());
-#endif
- return;
- }
-
-#if DEBUG_BATCHING
- if (status == NO_MEMORY) {
- ALOGD("channel '%s' ~ Could not append motion sample to currently "
- "dispatched move event because the shared memory buffer is full. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
- } else if (status == status_t(FAILED_TRANSACTION)) {
- ALOGD("channel '%s' ~ Could not append motion sample to currently "
- "dispatched move event because the event has already been consumed. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
- } else {
- ALOGD("channel '%s' ~ Could not append motion sample to currently "
- "dispatched move event due to an error, status=%d. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName(), status);
- }
-#endif
- // Failed to stream. Start a new tail of pending motion samples to dispatch
- // in the next cycle.
- motionEventDispatchEntry->tailMotionSample = appendedMotionSample;
- return;
- }
- }
-
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
+ InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
+ InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
+ InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS);
+ InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
+ InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
+ InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
- activateConnectionLocked(connection.get());
startDispatchCycleLocked(currentTime, connection);
}
}
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample, int32_t dispatchMode) {
+ int32_t dispatchMode) {
int32_t inputTargetFlags = inputTarget->flags;
if (!(inputTargetFlags & dispatchMode)) {
return;
@@ -2060,20 +1798,6 @@
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
- // Handle the case where we could not stream a new motion sample because the consumer has
- // already consumed the motion event (otherwise the corresponding dispatch entry would
- // still be in the outbound queue for this connection). We set the head motion sample
- // to the list starting with the newly appended motion sample.
- if (resumeWithAppendedMotionSample) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Preparing a new dispatch cycle for additional motion samples "
- "that cannot be streamed because the motion event has already been consumed.",
- connection->getInputChannelName());
-#endif
- MotionSample* appendedMotionSample = static_cast<MotionEntry*>(eventEntry)->lastSample;
- dispatchEntry->headMotionSample = appendedMotionSample;
- }
-
// Apply target flags and update the connection's input state.
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
@@ -2152,227 +1876,128 @@
connection->getInputChannelName());
#endif
- ALOG_ASSERT(connection->status == Connection::STATUS_NORMAL);
- ALOG_ASSERT(! connection->outboundQueue.isEmpty());
+ while (connection->status == Connection::STATUS_NORMAL
+ && !connection->outboundQueue.isEmpty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- ALOG_ASSERT(! dispatchEntry->inProgress);
+ // Publish the event.
+ status_t status;
+ EventEntry* eventEntry = dispatchEntry->eventEntry;
+ switch (eventEntry->type) {
+ case EventEntry::TYPE_KEY: {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
- // Mark the dispatch entry as in progress.
- dispatchEntry->inProgress = true;
-
- // Publish the event.
- status_t status;
- EventEntry* eventEntry = dispatchEntry->eventEntry;
- switch (eventEntry->type) {
- case EventEntry::TYPE_KEY: {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-
- // Publish the key event.
- status = connection->inputPublisher.publishKeyEvent(
- keyEntry->deviceId, keyEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- keyEntry->keyCode, keyEntry->scanCode,
- keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
- keyEntry->eventTime);
-
- if (status) {
- ALOGE("channel '%s' ~ Could not publish key event, "
- "status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
- }
- break;
- }
-
- case EventEntry::TYPE_MOTION: {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
-
- // If headMotionSample is non-NULL, then it points to the first new sample that we
- // were unable to dispatch during the previous cycle so we resume dispatching from
- // that point in the list of motion samples.
- // Otherwise, we just start from the first sample of the motion event.
- MotionSample* firstMotionSample = dispatchEntry->headMotionSample;
- if (! firstMotionSample) {
- firstMotionSample = & motionEntry->firstSample;
+ // Publish the key event.
+ status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
+ keyEntry->deviceId, keyEntry->source,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+ keyEntry->keyCode, keyEntry->scanCode,
+ keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
+ keyEntry->eventTime);
+ break;
}
- PointerCoords scaledCoords[MAX_POINTERS];
- const PointerCoords* usingCoords = firstMotionSample->pointerCoords;
+ case EventEntry::TYPE_MOTION: {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
- // Set the X and Y offset depending on the input source.
- float xOffset, yOffset, scaleFactor;
- if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER
- && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- scaleFactor = dispatchEntry->scaleFactor;
- xOffset = dispatchEntry->xOffset * scaleFactor;
- yOffset = dispatchEntry->yOffset * scaleFactor;
- if (scaleFactor != 1.0f) {
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = firstMotionSample->pointerCoords[i];
- scaledCoords[i].scale(scaleFactor);
- }
- usingCoords = scaledCoords;
- }
- } else {
- xOffset = 0.0f;
- yOffset = 0.0f;
- scaleFactor = 1.0f;
+ PointerCoords scaledCoords[MAX_POINTERS];
+ const PointerCoords* usingCoords = motionEntry->pointerCoords;
- // We don't want the dispatch target to know.
- if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i].clear();
- }
- usingCoords = scaledCoords;
- }
- }
-
- // Publish the motion event and the first motion sample.
- status = connection->inputPublisher.publishMotionEvent(
- motionEntry->deviceId, motionEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
- xOffset, yOffset,
- motionEntry->xPrecision, motionEntry->yPrecision,
- motionEntry->downTime, firstMotionSample->eventTime,
- motionEntry->pointerCount, motionEntry->pointerProperties,
- usingCoords);
-
- if (status) {
- ALOGE("channel '%s' ~ Could not publish motion event, "
- "status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
- }
-
- if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_MOVE
- || dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- // Append additional motion samples.
- MotionSample* nextMotionSample = firstMotionSample->next;
- for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
- if (usingCoords == scaledCoords) {
- if (!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = nextMotionSample->pointerCoords[i];
- scaledCoords[i].scale(scaleFactor);
- }
+ // Set the X and Y offset depending on the input source.
+ float xOffset, yOffset, scaleFactor;
+ if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
+ && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
+ scaleFactor = dispatchEntry->scaleFactor;
+ xOffset = dispatchEntry->xOffset * scaleFactor;
+ yOffset = dispatchEntry->yOffset * scaleFactor;
+ if (scaleFactor != 1.0f) {
+ for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+ scaledCoords[i] = motionEntry->pointerCoords[i];
+ scaledCoords[i].scale(scaleFactor);
}
- } else {
- usingCoords = nextMotionSample->pointerCoords;
+ usingCoords = scaledCoords;
}
- status = connection->inputPublisher.appendMotionSample(
- nextMotionSample->eventTime, usingCoords);
- if (status == NO_MEMORY) {
+ } else {
+ xOffset = 0.0f;
+ yOffset = 0.0f;
+ scaleFactor = 1.0f;
+
+ // We don't want the dispatch target to know.
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
+ for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+ scaledCoords[i].clear();
+ }
+ usingCoords = scaledCoords;
+ }
+ }
+
+ // Publish the motion event.
+ status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
+ motionEntry->deviceId, motionEntry->source,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+ motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
+ xOffset, yOffset,
+ motionEntry->xPrecision, motionEntry->yPrecision,
+ motionEntry->downTime, motionEntry->eventTime,
+ motionEntry->pointerCount, motionEntry->pointerProperties,
+ usingCoords);
+ break;
+ }
+
+ default:
+ ALOG_ASSERT(false);
+ return;
+ }
+
+ // Check the result.
+ if (status) {
+ if (status == WOULD_BLOCK) {
+ if (connection->waitQueue.isEmpty()) {
+ ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
+ "This is unexpected because the wait queue is empty, so the pipe "
+ "should be empty and we shouldn't have any problems writing an "
+ "event to it, status=%d", connection->getInputChannelName(), status);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
+ } else {
+ // Pipe is full and we are waiting for the app to finish process some events
+ // before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will "
- "be sent in the next dispatch cycle.",
+ ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
+ "waiting for the application to catch up",
connection->getInputChannelName());
#endif
- break;
+ connection->inputPublisherBlocked = true;
}
- if (status != OK) {
- ALOGE("channel '%s' ~ Could not append motion sample "
- "for a reason other than out of memory, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
- }
+ } else {
+ ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
+ "status=%d", connection->getInputChannelName(), status);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
-
- // Remember the next motion sample that we could not dispatch, in case we ran out
- // of space in the shared memory buffer.
- dispatchEntry->tailMotionSample = nextMotionSample;
+ return;
}
- break;
- }
- default: {
- ALOG_ASSERT(false);
+ // Re-enqueue the event on the wait queue.
+ connection->outboundQueue.dequeue(dispatchEntry);
+ connection->waitQueue.enqueueAtTail(dispatchEntry);
}
- }
-
- // Send the dispatch signal.
- status = connection->inputPublisher.sendDispatchSignal();
- if (status) {
- ALOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
- }
-
- // Record information about the newly started dispatch cycle.
- connection->lastEventTime = eventEntry->eventTime;
- connection->lastDispatchTime = currentTime;
-
- // Notify other system components.
- onDispatchCycleStartedLocked(currentTime, connection);
}
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, bool handled) {
+ const sp<Connection>& connection, uint32_t seq, bool handled) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
- "%01.1fms since dispatch, handled=%s",
- connection->getInputChannelName(),
- connection->getEventLatencyMillis(currentTime),
- connection->getDispatchLatencyMillis(currentTime),
- toString(handled));
+ ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
+ connection->getInputChannelName(), seq, toString(handled));
#endif
+ connection->inputPublisherBlocked = false;
+
if (connection->status == Connection::STATUS_BROKEN
|| connection->status == Connection::STATUS_ZOMBIE) {
return;
}
- // Reset the publisher since the event has been consumed.
- // We do this now so that the publisher can release some of its internal resources
- // while waiting for the next dispatch cycle to begin.
- status_t status = connection->inputPublisher.reset();
- if (status) {
- ALOGE("channel '%s' ~ Could not reset publisher, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
- }
-
// Notify other system components and prepare to start the next dispatch cycle.
- onDispatchCycleFinishedLocked(currentTime, connection, handled);
-}
-
-void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- // Start the next dispatch cycle for this connection.
- while (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (dispatchEntry->inProgress) {
- // Finish or resume current event in progress.
- if (dispatchEntry->tailMotionSample) {
- // We have a tail of undispatched motion samples.
- // Reuse the same DispatchEntry and start a new cycle.
- dispatchEntry->inProgress = false;
- dispatchEntry->headMotionSample = dispatchEntry->tailMotionSample;
- dispatchEntry->tailMotionSample = NULL;
- startDispatchCycleLocked(currentTime, connection);
- return;
- }
- // Finished.
- connection->outboundQueue.dequeueAtHead();
- if (dispatchEntry->hasForegroundTarget()) {
- decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
- }
- delete dispatchEntry;
- } else {
- // If the head is not in progress, then we must have already dequeued the in
- // progress event, which means we actually aborted it.
- // So just start the next event for this connection.
- startDispatchCycleLocked(currentTime, connection);
- return;
- }
- }
-
- // Outbound queue is empty, deactivate the connection.
- deactivateConnectionLocked(connection.get());
+ onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
@@ -2382,8 +2007,9 @@
connection->getInputChannelName(), toString(notify));
#endif
- // Clear the outbound queue.
- drainOutboundQueueLocked(connection.get());
+ // Clear the dispatch queues.
+ drainDispatchQueueLocked(&connection->outboundQueue);
+ drainDispatchQueueLocked(&connection->waitQueue);
// The connection appears to be unrecoverably broken.
// Ignore already broken or zombie connections.
@@ -2397,33 +2023,35 @@
}
}
-void InputDispatcher::drainOutboundQueueLocked(Connection* connection) {
- while (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
- if (dispatchEntry->hasForegroundTarget()) {
- decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
- }
- delete dispatchEntry;
+void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) {
+ while (!queue->isEmpty()) {
+ DispatchEntry* dispatchEntry = queue->dequeueAtHead();
+ releaseDispatchEntryLocked(dispatchEntry);
}
-
- deactivateConnectionLocked(connection);
}
-int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
+void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) {
+ if (dispatchEntry->hasForegroundTarget()) {
+ decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
+ }
+ delete dispatchEntry;
+}
+
+int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
InputDispatcher* d = static_cast<InputDispatcher*>(data);
{ // acquire lock
AutoMutex _l(d->mLock);
- ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
+ ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
if (connectionIndex < 0) {
ALOGE("Received spurious receive callback for unknown input channel. "
- "fd=%d, events=0x%x", receiveFd, events);
+ "fd=%d, events=0x%x", fd, events);
return 0; // remove the callback
}
bool notify;
- sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
+ sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
if (!(events & ALOOPER_EVENT_INPUT)) {
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
@@ -2431,18 +2059,31 @@
return 1;
}
- bool handled = false;
- status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
- if (!status) {
- nsecs_t currentTime = now();
- d->finishDispatchCycleLocked(currentTime, connection, handled);
+ nsecs_t currentTime = now();
+ bool gotOne = false;
+ status_t status;
+ for (;;) {
+ uint32_t seq;
+ bool handled;
+ status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
+ if (status) {
+ break;
+ }
+ d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
+ gotOne = true;
+ }
+ if (gotOne) {
d->runCommandsLockedInterruptible();
- return 1;
+ if (status == WOULD_BLOCK) {
+ return 1;
+ }
}
- ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
- connection->getInputChannelName(), status);
- notify = true;
+ notify = status != DEAD_OBJECT || !connection->monitor;
+ if (notify) {
+ ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
+ connection->getInputChannelName(), status);
+ }
} else {
// Monitor channels are never explicitly unregistered.
// We do it automatically when the remote endpoint is closed so don't warn
@@ -2462,9 +2103,9 @@
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) {
- for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
+ for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
synthesizeCancelationEventsForConnectionLocked(
- mConnectionsByReceiveFd.valueAt(i), options);
+ mConnectionsByFd.valueAt(i), options);
}
}
@@ -2473,7 +2114,7 @@
ssize_t index = getConnectionIndexLocked(channel);
if (index >= 0) {
synthesizeCancelationEventsForConnectionLocked(
- mConnectionsByReceiveFd.valueAt(index), options);
+ mConnectionsByFd.valueAt(index), options);
}
}
@@ -2485,19 +2126,19 @@
nsecs_t currentTime = now();
- mTempCancelationEvents.clear();
+ Vector<EventEntry*> cancelationEvents;
connection->inputState.synthesizeCancelationEvents(currentTime,
- mTempCancelationEvents, options);
+ cancelationEvents, options);
- if (!mTempCancelationEvents.isEmpty()) {
+ if (!cancelationEvents.isEmpty()) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
"with reality: %s, mode=%d.",
- connection->getInputChannelName(), mTempCancelationEvents.size(),
+ connection->getInputChannelName(), cancelationEvents.size(),
options.reason, options.mode);
#endif
- for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
- EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
+ for (size_t i = 0; i < cancelationEvents.size(); i++) {
+ EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
switch (cancelationEventEntry->type) {
case EventEntry::TYPE_KEY:
logOutboundKeyDetailsLocked("cancel - ",
@@ -2525,14 +2166,12 @@
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
- &target, false, InputTarget::FLAG_DISPATCH_AS_IS);
+ &target, InputTarget::FLAG_DISPATCH_AS_IS);
cancelationEventEntry->release();
}
- if (!connection->outboundQueue.head->inProgress) {
- startDispatchCycleLocked(currentTime, connection);
- }
+ startDispatchCycleLocked(currentTime, connection);
}
}
@@ -2556,7 +2195,7 @@
splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
splitPointerProperties[splitPointerCount].copyFrom(pointerProperties);
splitPointerCoords[splitPointerCount].copyFrom(
- originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]);
+ originalMotionEntry->pointerCoords[originalPointerIndex]);
splitPointerCount += 1;
}
}
@@ -2617,18 +2256,6 @@
originalMotionEntry->downTime,
splitPointerCount, splitPointerProperties, splitPointerCoords);
- for (MotionSample* originalMotionSample = originalMotionEntry->firstSample.next;
- originalMotionSample != NULL; originalMotionSample = originalMotionSample->next) {
- for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
- splitPointerIndex++) {
- uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
- splitPointerCoords[splitPointerIndex].copyFrom(
- originalMotionSample->pointerCoords[originalPointerIndex]);
- }
-
- splitMotionEntry->appendSample(originalMotionSample->eventTime, splitPointerCoords);
- }
-
if (originalMotionEntry->injectionState) {
splitMotionEntry->injectionState = originalMotionEntry->injectionState;
splitMotionEntry->injectionState->refCount += 1;
@@ -2789,163 +2416,6 @@
mLock.lock();
}
- // Attempt batching and streaming of move events.
- if (args->action == AMOTION_EVENT_ACTION_MOVE
- || args->action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- // BATCHING CASE
- //
- // Try to append a move sample to the tail of the inbound queue for this device.
- // Give up if we encounter a non-move motion event for this device since that
- // means we cannot append any new samples until a new motion event has started.
- for (EventEntry* entry = mInboundQueue.tail; entry; entry = entry->prev) {
- if (entry->type != EventEntry::TYPE_MOTION) {
- // Keep looking for motion events.
- continue;
- }
-
- MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- if (motionEntry->deviceId != args->deviceId
- || motionEntry->source != args->source) {
- // Keep looking for this device and source.
- continue;
- }
-
- if (!motionEntry->canAppendSamples(args->action,
- args->pointerCount, args->pointerProperties)) {
- // Last motion event in the queue for this device and source is
- // not compatible for appending new samples. Stop here.
- goto NoBatchingOrStreaming;
- }
-
- // Do the batching magic.
- batchMotionLocked(motionEntry, args->eventTime,
- args->metaState, args->pointerCoords,
- "most recent motion event for this device and source in the inbound queue");
- mLock.unlock();
- return; // done!
- }
-
- // BATCHING ONTO PENDING EVENT CASE
- //
- // Try to append a move sample to the currently pending event, if there is one.
- // We can do this as long as we are still waiting to find the targets for the
- // event. Once the targets are locked-in we can only do streaming.
- if (mPendingEvent
- && (!mPendingEvent->dispatchInProgress || !mCurrentInputTargetsValid)
- && mPendingEvent->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(mPendingEvent);
- if (motionEntry->deviceId == args->deviceId
- && motionEntry->source == args->source) {
- if (!motionEntry->canAppendSamples(args->action,
- args->pointerCount, args->pointerProperties)) {
- // Pending motion event is for this device and source but it is
- // not compatible for appending new samples. Stop here.
- goto NoBatchingOrStreaming;
- }
-
- // Do the batching magic.
- batchMotionLocked(motionEntry, args->eventTime,
- args->metaState, args->pointerCoords,
- "pending motion event");
- mLock.unlock();
- return; // done!
- }
- }
-
- // STREAMING CASE
- //
- // There is no pending motion event (of any kind) for this device in the inbound queue.
- // Search the outbound queue for the current foreground targets to find a dispatched
- // motion event that is still in progress. If found, then, appen the new sample to
- // that event and push it out to all current targets. The logic in
- // prepareDispatchCycleLocked takes care of the case where some targets may
- // already have consumed the motion event by starting a new dispatch cycle if needed.
- if (mCurrentInputTargetsValid) {
- for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
- const InputTarget& inputTarget = mCurrentInputTargets[i];
- if ((inputTarget.flags & InputTarget::FLAG_FOREGROUND) == 0) {
- // Skip non-foreground targets. We only want to stream if there is at
- // least one foreground target whose dispatch is still in progress.
- continue;
- }
-
- ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
- if (connectionIndex < 0) {
- // Connection must no longer be valid.
- continue;
- }
-
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (connection->outboundQueue.isEmpty()) {
- // This foreground target has an empty outbound queue.
- continue;
- }
-
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (! dispatchEntry->inProgress
- || dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION
- || dispatchEntry->isSplit()) {
- // No motion event is being dispatched, or it is being split across
- // windows in which case we cannot stream.
- continue;
- }
-
- MotionEntry* motionEntry = static_cast<MotionEntry*>(
- dispatchEntry->eventEntry);
- if (motionEntry->action != args->action
- || motionEntry->deviceId != args->deviceId
- || motionEntry->source != args->source
- || motionEntry->pointerCount != args->pointerCount
- || motionEntry->isInjected()) {
- // The motion event is not compatible with this move.
- continue;
- }
-
- if (args->action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- if (mLastHoverWindowHandle == NULL) {
-#if DEBUG_BATCHING
- ALOGD("Not streaming hover move because there is no "
- "last hovered window.");
-#endif
- goto NoBatchingOrStreaming;
- }
-
- sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked(
- args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
- args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (mLastHoverWindowHandle != hoverWindowHandle) {
-#if DEBUG_BATCHING
- ALOGD("Not streaming hover move because the last hovered window "
- "is '%s' but the currently hovered window is '%s'.",
- mLastHoverWindowHandle->getName().string(),
- hoverWindowHandle != NULL
- ? hoverWindowHandle->getName().string() : "<null>");
-#endif
- goto NoBatchingOrStreaming;
- }
- }
-
- // Hurray! This foreground target is currently dispatching a move event
- // that we can stream onto. Append the motion sample and resume dispatch.
- motionEntry->appendSample(args->eventTime, args->pointerCoords);
-#if DEBUG_BATCHING
- ALOGD("Appended motion sample onto batch for most recently dispatched "
- "motion event for this device and source in the outbound queues. "
- "Attempting to stream the motion sample.");
-#endif
- nsecs_t currentTime = now();
- dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
- true /*resumeWithAppendedMotionSample*/);
-
- runCommandsLockedInterruptible();
- mLock.unlock();
- return; // done!
- }
- }
-
-NoBatchingOrStreaming:;
- }
-
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
@@ -2962,36 +2432,6 @@
}
}
-void InputDispatcher::batchMotionLocked(MotionEntry* entry, nsecs_t eventTime,
- int32_t metaState, const PointerCoords* pointerCoords, const char* eventDescription) {
- // Combine meta states.
- entry->metaState |= metaState;
-
- // Coalesce this sample if not enough time has elapsed since the last sample was
- // initially appended to the batch.
- MotionSample* lastSample = entry->lastSample;
- long interval = eventTime - lastSample->eventTimeBeforeCoalescing;
- if (interval <= MOTION_SAMPLE_COALESCE_INTERVAL) {
- uint32_t pointerCount = entry->pointerCount;
- for (uint32_t i = 0; i < pointerCount; i++) {
- lastSample->pointerCoords[i].copyFrom(pointerCoords[i]);
- }
- lastSample->eventTime = eventTime;
-#if DEBUG_BATCHING
- ALOGD("Coalesced motion into last sample of batch for %s, events were %0.3f ms apart",
- eventDescription, interval * 0.000001f);
-#endif
- return;
- }
-
- // Append the sample.
- entry->appendSample(eventTime, pointerCoords);
-#if DEBUG_BATCHING
- ALOGD("Appended motion sample onto batch for %s, events were %0.3f ms apart",
- eventDescription, interval * 0.000001f);
-#endif
-}
-
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchCode=%d, switchValue=%d",
@@ -3040,7 +2480,8 @@
policyFlags |= POLICY_FLAG_TRUSTED;
}
- EventEntry* injectedEntry;
+ EventEntry* firstInjectedEntry;
+ EventEntry* lastInjectedEntry;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
@@ -3063,11 +2504,12 @@
}
mLock.lock();
- injectedEntry = new KeyEntry(keyEvent->getEventTime(),
+ firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
keyEvent->getDeviceId(), keyEvent->getSource(),
policyFlags, action, flags,
keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), keyEvent->getDownTime());
+ lastInjectedEntry = firstInjectedEntry;
break;
}
@@ -3088,7 +2530,7 @@
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- MotionEntry* motionEntry = new MotionEntry(*sampleEventTimes,
+ firstInjectedEntry = new MotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
action, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
@@ -3096,12 +2538,21 @@
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(), uint32_t(pointerCount),
pointerProperties, samplePointerCoords);
+ lastInjectedEntry = firstInjectedEntry;
for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
- motionEntry->appendSample(*sampleEventTimes, samplePointerCoords);
+ MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
+ motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+ action, motionEvent->getFlags(),
+ motionEvent->getMetaState(), motionEvent->getButtonState(),
+ motionEvent->getEdgeFlags(),
+ motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+ motionEvent->getDownTime(), uint32_t(pointerCount),
+ pointerProperties, samplePointerCoords);
+ lastInjectedEntry->next = nextInjectedEntry;
+ lastInjectedEntry = nextInjectedEntry;
}
- injectedEntry = motionEntry;
break;
}
@@ -3116,9 +2567,15 @@
}
injectionState->refCount += 1;
- injectedEntry->injectionState = injectionState;
+ lastInjectedEntry->injectionState = injectionState;
- bool needWake = enqueueInboundEventLocked(injectedEntry);
+ bool needWake = false;
+ for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {
+ EventEntry* nextEntry = entry->next;
+ needWake |= enqueueInboundEventLocked(entry);
+ entry = nextEntry;
+ }
+
mLock.unlock();
if (needWake) {
@@ -3366,13 +2823,13 @@
if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
if (mFocusedApplicationHandle != inputApplicationHandle) {
if (mFocusedApplicationHandle != NULL) {
- resetTargetsLocked();
+ resetANRTimeoutsLocked();
mFocusedApplicationHandle->releaseInfo();
}
mFocusedApplicationHandle = inputApplicationHandle;
}
} else if (mFocusedApplicationHandle != NULL) {
- resetTargetsLocked();
+ resetANRTimeoutsLocked();
mFocusedApplicationHandle->releaseInfo();
mFocusedApplicationHandle.clear();
}
@@ -3495,8 +2952,8 @@
ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
- sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
- sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+ sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
+ sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3525,7 +2982,7 @@
resetKeyRepeatLocked();
releasePendingEventLocked();
drainInboundQueueLocked();
- resetTargetsLocked();
+ resetANRTimeoutsLocked();
mTouchState.reset();
mLastHoverWindowHandle.clear();
@@ -3622,20 +3079,6 @@
dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
- if (!mActiveConnections.isEmpty()) {
- dump.append(INDENT "ActiveConnections:\n");
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- const Connection* connection = mActiveConnections[i];
- dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u, "
- "inputState.isNeutral=%s\n",
- i, connection->getInputChannelName(), connection->getStatusLabel(),
- connection->outboundQueue.count(),
- toString(connection->inputState.isNeutral()));
- }
- } else {
- dump.append(INDENT "ActiveConnections: <none>\n");
- }
-
if (isAppSwitchPendingLocked()) {
dump.appendFormat(INDENT "AppSwitch: pending, due in %01.1fms\n",
(mAppSwitchDueTime - now()) / 1000000.0);
@@ -3661,21 +3104,15 @@
}
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
- status_t status = connection->initialize();
- if (status) {
- ALOGE("Failed to initialize input publisher for input channel '%s', status=%d",
- inputChannel->getName().string(), status);
- return status;
- }
- int32_t receiveFd = inputChannel->getReceivePipeFd();
- mConnectionsByReceiveFd.add(receiveFd, connection);
+ int fd = inputChannel->getFd();
+ mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
- mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+ mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
runCommandsLockedInterruptible();
} // release lock
@@ -3711,14 +3148,14 @@
return BAD_VALUE;
}
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ mConnectionsByFd.removeItemsAt(connectionIndex);
if (connection->monitor) {
removeMonitorChannelLocked(inputChannel);
}
- mLooper->removeFd(inputChannel->getReceivePipeFd());
+ mLooper->removeFd(inputChannel->getFd());
nsecs_t currentTime = now();
abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -3739,9 +3176,9 @@
}
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
- ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+ ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->inputChannel.get() == inputChannel.get()) {
return connectionIndex;
}
@@ -3750,33 +3187,12 @@
return -1;
}
-void InputDispatcher::activateConnectionLocked(Connection* connection) {
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- if (mActiveConnections.itemAt(i) == connection) {
- return;
- }
- }
- mActiveConnections.add(connection);
-}
-
-void InputDispatcher::deactivateConnectionLocked(Connection* connection) {
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- if (mActiveConnections.itemAt(i) == connection) {
- mActiveConnections.removeAt(i);
- return;
- }
- }
-}
-
-void InputDispatcher::onDispatchCycleStartedLocked(
- nsecs_t currentTime, const sp<Connection>& connection) {
-}
-
void InputDispatcher::onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection, bool handled) {
+ nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
+ commandEntry->seq = seq;
commandEntry->handled = handled;
}
@@ -3870,26 +3286,40 @@
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
+ uint32_t seq = commandEntry->seq;
bool handled = commandEntry->handled;
- bool skipNext = false;
- if (!connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (dispatchEntry->inProgress) {
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- skipNext = afterKeyEventLockedInterruptible(connection,
- dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- skipNext = afterMotionEventLockedInterruptible(connection,
- dispatchEntry, motionEntry, handled);
+ // Handle post-event policy actions.
+ DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
+ if (dispatchEntry) {
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterKeyEventLockedInterruptible(connection,
+ dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterMotionEventLockedInterruptible(connection,
+ dispatchEntry, motionEntry, handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Note that because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
+ connection->waitQueue.dequeue(dispatchEntry);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.enqueueAtHead(dispatchEntry);
+ } else {
+ releaseDispatchEntryLocked(dispatchEntry);
}
}
- }
- if (!skipNext) {
- startNextDispatchCycleLocked(now(), connection);
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
}
@@ -3953,11 +3383,9 @@
if (connection->status != Connection::STATUS_NORMAL) {
connection->inputState.removeFallbackKey(originalKeyCode);
- return true; // skip next cycle
+ return false;
}
- ALOG_ASSERT(connection->outboundQueue.head == dispatchEntry);
-
// Latch the fallback keycode for this key on an initial down.
// The fallback keycode cannot change at any other point in the lifecycle.
if (initialDown) {
@@ -4035,10 +3463,7 @@
"originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
originalKeyCode, fallbackKeyCode, keyEntry->metaState);
#endif
-
- dispatchEntry->inProgress = false;
- startDispatchCycleLocked(now(), connection);
- return true; // already started next cycle
+ return true; // restart the event
} else {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: No fallback key.");
@@ -4080,7 +3505,6 @@
dumpDispatchStateLocked(dump);
dump.append(INDENT "Configuration:\n");
- dump.appendFormat(INDENT2 "MaxEventsPerSecond: %d\n", mConfig.maxEventsPerSecond);
dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f);
dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f);
}
@@ -4204,17 +3628,6 @@
}
-// --- InputDispatcher::MotionSample ---
-
-InputDispatcher::MotionSample::MotionSample(nsecs_t eventTime,
- const PointerCoords* pointerCoords, uint32_t pointerCount) :
- next(NULL), eventTime(eventTime), eventTimeBeforeCoalescing(eventTime) {
- for (uint32_t i = 0; i < pointerCount; i++) {
- this->pointerCoords[i].copyFrom(pointerCoords[i]);
- }
-}
-
-
// --- InputDispatcher::MotionEntry ---
InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
@@ -4224,66 +3637,31 @@
nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) :
EventEntry(TYPE_MOTION, eventTime, policyFlags),
+ eventTime(eventTime),
deviceId(deviceId), source(source), action(action), flags(flags),
metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
xPrecision(xPrecision), yPrecision(yPrecision),
- downTime(downTime), pointerCount(pointerCount),
- firstSample(eventTime, pointerCoords, pointerCount),
- lastSample(&firstSample) {
+ downTime(downTime), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
+ this->pointerCoords[i].copyFrom(pointerCoords[i]);
}
}
InputDispatcher::MotionEntry::~MotionEntry() {
- for (MotionSample* sample = firstSample.next; sample != NULL; ) {
- MotionSample* next = sample->next;
- delete sample;
- sample = next;
- }
-}
-
-uint32_t InputDispatcher::MotionEntry::countSamples() const {
- uint32_t count = 1;
- for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) {
- count += 1;
- }
- return count;
-}
-
-bool InputDispatcher::MotionEntry::canAppendSamples(int32_t action, uint32_t pointerCount,
- const PointerProperties* pointerProperties) const {
- if (this->action != action
- || this->pointerCount != pointerCount
- || this->isInjected()) {
- return false;
- }
- for (uint32_t i = 0; i < pointerCount; i++) {
- if (this->pointerProperties[i] != pointerProperties[i]) {
- return false;
- }
- }
- return true;
-}
-
-void InputDispatcher::MotionEntry::appendSample(
- nsecs_t eventTime, const PointerCoords* pointerCoords) {
- MotionSample* sample = new MotionSample(eventTime, pointerCoords, pointerCount);
-
- lastSample->next = sample;
- lastSample = sample;
}
// --- InputDispatcher::DispatchEntry ---
+volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
+
InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
+ seq(nextSeq()),
eventEntry(eventEntry), targetFlags(targetFlags),
xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
- inProgress(false),
- resolvedAction(0), resolvedFlags(0),
- headMotionSample(NULL), tailMotionSample(NULL) {
+ resolvedAction(0), resolvedFlags(0) {
eventEntry->refCount += 1;
}
@@ -4291,6 +3669,15 @@
eventEntry->release();
}
+uint32_t InputDispatcher::DispatchEntry::nextSeq() {
+ // Sequence number 0 is reserved and will never be returned.
+ uint32_t seq;
+ do {
+ seq = android_atomic_inc(&sNextSeqAtomic);
+ } while (!seq);
+ return seq;
+}
+
// --- InputDispatcher::InputState ---
@@ -4501,7 +3888,7 @@
pointerCount = entry->pointerCount;
for (uint32_t i = 0; i < entry->pointerCount; i++) {
pointerProperties[i].copyFrom(entry->pointerProperties[i]);
- pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]);
+ pointerCoords[i].copyFrom(entry->pointerCoords[i]);
}
}
@@ -4621,17 +4008,12 @@
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
monitor(monitor),
- inputPublisher(inputChannel),
- lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
+ inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
InputDispatcher::Connection::~Connection() {
}
-status_t InputDispatcher::Connection::initialize() {
- return inputPublisher.initialize();
-}
-
const char* InputDispatcher::Connection::getStatusLabel() const {
switch (status) {
case STATUS_NORMAL:
@@ -4648,12 +4030,10 @@
}
}
-InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(
- const EventEntry* eventEntry) const {
- for (DispatchEntry* dispatchEntry = outboundQueue.tail; dispatchEntry;
- dispatchEntry = dispatchEntry->prev) {
- if (dispatchEntry->eventEntry == eventEntry) {
- return dispatchEntry;
+InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
+ for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) {
+ if (entry->seq == seq) {
+ return entry;
}
}
return NULL;
@@ -4663,7 +4043,8 @@
// --- InputDispatcher::CommandEntry ---
InputDispatcher::CommandEntry::CommandEntry(Command command) :
- command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), handled(false) {
+ command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0),
+ seq(0), handled(false) {
}
InputDispatcher::CommandEntry::~CommandEntry() {
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index a1d42e1..4b36480 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -17,8 +17,8 @@
#ifndef _UI_INPUT_DISPATCHER_H
#define _UI_INPUT_DISPATCHER_H
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/threads.h>
@@ -27,6 +27,7 @@
#include <utils/String8.h>
#include <utils/Looper.h>
#include <utils/BitSet.h>
+#include <cutils/atomic.h>
#include <stddef.h>
#include <unistd.h>
@@ -172,15 +173,9 @@
// The key repeat inter-key delay.
nsecs_t keyRepeatDelay;
- // The maximum suggested event delivery rate per second.
- // This value is used to throttle motion event movement actions on a per-device
- // basis. It is not intended to be a hard limit.
- int32_t maxEventsPerSecond;
-
InputDispatcherConfiguration() :
keyRepeatTimeout(500 * 1000000LL),
- keyRepeatDelay(50 * 1000000LL),
- maxEventsPerSecond(60) { }
+ keyRepeatDelay(50 * 1000000LL) { }
};
@@ -404,6 +399,9 @@
struct Link {
T* next;
T* prev;
+
+ protected:
+ inline Link() : next(NULL), prev(NULL) { }
};
struct InjectionState {
@@ -496,18 +494,8 @@
virtual ~KeyEntry();
};
- struct MotionSample {
- MotionSample* next;
-
- nsecs_t eventTime; // may be updated during coalescing
- nsecs_t eventTimeBeforeCoalescing; // not updated during coalescing
- PointerCoords pointerCoords[MAX_POINTERS];
-
- MotionSample(nsecs_t eventTime, const PointerCoords* pointerCoords,
- uint32_t pointerCount);
- };
-
struct MotionEntry : EventEntry {
+ nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
int32_t action;
@@ -520,10 +508,7 @@
nsecs_t downTime;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
-
- // Linked list of motion samples associated with this motion event.
- MotionSample firstSample;
- MotionSample* lastSample;
+ PointerCoords pointerCoords[MAX_POINTERS];
MotionEntry(nsecs_t eventTime,
int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
@@ -532,46 +517,24 @@
nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
- uint32_t countSamples() const;
-
- // Checks whether we can append samples, assuming the device id and source are the same.
- bool canAppendSamples(int32_t action, uint32_t pointerCount,
- const PointerProperties* pointerProperties) const;
-
- void appendSample(nsecs_t eventTime, const PointerCoords* pointerCoords);
-
protected:
virtual ~MotionEntry();
};
// Tracks the progress of dispatching a particular event to a particular connection.
struct DispatchEntry : Link<DispatchEntry> {
+ const uint32_t seq; // unique sequence number, never 0
+
EventEntry* eventEntry; // the event to dispatch
int32_t targetFlags;
float xOffset;
float yOffset;
float scaleFactor;
- // True if dispatch has started.
- bool inProgress;
-
// Set to the resolved action and flags when the event is enqueued.
int32_t resolvedAction;
int32_t resolvedFlags;
- // For motion events:
- // Pointer to the first motion sample to dispatch in this cycle.
- // Usually NULL to indicate that the list of motion samples begins at
- // MotionEntry::firstSample. Otherwise, some samples were dispatched in a previous
- // cycle and this pointer indicates the location of the first remainining sample
- // to dispatch during the current cycle.
- MotionSample* headMotionSample;
- // Pointer to a motion sample to dispatch in the next cycle if the dispatcher was
- // unable to send all motion samples during this cycle. On the next cycle,
- // headMotionSample will be initialized to tailMotionSample and tailMotionSample
- // will be set to NULL.
- MotionSample* tailMotionSample;
-
DispatchEntry(EventEntry* eventEntry,
int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
~DispatchEntry();
@@ -583,6 +546,11 @@
inline bool isSplit() const {
return targetFlags & InputTarget::FLAG_SPLIT;
}
+
+ private:
+ static volatile int32_t sNextSeqAtomic;
+
+ static uint32_t nextSeq();
};
// A command entry captures state and behavior for an action to be performed in the
@@ -618,6 +586,7 @@
sp<InputApplicationHandle> inputApplicationHandle;
sp<InputWindowHandle> inputWindowHandle;
int32_t userActivityEventType;
+ uint32_t seq;
bool handled;
};
@@ -819,10 +788,17 @@
bool monitor;
InputPublisher inputPublisher;
InputState inputState;
+
+ // True if the socket is full and no further events can be published until
+ // the application consumes some of the input.
+ bool inputPublisherBlocked;
+
+ // Queue of events that need to be published to the connection.
Queue<DispatchEntry> outboundQueue;
- nsecs_t lastEventTime; // the time when the event was originally captured
- nsecs_t lastDispatchTime; // the time when the last event was dispatched
+ // Queue of events that have been published to the connection but that have not
+ // yet received a "finished" response from the application.
+ Queue<DispatchEntry> waitQueue;
explicit Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
@@ -831,21 +807,7 @@
const char* getStatusLabel() const;
- // Finds a DispatchEntry in the outbound queue associated with the specified event.
- // Returns NULL if not found.
- DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const;
-
- // Gets the time since the current event was originally obtained from the input driver.
- inline double getEventLatencyMillis(nsecs_t currentTime) const {
- return (currentTime - lastEventTime) / 1000000.0;
- }
-
- // Gets the time since the current event entered the outbound dispatch queue.
- inline double getDispatchLatencyMillis(nsecs_t currentTime) const {
- return (currentTime - lastDispatchTime) / 1000000.0;
- }
-
- status_t initialize();
+ DispatchEntry* findWaitQueueEntry(uint32_t seq);
};
enum DropReason {
@@ -870,15 +832,7 @@
Queue<EventEntry> mInboundQueue;
Queue<CommandEntry> mCommandQueue;
- Vector<EventEntry*> mTempCancelationEvents;
-
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
- void dispatchIdleLocked();
-
- // Batches a new sample onto a motion entry.
- // Assumes that the we have already checked that we can append samples.
- void batchMotionLocked(MotionEntry* entry, nsecs_t eventTime, int32_t metaState,
- const PointerCoords* pointerCoords, const char* eventDescription);
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
@@ -904,17 +858,11 @@
sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
- // All registered connections mapped by receive pipe file descriptor.
- KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
+ // All registered connections mapped by channel file descriptor.
+ KeyedVector<int, sp<Connection> > mConnectionsByFd;
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
- // Active connections are connections that have a non-empty outbound queue.
- // We don't use a ref-counted pointer here because we explicitly abort connections
- // during unregistration which causes the connection's outbound queue to be cleared
- // and the connection itself to be deactivated.
- Vector<Connection*> mActiveConnections;
-
// Input channels that will receive a copy of all input events.
Vector<sp<InputChannel> > mMonitoringChannels;
@@ -927,17 +875,6 @@
void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
- // Throttling state.
- struct ThrottleState {
- nsecs_t minTimeBetweenEvents;
-
- nsecs_t lastEventTime;
- int32_t lastDeviceId;
- uint32_t lastSource;
-
- uint32_t originalSampleCount; // only collected during debugging
- } mThrottleState;
-
// Key repeat tracking.
struct KeyRepeatState {
KeyEntry* lastKeyEntry; // or null if no repeat
@@ -1010,16 +947,13 @@
bool dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime);
- void dispatchEventToCurrentInputTargetsLocked(
- nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
+ void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
+ const Vector<InputTarget>& inputTargets);
void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
- // The input targets that were most recently identified for dispatch.
- bool mCurrentInputTargetsValid; // false while targets are being recomputed
- Vector<InputTarget> mCurrentInputTargets;
-
+ // Keeping track of ANR timeouts.
enum InputTargetWaitCause {
INPUT_TARGET_WAIT_CAUSE_NONE,
INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY,
@@ -1036,8 +970,6 @@
sp<InputWindowHandle> mLastHoverWindowHandle;
// Finding targets for input events.
- void resetTargetsLocked();
- void commitTargetsLocked();
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -1048,20 +980,22 @@
void resetANRTimeoutsLocked();
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
- nsecs_t* nextWakeupTime);
+ Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
- nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
- const MotionSample** outSplitBatchAfterSample);
+ Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+ bool* outConflictingPointerActions);
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds);
- void addMonitoringTargetsLocked();
+ int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
+ void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets);
+
void pokeUserActivityLocked(const EventEntry* eventEntry);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState);
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
int32_t x, int32_t y) const;
- bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
+ bool isWindowReadyForMoreInputLocked(nsecs_t currentTime,
+ const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry);
String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle);
@@ -1070,22 +1004,19 @@
// with the mutex held makes it easier to ensure that connection invariants are maintained.
// If needed, the methods post commands to run later once the critical bits are done.
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample);
+ EventEntry* eventEntry, const InputTarget* inputTarget);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample);
+ EventEntry* eventEntry, const InputTarget* inputTarget);
void enqueueDispatchEntryLocked(const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample, int32_t dispatchMode);
+ EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- bool handled);
- void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ uint32_t seq, bool handled);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify);
- void drainOutboundQueueLocked(Connection* connection);
- static int handleReceiveCallback(int receiveFd, int events, void* data);
+ void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
+ void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
+ static int handleReceiveCallback(int fd, int events, void* data);
void synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options);
@@ -1113,10 +1044,8 @@
void deactivateConnectionLocked(Connection* connection);
// Interesting events that we might like to log or tell the framework about.
- void onDispatchCycleStartedLocked(
- nsecs_t currentTime, const sp<Connection>& connection);
void onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection, bool handled);
+ nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onANRLocked(
diff --git a/services/input/InputListener.h b/services/input/InputListener.h
index f920cd1..b1dc0b8 100644
--- a/services/input/InputListener.h
+++ b/services/input/InputListener.h
@@ -17,7 +17,7 @@
#ifndef _UI_INPUT_LISTENER_H
#define _UI_INPUT_LISTENER_H
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/services/input/InputManager.h b/services/input/InputManager.h
index df4d299e..29584c9 100644
--- a/services/input/InputManager.h
+++ b/services/input/InputManager.h
@@ -25,8 +25,8 @@
#include "InputReader.h"
#include "InputDispatcher.h"
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 4be06e4..eccce29 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -39,8 +39,8 @@
#include "InputReader.h"
#include <cutils/log.h>
-#include <ui/Keyboard.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/VirtualKeyMap.h>
#include <stddef.h>
#include <stdlib.h>
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index ad89a22..9bbe49c 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -21,7 +21,7 @@
#include "PointerController.h"
#include "InputListener.h"
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <ui/DisplayInfo.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 38968f9..824a64b 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -17,8 +17,8 @@
#ifndef _UI_INPUT_WINDOW_H
#define _UI_INPUT_WINDOW_H
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/String8.h>
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index 700ef72..39dbf6b 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -20,7 +20,7 @@
#include "SpriteController.h"
#include <ui/DisplayInfo.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
#include <utils/String8.h>
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 250386f..9c408c4 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -463,7 +463,7 @@
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
intent.setComponent(p.info.provider);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcast(intent, mUserId);
if (p.instances.size() == 0) {
// cancel the future updates
cancelBroadcasts(p);
@@ -471,7 +471,7 @@
// send the broacast saying that the provider is not in use any more
intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
intent.setComponent(p.info.provider);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcast(intent, mUserId);
}
}
}
@@ -515,8 +515,6 @@
+ " safe mode: " + provider);
}
- Binder.restoreCallingIdentity(ident);
-
id.provider = p;
p.instances.add(id);
int instancesSize = p.instances.size();
@@ -573,12 +571,13 @@
mBoundRemoteViewsServices.remove(key);
}
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the RemoteViewsService (which will trigger a callback to the
// RemoteViewsAdapter.onServiceConnected())
final long token = Binder.clearCallingIdentity();
try {
conn = new ServiceConnectionProxy(key, connection);
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
mBoundRemoteViewsServices.put(key, conn);
} finally {
Binder.restoreCallingIdentity(token);
@@ -638,11 +637,11 @@
// Check if we need to destroy any services (if no other app widgets are
// referencing the same service)
- decrementAppWidgetServiceRefCount(appWidgetId);
+ decrementAppWidgetServiceRefCount(id);
}
// Destroys the cached factory on the RemoteViewsService's side related to the specified intent
- private void destroyRemoteViewsService(final Intent intent) {
+ private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) {
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -663,11 +662,12 @@
}
};
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the service and remove the static intent->factory mapping in the
// RemoteViewsService.
final long token = Binder.clearCallingIdentity();
try {
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -687,16 +687,16 @@
// Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
// the ref-count reaches zero.
- private void decrementAppWidgetServiceRefCount(int appWidgetId) {
+ private void decrementAppWidgetServiceRefCount(AppWidgetId id) {
Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator();
while (it.hasNext()) {
final FilterComparison key = it.next();
final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
- if (ids.remove(appWidgetId)) {
+ if (ids.remove(id.appWidgetId)) {
// If we have removed the last app widget referencing this service, then we
// should destroy it and remove it from this set
if (ids.isEmpty()) {
- destroyRemoteViewsService(key.getIntent());
+ destroyRemoteViewsService(key.getIntent(), id);
it.remove();
}
}
@@ -888,10 +888,11 @@
}
};
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the service and call onDataSetChanged()
final long token = Binder.clearCallingIdentity();
try {
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1063,7 +1064,7 @@
void sendEnableIntentLocked(Provider p) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
intent.setComponent(p.info.provider);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcast(intent, mUserId);
}
void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
@@ -1071,7 +1072,7 @@
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
intent.setComponent(p.info.provider);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcast(intent, mUserId);
}
}
@@ -1343,7 +1344,6 @@
void readStateFromFileLocked(FileInputStream stream) {
boolean success = false;
-
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, null);
@@ -1475,12 +1475,11 @@
}
AtomicFile savedStateFile() {
- int userId = Binder.getOrigCallingUser();
- File dir = new File("/data/system/users/" + userId);
+ File dir = new File("/data/system/users/" + mUserId);
File settingsFile = new File(dir, SETTINGS_FILENAME);
if (!dir.exists()) {
dir.mkdirs();
- if (userId == 0) {
+ if (mUserId == 0) {
// Migrate old data
File oldFile = new File("/data/system/" + SETTINGS_FILENAME);
// Method doesn't throw an exception on failure. Ignore any errors
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java
new file mode 100644
index 0000000..9a25d2e
--- /dev/null
+++ b/services/java/com/android/server/CommonTimeManagementService.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.net.INetworkManagementEventObserver;
+import android.net.InterfaceConfiguration;
+import android.net.NetworkInfo;
+import android.os.Binder;
+import android.os.CommonTimeConfig;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
+
+/**
+ * @hide
+ * <p>CommonTimeManagementService manages the configuration of the native Common Time service,
+ * reconfiguring the native service as appropriate in response to changes in network configuration.
+ */
+class CommonTimeManagementService extends Binder {
+ /*
+ * Constants and globals.
+ */
+ private static final String TAG = CommonTimeManagementService.class.getSimpleName();
+ private static final int NATIVE_SERVICE_RECONNECT_TIMEOUT = 5000;
+ private static final String AUTO_DISABLE_PROP = "ro.common_time.auto_disable";
+ private static final String ALLOW_WIFI_PROP = "ro.common_time.allow_wifi";
+ private static final String SERVER_PRIO_PROP = "ro.common_time.server_prio";
+ private static final String NO_INTERFACE_TIMEOUT_PROP = "ro.common_time.no_iface_timeout";
+ private static final boolean AUTO_DISABLE;
+ private static final boolean ALLOW_WIFI;
+ private static final byte BASE_SERVER_PRIO;
+ private static final int NO_INTERFACE_TIMEOUT;
+ private static final InterfaceScoreRule[] IFACE_SCORE_RULES;
+
+ static {
+ int tmp;
+ AUTO_DISABLE = (0 != SystemProperties.getInt(AUTO_DISABLE_PROP, 1));
+ ALLOW_WIFI = (0 != SystemProperties.getInt(ALLOW_WIFI_PROP, 0));
+ tmp = SystemProperties.getInt(SERVER_PRIO_PROP, 1);
+ NO_INTERFACE_TIMEOUT = SystemProperties.getInt(NO_INTERFACE_TIMEOUT_PROP, 60000);
+
+ if (tmp < 1)
+ BASE_SERVER_PRIO = 1;
+ else
+ if (tmp > 30)
+ BASE_SERVER_PRIO = 30;
+ else
+ BASE_SERVER_PRIO = (byte)tmp;
+
+ if (ALLOW_WIFI) {
+ IFACE_SCORE_RULES = new InterfaceScoreRule[] {
+ new InterfaceScoreRule("wlan", (byte)1),
+ new InterfaceScoreRule("eth", (byte)2),
+ };
+ } else {
+ IFACE_SCORE_RULES = new InterfaceScoreRule[] {
+ new InterfaceScoreRule("eth", (byte)2),
+ };
+ }
+ };
+
+ /*
+ * Internal state
+ */
+ private final Context mContext;
+ private INetworkManagementService mNetMgr;
+ private CommonTimeConfig mCTConfig;
+ private String mCurIface;
+ private Handler mReconnectHandler = new Handler();
+ private Handler mNoInterfaceHandler = new Handler();
+ private Object mLock = new Object();
+ private boolean mDetectedAtStartup = false;
+ private byte mEffectivePrio = BASE_SERVER_PRIO;
+
+ /*
+ * Callback handler implementations.
+ */
+ private INetworkManagementEventObserver mIfaceObserver =
+ new INetworkManagementEventObserver.Stub() {
+
+ public void interfaceStatusChanged(String iface, boolean up) {
+ reevaluateServiceState();
+ }
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ reevaluateServiceState();
+ }
+ public void interfaceAdded(String iface) {
+ reevaluateServiceState();
+ }
+ public void interfaceRemoved(String iface) {
+ reevaluateServiceState();
+ }
+ public void limitReached(String limitName, String iface) { }
+ };
+
+ private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ reevaluateServiceState();
+ }
+ };
+
+ private CommonTimeConfig.OnServerDiedListener mCTServerDiedListener =
+ new CommonTimeConfig.OnServerDiedListener() {
+ public void onServerDied() {
+ scheduleTimeConfigReconnect();
+ }
+ };
+
+ private Runnable mReconnectRunnable = new Runnable() {
+ public void run() { connectToTimeConfig(); }
+ };
+
+ private Runnable mNoInterfaceRunnable = new Runnable() {
+ public void run() { handleNoInterfaceTimeout(); }
+ };
+
+ /*
+ * Public interface (constructor, systemReady and dump)
+ */
+ public CommonTimeManagementService(Context context) {
+ mContext = context;
+ }
+
+ void systemReady() {
+ if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) {
+ Log.i(TAG, "No common time service detected on this platform. " +
+ "Common time services will be unavailable.");
+ return;
+ }
+
+ mDetectedAtStartup = true;
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ mNetMgr = INetworkManagementService.Stub.asInterface(b);
+
+ // Network manager is running along-side us, so we should never receiver a remote exception
+ // while trying to register this observer.
+ try {
+ mNetMgr.registerObserver(mIfaceObserver);
+ }
+ catch (RemoteException e) { }
+
+ // Register with the connectivity manager for connectivity changed intents.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiver(mConnectivityMangerObserver, filter);
+
+ // Connect to the common time config service and apply the initial configuration.
+ connectToTimeConfig();
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println(String.format(
+ "Permission Denial: can't dump CommonTimeManagement service from from " +
+ "pid=%d, uid=%d", Binder.getCallingPid(), Binder.getCallingUid()));
+ return;
+ }
+
+ if (!mDetectedAtStartup) {
+ pw.println("Native Common Time service was not detected at startup. " +
+ "Service is unavailable");
+ return;
+ }
+
+ synchronized (mLock) {
+ pw.println("Current Common Time Management Service Config:");
+ pw.println(String.format(" Native service : %s",
+ (null == mCTConfig) ? "reconnecting"
+ : "alive"));
+ pw.println(String.format(" Bound interface : %s",
+ (null == mCurIface ? "unbound" : mCurIface)));
+ pw.println(String.format(" Allow WiFi : %s", ALLOW_WIFI ? "yes" : "no"));
+ pw.println(String.format(" Allow Auto Disable : %s", AUTO_DISABLE ? "yes" : "no"));
+ pw.println(String.format(" Server Priority : %d", mEffectivePrio));
+ pw.println(String.format(" No iface timeout : %d", NO_INTERFACE_TIMEOUT));
+ }
+ }
+
+ /*
+ * Inner helper classes
+ */
+ private static class InterfaceScoreRule {
+ public final String mPrefix;
+ public final byte mScore;
+ public InterfaceScoreRule(String prefix, byte score) {
+ mPrefix = prefix;
+ mScore = score;
+ }
+ };
+
+ /*
+ * Internal implementation
+ */
+ private void cleanupTimeConfig() {
+ mReconnectHandler.removeCallbacks(mReconnectRunnable);
+ mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
+ if (null != mCTConfig) {
+ mCTConfig.release();
+ mCTConfig = null;
+ }
+ }
+
+ private void connectToTimeConfig() {
+ // Get access to the common time service configuration interface. If we catch a remote
+ // exception in the process (service crashed or no running for w/e reason), schedule an
+ // attempt to reconnect in the future.
+ cleanupTimeConfig();
+ try {
+ synchronized (mLock) {
+ mCTConfig = new CommonTimeConfig();
+ mCTConfig.setServerDiedListener(mCTServerDiedListener);
+ mCurIface = mCTConfig.getInterfaceBinding();
+ mCTConfig.setAutoDisable(AUTO_DISABLE);
+ mCTConfig.setMasterElectionPriority(mEffectivePrio);
+ }
+
+ if (NO_INTERFACE_TIMEOUT >= 0)
+ mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
+
+ reevaluateServiceState();
+ }
+ catch (RemoteException e) {
+ scheduleTimeConfigReconnect();
+ }
+ }
+
+ private void scheduleTimeConfigReconnect() {
+ cleanupTimeConfig();
+ Log.w(TAG, String.format("Native service died, will reconnect in %d mSec",
+ NATIVE_SERVICE_RECONNECT_TIMEOUT));
+ mReconnectHandler.postDelayed(mReconnectRunnable,
+ NATIVE_SERVICE_RECONNECT_TIMEOUT);
+ }
+
+ private void handleNoInterfaceTimeout() {
+ if (null != mCTConfig) {
+ Log.i(TAG, "Timeout waiting for interface to come up. " +
+ "Forcing networkless master mode.");
+ if (CommonTimeConfig.ERROR_DEAD_OBJECT == mCTConfig.forceNetworklessMasterMode())
+ scheduleTimeConfigReconnect();
+ }
+ }
+
+ private void reevaluateServiceState() {
+ String bindIface = null;
+ byte bestScore = -1;
+ try {
+ // Check to see if this interface is suitable to use for time synchronization.
+ //
+ // TODO : This selection algorithm needs to be enhanced for use with mobile devices. In
+ // particular, the choice of whether to a wireless interface or not should not be an all
+ // or nothing thing controlled by properties. It would probably be better if the
+ // platform had some concept of public wireless networks vs. home or friendly wireless
+ // networks (something a user would configure in settings or when a new interface is
+ // added). Then this algorithm could pick only wireless interfaces which were flagged
+ // as friendly, and be dormant when on public wireless networks.
+ //
+ // Another issue which needs to be dealt with is the use of driver supplied interface
+ // name to determine the network type. The fact that the wireless interface on a device
+ // is named "wlan0" is just a matter of convention; its not a 100% rule. For example,
+ // there are devices out there where the wireless is name "tiwlan0", not "wlan0". The
+ // internal network management interfaces in Android have all of the information needed
+ // to make a proper classification, there is just no way (currently) to fetch an
+ // interface's type (available from the ConnectionManager) as well as its address
+ // (available from either the java.net interfaces or from the NetworkManagment service).
+ // Both can enumerate interfaces, but that is no way to correlate their results (no
+ // common shared key; although using the interface name in the connection manager would
+ // be a good start). Until this gets resolved, we resort to substring searching for
+ // tags like wlan and eth.
+ //
+ String ifaceList[] = mNetMgr.listInterfaces();
+ if (null != ifaceList) {
+ for (String iface : ifaceList) {
+
+ byte thisScore = -1;
+ for (InterfaceScoreRule r : IFACE_SCORE_RULES) {
+ if (iface.contains(r.mPrefix)) {
+ thisScore = r.mScore;
+ break;
+ }
+ }
+
+ if (thisScore <= bestScore)
+ continue;
+
+ InterfaceConfiguration config = mNetMgr.getInterfaceConfig(iface);
+ if (null == config)
+ continue;
+
+ if (config.isActive()) {
+ bindIface = iface;
+ bestScore = thisScore;
+ }
+ }
+ }
+ }
+ catch (RemoteException e) {
+ // Bad news; we should not be getting remote exceptions from the connectivity manager
+ // since it is running in SystemServer along side of us. It probably does not matter
+ // what we do here, but go ahead and unbind the common time service in this case, just
+ // so we have some defined behavior.
+ bindIface = null;
+ }
+
+ boolean doRebind = true;
+ synchronized (mLock) {
+ if ((null != bindIface) && (null == mCurIface)) {
+ Log.e(TAG, String.format("Binding common time service to %s.", bindIface));
+ mCurIface = bindIface;
+ } else
+ if ((null == bindIface) && (null != mCurIface)) {
+ Log.e(TAG, "Unbinding common time service.");
+ mCurIface = null;
+ } else
+ if ((null != bindIface) && (null != mCurIface) && !bindIface.equals(mCurIface)) {
+ Log.e(TAG, String.format("Switching common time service binding from %s to %s.",
+ mCurIface, bindIface));
+ mCurIface = bindIface;
+ } else {
+ doRebind = false;
+ }
+ }
+
+ if (doRebind && (null != mCTConfig)) {
+ byte newPrio = (bestScore > 0)
+ ? (byte)(bestScore * BASE_SERVER_PRIO)
+ : BASE_SERVER_PRIO;
+ if (newPrio != mEffectivePrio) {
+ mEffectivePrio = newPrio;
+ mCTConfig.setMasterElectionPriority(mEffectivePrio);
+ }
+
+ int res = mCTConfig.setNetworkBinding(mCurIface);
+ if (res != CommonTimeConfig.SUCCESS)
+ scheduleTimeConfigReconnect();
+
+ else if (NO_INTERFACE_TIMEOUT >= 0) {
+ mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
+ if (null == mCurIface)
+ mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index aba1bc6..86669f8 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -101,6 +101,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -154,6 +155,7 @@
final IWindowManager mIWindowManager;
final HandlerCaller mCaller;
private final InputMethodFileManager mFileManager;
+ private final InputMethodAndSubtypeListManager mImListManager;
final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
@@ -555,6 +557,7 @@
synchronized (mMethodMap) {
mFileManager = new InputMethodFileManager(mMethodMap);
}
+ mImListManager = new InputMethodAndSubtypeListManager(context, this);
(new MyPackageMonitor()).register(mContext, true);
@@ -1693,6 +1696,19 @@
}
@Override
+ public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
+ synchronized (mMethodMap) {
+ final ImeSubtypeListItem nextSubtype = mImListManager.getNextInputMethod(
+ onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+ if (nextSubtype == null) {
+ return false;
+ }
+ setInputMethodWithSubtypeId(token, nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+ return true;
+ }
+ }
+
+ @Override
public InputMethodSubtype getLastInputMethodSubtype() {
synchronized (mMethodMap) {
final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
@@ -2109,62 +2125,9 @@
hideInputMethodMenuLocked();
- final TreeMap<InputMethodInfo, List<InputMethodSubtype>> sortedImmis =
- new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
- new Comparator<InputMethodInfo>() {
- @Override
- public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
- if (imi2 == null) return 0;
- if (imi1 == null) return 1;
- if (pm == null) {
- return imi1.getId().compareTo(imi2.getId());
- }
- CharSequence imiId1 = imi1.loadLabel(pm) + "/" + imi1.getId();
- CharSequence imiId2 = imi2.loadLabel(pm) + "/" + imi2.getId();
- return imiId1.toString().compareTo(imiId2.toString());
- }
- });
-
- sortedImmis.putAll(immis);
-
- final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
-
- for (InputMethodInfo imi : sortedImmis.keySet()) {
- if (imi == null) continue;
- List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
- HashSet<String> enabledSubtypeSet = new HashSet<String>();
- for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
- enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
- }
- ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
- final CharSequence imeLabel = imi.loadLabel(pm);
- if (showSubtypes && enabledSubtypeSet.size() > 0) {
- final int subtypeCount = imi.getSubtypeCount();
- if (DEBUG) {
- Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
- }
- for (int j = 0; j < subtypeCount; ++j) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(j);
- final String subtypeHashCode = String.valueOf(subtype.hashCode());
- // We show all enabled IMEs and subtypes when an IME is shown.
- if (enabledSubtypeSet.contains(subtypeHashCode)
- && ((mInputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
- final CharSequence subtypeLabel =
- subtype.overridesImplicitlyEnabledSubtype() ? null
- : subtype.getDisplayName(context, imi.getPackageName(),
- imi.getServiceInfo().applicationInfo);
- imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
-
- // Removing this subtype from enabledSubtypeSet because we no longer
- // need to add an entry of this subtype to imList to avoid duplicated
- // entries.
- enabledSubtypeSet.remove(subtypeHashCode);
- }
- }
- } else {
- imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
- }
- }
+ final List<ImeSubtypeListItem> imList =
+ mImListManager.getSortedInputMethodAndSubtypeList(
+ showSubtypes, mInputShown, isScreenLocked);
if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtype();
@@ -2786,6 +2749,117 @@
}
}
+ private static class InputMethodAndSubtypeListManager {
+ private final Context mContext;
+ private final PackageManager mPm;
+ private final InputMethodManagerService mImms;
+ public InputMethodAndSubtypeListManager(Context context, InputMethodManagerService imms) {
+ mContext = context;
+ mPm = context.getPackageManager();
+ mImms = imms;
+ }
+
+ private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
+ new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
+ new Comparator<InputMethodInfo>() {
+ @Override
+ public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
+ if (imi2 == null) return 0;
+ if (imi1 == null) return 1;
+ if (mPm == null) {
+ return imi1.getId().compareTo(imi2.getId());
+ }
+ CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
+ CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
+ return imiId1.toString().compareTo(imiId2.toString());
+ }
+ });
+
+ public ImeSubtypeListItem getNextInputMethod(
+ boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
+ if (imi == null) {
+ return null;
+ }
+ final List<ImeSubtypeListItem> imList = getSortedInputMethodAndSubtypeList();
+ if (imList.size() <= 1) {
+ return null;
+ }
+ final int N = imList.size();
+ final int currentSubtypeId = subtype != null
+ ? mImms.getSubtypeIdFromHashCode(imi, subtype.hashCode())
+ : NOT_A_SUBTYPE_ID;
+ for (int i = 0; i < N; ++i) {
+ final ImeSubtypeListItem isli = imList.get(i);
+ if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
+ if (!onlyCurrentIme) {
+ return imList.get((i + 1) % N);
+ }
+ for (int j = 0; j < N - 1; ++j) {
+ final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
+ if (candidate.mImi.equals(imi)) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
+ return getSortedInputMethodAndSubtypeList(true, false, false);
+ }
+
+ public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(boolean showSubtypes,
+ boolean inputShown, boolean isScreenLocked) {
+ final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
+ final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
+ mImms.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
+ if (immis == null || immis.size() == 0) {
+ return Collections.emptyList();
+ }
+ mSortedImmis.clear();
+ mSortedImmis.putAll(immis);
+ for (InputMethodInfo imi : mSortedImmis.keySet()) {
+ if (imi == null) continue;
+ List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
+ HashSet<String> enabledSubtypeSet = new HashSet<String>();
+ for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
+ enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
+ }
+ ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
+ final CharSequence imeLabel = imi.loadLabel(mPm);
+ if (showSubtypes && enabledSubtypeSet.size() > 0) {
+ final int subtypeCount = imi.getSubtypeCount();
+ if (DEBUG) {
+ Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
+ }
+ for (int j = 0; j < subtypeCount; ++j) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(j);
+ final String subtypeHashCode = String.valueOf(subtype.hashCode());
+ // We show all enabled IMEs and subtypes when an IME is shown.
+ if (enabledSubtypeSet.contains(subtypeHashCode)
+ && ((inputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
+ final CharSequence subtypeLabel =
+ subtype.overridesImplicitlyEnabledSubtype() ? null
+ : subtype.getDisplayName(mContext, imi.getPackageName(),
+ imi.getServiceInfo().applicationInfo);
+ imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
+
+ // Removing this subtype from enabledSubtypeSet because we no longer
+ // need to add an entry of this subtype to imList to avoid duplicated
+ // entries.
+ enabledSubtypeSet.remove(subtypeHashCode);
+ }
+ }
+ } else {
+ imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
+ }
+ }
+ return imList;
+ }
+ }
+
/**
* Utility class for putting and getting settings for InputMethod
* TODO: Move all putters and getters of settings to this class.
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index a7d1992..1ff914f 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -55,7 +55,7 @@
private static final int EVENT_AUTO_TIME_CHANGED = 1;
private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_WIFI_CONNECTED = 3;
+ private static final int EVENT_NETWORK_CONNECTED = 3;
/** Normal polling frequency */
private static final long POLLING_INTERVAL_MS = 24L * 60 * 60 * 1000; // 24 hrs
@@ -240,8 +240,9 @@
if (netInfo != null) {
// Verify that it's a WIFI connection
if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
- netInfo.getType() == ConnectivityManager.TYPE_WIFI ) {
- mHandler.obtainMessage(EVENT_WIFI_CONNECTED).sendToTarget();
+ (netInfo.getType() == ConnectivityManager.TYPE_WIFI ||
+ netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) {
+ mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget();
}
}
}
@@ -260,7 +261,7 @@
switch (msg.what) {
case EVENT_AUTO_TIME_CHANGED:
case EVENT_POLL_NETWORK_TIME:
- case EVENT_WIFI_CONNECTED:
+ case EVENT_NETWORK_CONNECTED:
onPollNetworkTime(msg.what);
break;
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 34a8a02..b3eceb1 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -768,7 +768,9 @@
long identity = Binder.clearCallingIdentity();
try {
r.statusBarKey = mStatusBar.addNotification(n);
- mAttentionLight.pulse();
+ if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
+ mAttentionLight.pulse();
+ }
}
finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index bb0ac3e..7b4372f 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -50,6 +50,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
@@ -176,6 +177,7 @@
private boolean mDoneBooting = false;
private boolean mBootCompleted = false;
+ private boolean mHeadless = false;
private int mStayOnConditions = 0;
private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private final int[] mBroadcastWhy = new int[3];
@@ -530,6 +532,7 @@
mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+ mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
nativeInit();
synchronized (mLocks) {
@@ -580,6 +583,7 @@
}
nativeInit();
+ Power.powerInitNative();
synchronized (mLocks) {
updateNativePowerStateLocked();
// We make sure to start out with the screen on due to user activity.
@@ -1894,9 +1898,11 @@
}
private void updateNativePowerStateLocked() {
- nativeSetPowerState(
- (mPowerState & SCREEN_ON_BIT) != 0,
- (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+ if (!mHeadless) {
+ nativeSetPowerState(
+ (mPowerState & SCREEN_ON_BIT) != 0,
+ (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+ }
}
private int screenOffFinishedAnimatingLocked(int reason) {
@@ -2240,11 +2246,13 @@
mScreenOffHandler.postAtTime(this, now+(1000/60));
}
} else {
- // It's pretty scary to hold mLocks for this long, and we should
- // redesign this, but it works for now.
- nativeStartSurfaceFlingerAnimation(
- mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
- ? 0 : mAnimationSetting);
+ if (!mHeadless) {
+ // It's pretty scary to hold mLocks for this long, and we should
+ // redesign this, but it works for now.
+ nativeStartSurfaceFlingerAnimation(
+ mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
+ ? 0 : mAnimationSetting);
+ }
mScreenBrightness.jumpToTargetLocked();
}
}
diff --git a/services/java/com/android/server/SerialService.java b/services/java/com/android/server/SerialService.java
new file mode 100644
index 0000000..5d2b2a0
--- /dev/null
+++ b/services/java/com/android/server/SerialService.java
@@ -0,0 +1,58 @@
+/*
+ * 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 an
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.hardware.ISerialManager;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class SerialService extends ISerialManager.Stub {
+
+ private final Context mContext;
+ private final String[] mSerialPorts;
+
+ public SerialService(Context context) {
+ mContext = context;
+ mSerialPorts = context.getResources().getStringArray(
+ com.android.internal.R.array.config_serialPorts);
+ }
+
+ public String[] getSerialPorts() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
+
+ ArrayList<String> ports = new ArrayList<String>();
+ for (int i = 0; i < mSerialPorts.length; i++) {
+ String path = mSerialPorts[i];
+ if (new File(path).exists()) {
+ ports.add(path);
+ }
+ }
+ String[] result = new String[ports.size()];
+ ports.toArray(result);
+ return result;
+ }
+
+ public ParcelFileDescriptor openSerialPort(String path) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
+ return native_open(path);
+ }
+
+ private native ParcelFileDescriptor native_open(String path);
+}
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index da97089..a7a583c 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -44,12 +44,16 @@
private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper";
private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
- private static final String WALLPAPER_IMAGE_DIR = "/data/data/com.android.settings/files";
- private static final String WALLPAPER_IMAGE = WALLPAPER_IMAGE_DIR + "/" + WALLPAPER_IMAGE_FILENAME;
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String WALLPAPER_IMAGE_DIR = "/data/system/users/0";
+ private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
- private static final String WALLPAPER_INFO_DIR = "/data/system";
- private static final String WALLPAPER_INFO = WALLPAPER_INFO_DIR + "/" + WALLPAPER_INFO_FILENAME;
-
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String WALLPAPER_INFO_DIR = "/data/system/users/0";
+ private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
+ // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+ private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
+ private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY;
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
@@ -58,13 +62,15 @@
WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
Context.WALLPAPER_SERVICE);
String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
- if (wallpaper != null && wallpaper.mName != null && wallpaper.mName.length() > 0) {
+ String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
+ if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
// When the wallpaper has a name, back up the info by itself.
// TODO: Don't rely on the innards of the service object like this!
// TODO: Send a delete for any stored wallpaper image in this case?
files = new String[] { WALLPAPER_INFO };
+ keys = new String[] { WALLPAPER_INFO_KEY };
}
- addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files));
+ addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
super.onBackup(oldState, data, newState);
}
@@ -90,9 +96,11 @@
throws IOException {
// On restore, we also support a previous data schema "system_files"
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+ new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
+ new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE }));
+ new String[] { WALLPAPER_IMAGE },
+ new String[] { WALLPAPER_IMAGE_KEY} ));
try {
super.onRestore(data, appVersionCode, newState);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 762acbb..c9b5997 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,6 +108,7 @@
String factoryTestStr = SystemProperties.get("ro.factorytest");
int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
: Integer.parseInt(factoryTestStr);
+ final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
LightsService lights = null;
PowerManagerService power = null;
@@ -126,10 +127,12 @@
BluetoothA2dpService bluetoothA2dp = null;
DockObserver dock = null;
UsbService usb = null;
+ SerialService serial = null;
UiModeManagerService uiMode = null;
RecognitionManagerService recognition = null;
ThrottleService throttle = null;
NetworkTimeUpdateService networkTimeUpdater = null;
+ CommonTimeManagementService commonTimeMgmtService = null;
// Critical services...
try {
@@ -231,10 +234,13 @@
bluetooth = new BluetoothService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
bluetooth.initAfterRegistration();
- bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
- ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
- bluetoothA2dp);
- bluetooth.initAfterA2dpRegistration();
+
+ if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+ bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
+ ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
+ bluetoothA2dp);
+ bluetooth.initAfterA2dpRegistration();
+ }
int airplaneModeOn = Settings.System.getInt(mContentResolver,
Settings.System.AIRPLANE_MODE_ON, 0);
@@ -396,15 +402,17 @@
reportWtf("starting ThrottleService", e);
}
- try {
- /*
- * NotificationManagerService is dependant on MountService,
- * (for media / usb notifications) so we must start MountService first.
- */
- Slog.i(TAG, "Mount Service");
- ServiceManager.addService("mount", new MountService(context));
- } catch (Throwable e) {
- reportWtf("starting Mount Service", e);
+ if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+ try {
+ /*
+ * NotificationManagerService is dependant on MountService,
+ * (for media / usb notifications) so we must start MountService first.
+ */
+ Slog.i(TAG, "Mount Service");
+ ServiceManager.addService("mount", new MountService(context));
+ } catch (Throwable e) {
+ reportWtf("starting Mount Service", e);
+ }
}
try {
@@ -456,19 +464,26 @@
reportWtf("starting DropBoxManagerService", e);
}
- try {
- Slog.i(TAG, "Wallpaper Service");
- wallpaper = new WallpaperManagerService(context);
- ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
- } catch (Throwable e) {
- reportWtf("starting Wallpaper Service", e);
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableWallpaperService)) {
+ try {
+ Slog.i(TAG, "Wallpaper Service");
+ if (!headless) {
+ wallpaper = new WallpaperManagerService(context);
+ ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
+ }
+ } catch (Throwable e) {
+ reportWtf("starting Wallpaper Service", e);
+ }
}
- try {
- Slog.i(TAG, "Audio Service");
- ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
- } catch (Throwable e) {
- reportWtf("starting Audio Service", e);
+ if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+ try {
+ Slog.i(TAG, "Audio Service");
+ ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
+ } catch (Throwable e) {
+ reportWtf("starting Audio Service", e);
+ }
}
try {
@@ -497,6 +512,15 @@
}
try {
+ Slog.i(TAG, "Serial Service");
+ // Serial port support
+ serial = new SerialService(context);
+ ServiceManager.addService(Context.SERIAL_SERVICE, serial);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting SerialService", e);
+ }
+
+ try {
Slog.i(TAG, "UI Mode Manager Service");
// Listen for UI mode changes
uiMode = new UiModeManagerService(context);
@@ -552,6 +576,14 @@
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
}
+
+ try {
+ Slog.i(TAG, "CommonTimeManagementService");
+ commonTimeMgmtService = new CommonTimeManagementService(context);
+ ServiceManager.addService("commontime_management", commonTimeMgmtService);
+ } catch (Throwable e) {
+ reportWtf("starting CommonTimeManagementService service", e);
+ }
}
// Before things start rolling, be sure we have decided whether
@@ -630,6 +662,7 @@
final LocationManagerService locationF = location;
final CountryDetectorService countryDetectorF = countryDetector;
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
+ final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
final TextServicesManagerService textServiceManagerServiceF = tsms;
final StatusBarManagerService statusBarF = statusBar;
@@ -642,7 +675,7 @@
public void run() {
Slog.i(TAG, "Making services ready");
- startSystemUi(contextF);
+ if (!headless) startSystemUi(contextF);
try {
if (batteryF != null) batteryF.systemReady();
} catch (Throwable e) {
@@ -729,6 +762,11 @@
reportWtf("making Network Time Service ready", e);
}
try {
+ if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making Common time management service ready", e);
+ }
+ try {
if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
} catch (Throwable e) {
reportWtf("making Text Services Manager Service ready", e);
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4925a4e..8ee12bc 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -24,6 +24,7 @@
import android.app.PendingIntent;
import android.app.WallpaperInfo;
import android.app.backup.BackupManager;
+import android.app.backup.WallpaperBackupHelper;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -43,11 +44,13 @@
import android.os.RemoteCallbackList;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserId;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.service.wallpaper.WallpaperService;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
import android.view.IWindowManager;
@@ -70,6 +73,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.server.am.ActivityManagerService;
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
@@ -83,17 +87,9 @@
*/
static final long MIN_WALLPAPER_CRASH_TIME = 10000;
- static final File WALLPAPER_DIR = new File(
- "/data/data/com.android.settings/files");
+ static final File WALLPAPER_BASE_DIR = new File("/data/system/users");
static final String WALLPAPER = "wallpaper";
- static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
-
- /**
- * List of callbacks registered they should each be notified
- * when the wallpaper is changed.
- */
- private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
- = new RemoteCallbackList<IWallpaperManagerCallback>();
+ static final String WALLPAPER_INFO = "wallpaper_info.xml";
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
@@ -101,97 +97,135 @@
* wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
* everytime the wallpaper is changed.
*/
- private final FileObserver mWallpaperObserver = new FileObserver(
- WALLPAPER_DIR.getAbsolutePath(), CLOSE_WRITE | DELETE | DELETE_SELF) {
- @Override
- public void onEvent(int event, String path) {
- if (path == null) {
- return;
- }
- synchronized (mLock) {
- // changing the wallpaper means we'll need to back up the new one
- long origId = Binder.clearCallingIdentity();
- BackupManager bm = new BackupManager(mContext);
- bm.dataChanged();
- Binder.restoreCallingIdentity(origId);
+ private class WallpaperObserver extends FileObserver {
- File changedFile = new File(WALLPAPER_DIR, path);
- if (WALLPAPER_FILE.equals(changedFile)) {
- notifyCallbacksLocked();
- if (mWallpaperComponent == null || event != CLOSE_WRITE
- || mImageWallpaperPending) {
- if (event == CLOSE_WRITE) {
- mImageWallpaperPending = false;
- }
- bindWallpaperComponentLocked(mImageWallpaperComponent,
- true, false);
- saveSettingsLocked();
- }
+ final WallpaperData mWallpaper;
+ final File mWallpaperDir;
+ final File mWallpaperFile;
+
+ public WallpaperObserver(WallpaperData wallpaper) {
+ super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
+ CLOSE_WRITE | DELETE | DELETE_SELF);
+ mWallpaperDir = getWallpaperDir(wallpaper.userId);
+ mWallpaper = wallpaper;
+ mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+ }
+
+ @Override
+ public void onEvent(int event, String path) {
+ if (path == null) {
+ return;
+ }
+ synchronized (mLock) {
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ File changedFile = new File(mWallpaperDir, path);
+ if (mWallpaperFile.equals(changedFile)) {
+ notifyCallbacksLocked(mWallpaper);
+ if (mWallpaper.wallpaperComponent == null || event != CLOSE_WRITE
+ || mWallpaper.imageWallpaperPending) {
+ if (event == CLOSE_WRITE) {
+ mWallpaper.imageWallpaperPending = false;
}
+ bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+ false, mWallpaper);
+ saveSettingsLocked(mWallpaper);
}
}
- };
-
+ }
+ }
+ }
+
final Context mContext;
final IWindowManager mIWindowManager;
final MyPackageMonitor mMonitor;
+ WallpaperData mLastWallpaper;
- int mWidth = -1;
- int mHeight = -1;
+ SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
- /**
- * Client is currently writing a new image wallpaper.
- */
- boolean mImageWallpaperPending;
+ int mCurrentUserId;
- /**
- * Resource name if using a picture from the wallpaper gallery
- */
- String mName = "";
-
- /**
- * The component name of the currently set live wallpaper.
- */
- ComponentName mWallpaperComponent;
-
- /**
- * The component name of the wallpaper that should be set next.
- */
- ComponentName mNextWallpaperComponent;
-
- /**
- * Name of the component used to display bitmap wallpapers from either the gallery or
- * built-in wallpapers.
- */
- ComponentName mImageWallpaperComponent = new ComponentName("com.android.systemui",
- "com.android.systemui.ImageWallpaper");
-
- WallpaperConnection mWallpaperConnection;
- long mLastDiedTime;
- boolean mWallpaperUpdating;
-
+ static class WallpaperData {
+
+ int userId;
+
+ File wallpaperFile;
+
+ /**
+ * Client is currently writing a new image wallpaper.
+ */
+ boolean imageWallpaperPending;
+
+ /**
+ * Resource name if using a picture from the wallpaper gallery
+ */
+ String name = "";
+
+ /**
+ * The component name of the currently set live wallpaper.
+ */
+ ComponentName wallpaperComponent;
+
+ /**
+ * The component name of the wallpaper that should be set next.
+ */
+ ComponentName nextWallpaperComponent;
+
+ /**
+ * Name of the component used to display bitmap wallpapers from either the gallery or
+ * built-in wallpapers.
+ */
+ ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
+ "com.android.systemui.ImageWallpaper");
+
+ WallpaperConnection connection;
+ long lastDiedTime;
+ boolean wallpaperUpdating;
+ WallpaperObserver wallpaperObserver;
+
+ /**
+ * List of callbacks registered they should each be notified when the wallpaper is changed.
+ */
+ private RemoteCallbackList<IWallpaperManagerCallback> callbacks
+ = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+ int width = -1;
+ int height = -1;
+
+ WallpaperData(int userId) {
+ this.userId = userId;
+ wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+ }
+ }
+
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
final WallpaperInfo mInfo;
final Binder mToken = new Binder();
IWallpaperService mService;
IWallpaperEngine mEngine;
+ WallpaperData mWallpaper;
- public WallpaperConnection(WallpaperInfo info) {
+ public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
mInfo = info;
+ mWallpaper = wallpaper;
}
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
- if (mWallpaperConnection == this) {
- mLastDiedTime = SystemClock.uptimeMillis();
+ if (mWallpaper.connection == this) {
+ mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
mService = IWallpaperService.Stub.asInterface(service);
- attachServiceLocked(this);
+ attachServiceLocked(this, mWallpaper);
// XXX should probably do saveSettingsLocked() later
// when we have an engine, but I'm not sure about
// locking there and anyway we always need to be able to
// recover if there is something wrong.
- saveSettingsLocked();
+ saveSettingsLocked(mWallpaper);
}
}
}
@@ -200,43 +234,50 @@
synchronized (mLock) {
mService = null;
mEngine = null;
- if (mWallpaperConnection == this) {
- Slog.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
- if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
- > SystemClock.uptimeMillis()) {
+ if (mWallpaper.connection == this) {
+ Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
+ if (!mWallpaper.wallpaperUpdating
+ && (mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME)
+ > SystemClock.uptimeMillis()
+ && mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true);
+ clearWallpaperLocked(true, mWallpaper.userId);
}
}
}
}
-
+
public void attachEngine(IWallpaperEngine engine) {
mEngine = engine;
}
-
+
public ParcelFileDescriptor setWallpaper(String name) {
synchronized (mLock) {
- if (mWallpaperConnection == this) {
- return updateWallpaperBitmapLocked(name);
+ if (mWallpaper.connection == this) {
+ return updateWallpaperBitmapLocked(name, mWallpaper);
}
return null;
}
}
}
-
+
class MyPackageMonitor extends PackageMonitor {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- if (mWallpaperComponent != null &&
- mWallpaperComponent.getPackageName().equals(packageName)) {
- mWallpaperUpdating = false;
- ComponentName comp = mWallpaperComponent;
- clearWallpaperComponentLocked();
- if (!bindWallpaperComponentLocked(comp, false, false)) {
- Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false);
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent != null
+ && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ wallpaper.wallpaperUpdating = false;
+ ComponentName comp = wallpaper.wallpaperComponent;
+ clearWallpaperComponentLocked(wallpaper);
+ // Do this only for the current user's wallpaper
+ if (wallpaper.userId == mCurrentUserId
+ && !bindWallpaperComponentLocked(comp, false, false, wallpaper)) {
+ Slog.w(TAG, "Wallpaper no longer available; reverting to default");
+ clearWallpaperLocked(false, wallpaper.userId);
+ }
}
}
}
@@ -245,72 +286,91 @@
@Override
public void onPackageModified(String packageName) {
synchronized (mLock) {
- if (mWallpaperComponent == null ||
- !mWallpaperComponent.getPackageName().equals(packageName)) {
- return;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent == null
+ || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ continue;
+ }
+ doPackagesChanged(true, wallpaper);
}
}
- doPackagesChanged(true);
}
@Override
public void onPackageUpdateStarted(String packageName, int uid) {
synchronized (mLock) {
- if (mWallpaperComponent != null &&
- mWallpaperComponent.getPackageName().equals(packageName)) {
- mWallpaperUpdating = true;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent != null
+ && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ wallpaper.wallpaperUpdating = true;
+ }
}
}
}
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
- return doPackagesChanged(doit);
+ boolean changed = false;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ boolean res = doPackagesChanged(doit, wallpaper);
+ changed |= res;
+ }
+ return changed;
}
@Override
public void onSomePackagesChanged() {
- doPackagesChanged(true);
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ doPackagesChanged(true, wallpaper);
+ }
}
-
- boolean doPackagesChanged(boolean doit) {
+
+ boolean doPackagesChanged(boolean doit, WallpaperData wallpaper) {
boolean changed = false;
synchronized (mLock) {
- if (mWallpaperComponent != null) {
- int change = isPackageDisappearing(mWallpaperComponent.getPackageName());
+ if (wallpaper.wallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.wallpaperComponent
+ .getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
changed = true;
if (doit) {
- Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent);
- clearWallpaperLocked(false);
+ Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ + wallpaper.wallpaperComponent);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
}
- if (mNextWallpaperComponent != null) {
- int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName());
+ if (wallpaper.nextWallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
+ .getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
- mNextWallpaperComponent = null;
+ wallpaper.nextWallpaperComponent = null;
}
}
- if (mWallpaperComponent != null
- && isPackageModified(mWallpaperComponent.getPackageName())) {
+ if (wallpaper.wallpaperComponent != null
+ && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
try {
mContext.getPackageManager().getServiceInfo(
- mWallpaperComponent, 0);
+ wallpaper.wallpaperComponent, 0);
} catch (NameNotFoundException e) {
- Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent);
- clearWallpaperLocked(false);
+ Slog.w(TAG, "Wallpaper component gone, removing: "
+ + wallpaper.wallpaperComponent);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
- if (mNextWallpaperComponent != null
- && isPackageModified(mNextWallpaperComponent.getPackageName())) {
+ if (wallpaper.nextWallpaperComponent != null
+ && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
try {
mContext.getPackageManager().getServiceInfo(
- mNextWallpaperComponent, 0);
+ wallpaper.nextWallpaperComponent, 0);
} catch (NameNotFoundException e) {
- mNextWallpaperComponent = null;
+ wallpaper.nextWallpaperComponent = null;
}
}
}
@@ -325,51 +385,110 @@
ServiceManager.getService(Context.WINDOW_SERVICE));
mMonitor = new MyPackageMonitor();
mMonitor.register(context, true);
- WALLPAPER_DIR.mkdirs();
- loadSettingsLocked();
- mWallpaperObserver.startWatching();
+ WALLPAPER_BASE_DIR.mkdirs();
+ loadSettingsLocked(0);
}
+ private static File getWallpaperDir(int userId) {
+ return new File(WALLPAPER_BASE_DIR + "/" + userId);
+ }
+
@Override
protected void finalize() throws Throwable {
super.finalize();
- mWallpaperObserver.stopWatching();
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ wallpaper.wallpaperObserver.stopWatching();
+ }
}
public void systemReady() {
if (DEBUG) Slog.v(TAG, "systemReady");
+ WallpaperData wallpaper = mWallpaperMap.get(0);
+ switchWallpaper(wallpaper);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver.startWatching();
+ ActivityManagerService ams = (ActivityManagerService) ServiceManager
+ .getService(Context.ACTIVITY_SERVICE);
+ ams.addUserListener(new ActivityManagerService.UserListener() {
+
+ @Override
+ public void onUserChanged(int userId) {
+ switchUser(userId);
+ }
+
+ @Override
+ public void onUserAdded(int userId) {
+ }
+
+ @Override
+ public void onUserRemoved(int userId) {
+ }
+
+ @Override
+ public void onUserLoggedOut(int userId) {
+ }
+
+ });
+ }
+
+ String getName() {
+ return mWallpaperMap.get(0).name;
+ }
+
+ void switchUser(int userId) {
+ synchronized (mLock) {
+ mCurrentUserId = userId;
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ wallpaper = new WallpaperData(userId);
+ mWallpaperMap.put(userId, wallpaper);
+ loadSettingsLocked(userId);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver.startWatching();
+ }
+ switchWallpaper(wallpaper);
+ }
+ }
+
+ void switchWallpaper(WallpaperData wallpaper) {
synchronized (mLock) {
RuntimeException e = null;
try {
- if (bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+ ComponentName cname = wallpaper.wallpaperComponent != null ?
+ wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ if (bindWallpaperComponentLocked(cname, true, false, wallpaper)) {
return;
}
} catch (RuntimeException e1) {
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false);
- }
- }
-
- public void clearWallpaper() {
- if (DEBUG) Slog.v(TAG, "clearWallpaper");
- synchronized (mLock) {
- clearWallpaperLocked(false);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
- public void clearWallpaperLocked(boolean defaultFailed) {
- File f = WALLPAPER_FILE;
+ public void clearWallpaper() {
+ if (DEBUG) Slog.v(TAG, "clearWallpaper");
+ synchronized (mLock) {
+ clearWallpaperLocked(false, UserId.getCallingUserId());
+ }
+ }
+
+ void clearWallpaperLocked(boolean defaultFailed, int userId) {
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ File f = new File(getWallpaperDir(userId), WALLPAPER);
if (f.exists()) {
f.delete();
}
final long ident = Binder.clearCallingIdentity();
RuntimeException e = null;
try {
- mImageWallpaperPending = false;
+ wallpaper.imageWallpaperPending = false;
+ if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
- ? mImageWallpaperComponent : null, true, false)) {
+ ? wallpaper.imageWallpaperComponent
+ : null, true, false, wallpaper)) {
return;
}
} catch (IllegalArgumentException e1) {
@@ -383,29 +502,35 @@
// let's not let it crash the system and just live with no
// wallpaper.
Slog.e(TAG, "Default wallpaper component not found!", e);
- clearWallpaperComponentLocked();
+ clearWallpaperComponentLocked(wallpaper);
}
public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
synchronized (mLock) {
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
- saveSettingsLocked();
- if (mWallpaperConnection != null) {
- if (mWallpaperConnection.mEngine != null) {
+ if (width != wallpaper.width || height != wallpaper.height) {
+ wallpaper.width = width;
+ wallpaper.height = height;
+ saveSettingsLocked(wallpaper);
+ if (mCurrentUserId != userId) return; // Don't change the properties now
+ if (wallpaper.connection != null) {
+ if (wallpaper.connection.mEngine != null) {
try {
- mWallpaperConnection.mEngine.setDesiredSize(
+ wallpaper.connection.mEngine.setDesiredSize(
width, height);
} catch (RemoteException e) {
}
- notifyCallbacksLocked();
+ notifyCallbacksLocked(wallpaper);
}
}
}
@@ -414,26 +539,38 @@
public int getWidthHint() throws RemoteException {
synchronized (mLock) {
- return mWidth;
+ WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+ return wallpaper.width;
}
}
public int getHeightHint() throws RemoteException {
synchronized (mLock) {
- return mHeight;
+ WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+ return wallpaper.height;
}
}
public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
Bundle outParams) {
synchronized (mLock) {
+ // This returns the current user's wallpaper, if called by a system service. Else it
+ // returns the wallpaper for the calling user.
+ int callingUid = Binder.getCallingUid();
+ int wallpaperUserId = 0;
+ if (callingUid == android.os.Process.SYSTEM_UID) {
+ wallpaperUserId = mCurrentUserId;
+ } else {
+ wallpaperUserId = UserId.getUserId(callingUid);
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
try {
if (outParams != null) {
- outParams.putInt("width", mWidth);
- outParams.putInt("height", mHeight);
+ outParams.putInt("width", wallpaper.width);
+ outParams.putInt("height", wallpaper.height);
}
- mCallbacks.register(cb);
- File f = WALLPAPER_FILE;
+ wallpaper.callbacks.register(cb);
+ File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
if (!f.exists()) {
return null;
}
@@ -447,24 +584,30 @@
}
public WallpaperInfo getWallpaperInfo() {
+ int userId = UserId.getCallingUserId();
synchronized (mLock) {
- if (mWallpaperConnection != null) {
- return mWallpaperConnection.mInfo;
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper.connection != null) {
+ return wallpaper.connection.mInfo;
}
return null;
}
}
-
+
public ParcelFileDescriptor setWallpaper(String name) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
-
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
checkPermission(android.Manifest.permission.SET_WALLPAPER);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
try {
- ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
if (pfd != null) {
- mImageWallpaperPending = true;
+ wallpaper.imageWallpaperPending = true;
}
return pfd;
} finally {
@@ -473,19 +616,20 @@
}
}
- ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+ ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
if (name == null) name = "";
try {
- if (!WALLPAPER_DIR.exists()) {
- WALLPAPER_DIR.mkdir();
+ File dir = getWallpaperDir(wallpaper.userId);
+ if (!dir.exists()) {
+ dir.mkdir();
FileUtils.setPermissions(
- WALLPAPER_DIR.getPath(),
+ dir.getPath(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
MODE_CREATE|MODE_READ_WRITE);
- mName = name;
+ wallpaper.name = name;
return fd;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Error setting wallpaper", e);
@@ -495,31 +639,36 @@
public void setWallpaperComponent(ComponentName name) {
if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
try {
- mImageWallpaperPending = false;
- bindWallpaperComponentLocked(name, false, true);
+ wallpaper.imageWallpaperPending = false;
+ bindWallpaperComponentLocked(name, false, true, wallpaper);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser) {
+ boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
+ boolean fromUser, WallpaperData wallpaper) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
-
// Has the component changed?
if (!force) {
- if (mWallpaperConnection != null) {
- if (mWallpaperComponent == null) {
+ if (wallpaper.connection != null) {
+ if (wallpaper.wallpaperComponent == null) {
if (componentName == null) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
// Still using default wallpaper.
return true;
}
- } else if (mWallpaperComponent.equals(componentName)) {
+ } else if (wallpaper.wallpaperComponent.equals(componentName)) {
// Changing to same wallpaper.
if (DEBUG) Slog.v(TAG, "same wallpaper");
return true;
@@ -538,7 +687,7 @@
}
if (componentName == null) {
// Fall back to static image wallpaper
- componentName = mImageWallpaperComponent;
+ componentName = wallpaper.imageWallpaperComponent;
//clearWallpaperComponentLocked();
//return;
if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -560,7 +709,7 @@
WallpaperInfo wi = null;
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
- if (componentName != null && !componentName.equals(mImageWallpaperComponent)) {
+ if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
// Make sure the selected service is actually a wallpaper service.
List<ResolveInfo> ris = mContext.getPackageManager()
.queryIntentServices(intent, PackageManager.GET_META_DATA);
@@ -599,8 +748,13 @@
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
- WallpaperConnection newConn = new WallpaperConnection(wi);
+ WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
intent.setComponent(componentName);
+ int serviceUserId = wallpaper.userId;
+ // Because the image wallpaper is running in the system ui
+ if (componentName.equals(wallpaper.imageWallpaperComponent)) {
+ serviceUserId = 0;
+ }
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.wallpaper_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
@@ -608,8 +762,7 @@
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
0));
- if (!mContext.bindService(intent, newConn,
- Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE, serviceUserId)) {
String msg = "Unable to bind service: "
+ componentName;
if (fromUser) {
@@ -618,18 +771,22 @@
Slog.w(TAG, msg);
return false;
}
-
- clearWallpaperComponentLocked();
- mWallpaperComponent = componentName;
- mWallpaperConnection = newConn;
- mLastDiedTime = SystemClock.uptimeMillis();
+ if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
+ detachWallpaperLocked(mLastWallpaper);
+ }
+ wallpaper.wallpaperComponent = componentName;
+ wallpaper.connection = newConn;
+ wallpaper.lastDiedTime = SystemClock.uptimeMillis();
try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + newConn.mToken);
- mIWindowManager.addWindowToken(newConn.mToken,
- WindowManager.LayoutParams.TYPE_WALLPAPER);
+ if (wallpaper.userId == mCurrentUserId) {
+ if (DEBUG)
+ Slog.v(TAG, "Adding window token: " + newConn.mToken);
+ mIWindowManager.addWindowToken(newConn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER);
+ mLastWallpaper = wallpaper;
+ }
} catch (RemoteException e) {
}
-
} catch (PackageManager.NameNotFoundException e) {
String msg = "Unknown component " + componentName;
if (fromUser) {
@@ -640,54 +797,58 @@
}
return true;
}
-
- void clearWallpaperComponentLocked() {
- mWallpaperComponent = null;
- if (mWallpaperConnection != null) {
- if (mWallpaperConnection.mEngine != null) {
+
+ void detachWallpaperLocked(WallpaperData wallpaper) {
+ if (wallpaper.connection != null) {
+ if (wallpaper.connection.mEngine != null) {
try {
- mWallpaperConnection.mEngine.destroy();
+ wallpaper.connection.mEngine.destroy();
} catch (RemoteException e) {
}
}
- mContext.unbindService(mWallpaperConnection);
+ mContext.unbindService(wallpaper.connection);
try {
- if (DEBUG) Slog.v(TAG, "Removing window token: "
- + mWallpaperConnection.mToken);
- mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
+ if (DEBUG)
+ Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
+ mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
} catch (RemoteException e) {
}
- mWallpaperConnection.mService = null;
- mWallpaperConnection.mEngine = null;
- mWallpaperConnection = null;
+ wallpaper.connection.mService = null;
+ wallpaper.connection.mEngine = null;
+ wallpaper.connection = null;
}
}
-
- void attachServiceLocked(WallpaperConnection conn) {
+
+ void clearWallpaperComponentLocked(WallpaperData wallpaper) {
+ wallpaper.wallpaperComponent = null;
+ detachWallpaperLocked(wallpaper);
+ }
+
+ void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
try {
conn.mService.attach(conn, conn.mToken,
WindowManager.LayoutParams.TYPE_WALLPAPER, false,
- mWidth, mHeight);
+ wallpaper.width, wallpaper.height);
} catch (RemoteException e) {
Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
- if (!mWallpaperUpdating) {
- bindWallpaperComponentLocked(null, false, false);
+ if (!wallpaper.wallpaperUpdating) {
+ bindWallpaperComponentLocked(null, false, false, wallpaper);
}
}
}
-
- private void notifyCallbacksLocked() {
- final int n = mCallbacks.beginBroadcast();
+
+ private void notifyCallbacksLocked(WallpaperData wallpaper) {
+ final int n = wallpaper.callbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
- mCallbacks.getBroadcastItem(i).onWallpaperChanged();
+ wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
- mCallbacks.finishBroadcast();
+ wallpaper.callbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
mContext.sendBroadcast(intent);
}
@@ -699,13 +860,13 @@
}
}
- private static JournaledFile makeJournaledFile() {
- final String base = "/data/system/wallpaper_info.xml";
+ private static JournaledFile makeJournaledFile(int userId) {
+ final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
- private void saveSettingsLocked() {
- JournaledFile journal = makeJournaledFile();
+ private void saveSettingsLocked(WallpaperData wallpaper) {
+ JournaledFile journal = makeJournaledFile(wallpaper.userId);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(journal.chooseForWrite(), false);
@@ -714,13 +875,13 @@
out.startDocument(null, true);
out.startTag(null, "wp");
- out.attribute(null, "width", Integer.toString(mWidth));
- out.attribute(null, "height", Integer.toString(mHeight));
- out.attribute(null, "name", mName);
- if (mWallpaperComponent != null &&
- !mWallpaperComponent.equals(mImageWallpaperComponent)) {
+ out.attribute(null, "width", Integer.toString(wallpaper.width));
+ out.attribute(null, "height", Integer.toString(wallpaper.height));
+ out.attribute(null, "name", wallpaper.name);
+ if (wallpaper.wallpaperComponent != null
+ && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
out.attribute(null, "component",
- mWallpaperComponent.flattenToShortString());
+ wallpaper.wallpaperComponent.flattenToShortString());
}
out.endTag(null, "wp");
@@ -739,12 +900,34 @@
}
}
- private void loadSettingsLocked() {
+ private void migrateFromOld() {
+ File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
+ File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
+ if (oldWallpaper.exists()) {
+ File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
+ oldWallpaper.renameTo(newWallpaper);
+ }
+ if (oldInfo.exists()) {
+ File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
+ oldInfo.renameTo(newInfo);
+ }
+ }
+
+ private void loadSettingsLocked(int userId) {
if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
- JournaledFile journal = makeJournaledFile();
+ JournaledFile journal = makeJournaledFile(userId);
FileInputStream stream = null;
File file = journal.chooseForRead();
+ if (!file.exists()) {
+ // This should only happen one time, when upgrading from a legacy system
+ migrateFromOld();
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ wallpaper = new WallpaperData(userId);
+ mWallpaperMap.put(userId, wallpaper);
+ }
boolean success = false;
try {
stream = new FileInputStream(file);
@@ -757,23 +940,26 @@
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
if ("wp".equals(tag)) {
- mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
- mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
- mName = parser.getAttributeValue(null, "name");
+ wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ wallpaper.name = parser.getAttributeValue(null, "name");
String comp = parser.getAttributeValue(null, "component");
- mNextWallpaperComponent = comp != null
+ wallpaper.nextWallpaperComponent = comp != null
? ComponentName.unflattenFromString(comp)
: null;
- if (mNextWallpaperComponent == null ||
- "android".equals(mNextWallpaperComponent.getPackageName())) {
- mNextWallpaperComponent = mImageWallpaperComponent;
+ if (wallpaper.nextWallpaperComponent == null
+ || "android".equals(wallpaper.nextWallpaperComponent
+ .getPackageName())) {
+ wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
}
if (DEBUG) {
- Slog.v(TAG, "mWidth:" + mWidth);
- Slog.v(TAG, "mHeight:" + mHeight);
- Slog.v(TAG, "mName:" + mName);
- Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
+ Slog.v(TAG, "mWidth:" + wallpaper.width);
+ Slog.v(TAG, "mHeight:" + wallpaper.height);
+ Slog.v(TAG, "mName:" + wallpaper.name);
+ Slog.v(TAG, "mNextWallpaperComponent:"
+ + wallpaper.nextWallpaperComponent);
}
}
}
@@ -799,70 +985,75 @@
}
if (!success) {
- mWidth = -1;
- mHeight = -1;
- mName = "";
+ wallpaper.width = -1;
+ wallpaper.height = -1;
+ wallpaper.name = "";
}
// We always want to have some reasonable width hint.
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
int baseSize = d.getMaximumSizeDimension();
- if (mWidth < baseSize) {
- mWidth = baseSize;
+ if (wallpaper.width < baseSize) {
+ wallpaper.width = baseSize;
}
- if (mHeight < baseSize) {
- mHeight = baseSize;
+ if (wallpaper.height < baseSize) {
+ wallpaper.height = baseSize;
}
}
// Called by SystemBackupAgent after files are restored to disk.
void settingsRestored() {
+ // TODO: If necessary, make it work for secondary users as well. This currently assumes
+ // restores only to the primary user
if (DEBUG) Slog.v(TAG, "settingsRestored");
-
+ WallpaperData wallpaper = null;
boolean success = false;
synchronized (mLock) {
- loadSettingsLocked();
- if (mNextWallpaperComponent != null &&
- !mNextWallpaperComponent.equals(mImageWallpaperComponent)) {
- if (!bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+ loadSettingsLocked(0);
+ wallpaper = mWallpaperMap.get(0);
+ if (wallpaper.nextWallpaperComponent != null
+ && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ wallpaper)) {
// No such live wallpaper or other failure; fall back to the default
// live wallpaper (since the profile being restored indicated that the
// user had selected a live rather than static one).
- bindWallpaperComponentLocked(null, false, false);
+ bindWallpaperComponentLocked(null, false, false, wallpaper);
}
success = true;
} else {
// If there's a wallpaper name, we use that. If that can't be loaded, then we
// use the default.
- if ("".equals(mName)) {
+ if ("".equals(wallpaper.name)) {
if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
success = true;
} else {
if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
- success = restoreNamedResourceLocked();
+ success = restoreNamedResourceLocked(wallpaper);
}
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
if (success) {
- bindWallpaperComponentLocked(mNextWallpaperComponent, false, false);
+ bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ wallpaper);
}
}
}
if (!success) {
- Slog.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
- mName = "";
- WALLPAPER_FILE.delete();
+ Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
+ wallpaper.name = "";
+ getWallpaperDir(0).delete();
}
synchronized (mLock) {
- saveSettingsLocked();
+ saveSettingsLocked(wallpaper);
}
}
- boolean restoreNamedResourceLocked() {
- if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
- String resName = mName.substring(4);
+ boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
+ if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
+ String resName = wallpaper.name.substring(4);
String pkg = null;
int colon = resName.indexOf(':');
@@ -896,10 +1087,10 @@
}
res = r.openRawResource(resId);
- if (WALLPAPER_FILE.exists()) {
- WALLPAPER_FILE.delete();
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
}
- fos = new FileOutputStream(WALLPAPER_FILE);
+ fos = new FileOutputStream(wallpaper.wallpaperFile);
byte[] buffer = new byte[32768];
int amt;
@@ -933,7 +1124,7 @@
}
return false;
}
-
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -947,20 +1138,35 @@
synchronized (mLock) {
pw.println("Current Wallpaper Service state:");
- pw.print(" mWidth="); pw.print(mWidth);
- pw.print(" mHeight="); pw.println(mHeight);
- pw.print(" mName="); pw.println(mName);
- pw.print(" mWallpaperComponent="); pw.println(mWallpaperComponent);
- if (mWallpaperConnection != null) {
- WallpaperConnection conn = mWallpaperConnection;
- pw.print(" Wallpaper connection ");
- pw.print(conn); pw.println(":");
- pw.print(" mInfo.component="); pw.println(conn.mInfo.getComponent());
- pw.print(" mToken="); pw.println(conn.mToken);
- pw.print(" mService="); pw.println(conn.mService);
- pw.print(" mEngine="); pw.println(conn.mEngine);
- pw.print(" mLastDiedTime=");
- pw.println(mLastDiedTime - SystemClock.uptimeMillis());
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ pw.println(" User " + wallpaper.userId + ":");
+ pw.print(" mWidth=");
+ pw.print(wallpaper.width);
+ pw.print(" mHeight=");
+ pw.println(wallpaper.height);
+ pw.print(" mName=");
+ pw.println(wallpaper.name);
+ pw.print(" mWallpaperComponent=");
+ pw.println(wallpaper.wallpaperComponent);
+ if (wallpaper.connection != null) {
+ WallpaperConnection conn = wallpaper.connection;
+ pw.print(" Wallpaper connection ");
+ pw.print(conn);
+ pw.println(":");
+ if (conn.mInfo != null) {
+ pw.print(" mInfo.component=");
+ pw.println(conn.mInfo.getComponent());
+ }
+ pw.print(" mToken=");
+ pw.println(conn.mToken);
+ pw.print(" mService=");
+ pw.println(conn.mService);
+ pw.print(" mEngine=");
+ pw.println(conn.mEngine);
+ pw.print(" mLastDiedTime=");
+ pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
+ }
}
}
}
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 6a63eac..326b940 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -191,8 +191,12 @@
mHeadsetState = headsetState;
if (headsetState == 0) {
- Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_sendAudioBecomingNoisy)) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
+
// It can take hundreds of ms flush the audio pipeline after
// apps pause audio playback, but audio route changes are
// immediate, so delay the route change by 1000ms.
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8bda755..586a67e 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -143,6 +143,8 @@
private final SecurityPolicy mSecurityPolicy;
+ private Service mUiAutomationService;
+
/**
* Handler for delayed event dispatch.
*/
@@ -494,19 +496,15 @@
}
}
// Hook the automation service up.
- Service service = new Service(componentName, accessibilityServiceInfo, true);
- service.onServiceConnected(componentName, listener.asBinder());
+ mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true);
+ mUiAutomationService.onServiceConnected(componentName, listener.asBinder());
}
public void unregisterUiTestAutomationService(IEventListener listener) {
synchronized (mLock) {
- final int serviceCount = mServices.size();
- for (int i = 0; i < serviceCount; i++) {
- Service service = mServices.get(i);
- if (service.mServiceInterface == listener && service.mIsAutomation) {
- // Automation service is not bound, so pretend it died to perform clean up.
- service.binderDied();
- }
+ // Automation service is not bound, so pretend it died to perform clean up.
+ if (mUiAutomationService != null) {
+ mUiAutomationService.binderDied();
}
}
}
@@ -741,7 +739,10 @@
* Manages services by starting enabled ones and stopping disabled ones.
*/
private void manageServicesLocked() {
- unbindAutomationService();
+ // While the UI automation service is running it takes over.
+ if (mUiAutomationService != null) {
+ return;
+ }
populateEnabledServicesLocked(mEnabledServices);
final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
mEnabledServices);
@@ -769,21 +770,6 @@
}
/**
- * Unbinds the automation service if such is running.
- */
- private void unbindAutomationService() {
- List<Service> runningServices = mServices;
- int runningServiceCount = mServices.size();
- for (int i = 0; i < runningServiceCount; i++) {
- Service service = runningServices.get(i);
- if (service.mIsAutomation) {
- service.unbind();
- return;
- }
- }
- }
-
- /**
* Populates a list with the {@link ComponentName}s of all enabled
* {@link AccessibilityService}s.
*
@@ -1248,6 +1234,7 @@
// We no longer have an automation service, so restore
// the state based on values in the settings database.
if (mIsAutomation) {
+ mUiAutomationService = null;
handleAccessibilityEnabledSettingChangedLocked();
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 10a0efe..8a5e7fc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -38,7 +38,6 @@
import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IActivityController;
-import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.INotificationManager;
@@ -50,6 +49,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.WallpaperManager;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -138,7 +138,6 @@
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -269,7 +268,14 @@
static final String[] EMPTY_STRING_ARRAY = new String[0];
public ActivityStack mMainStack;
-
+
+ private final boolean mHeadless;
+
+ // Whether we should show our dialogs (ANR, crash, etc) or just perform their
+ // default actuion automatically. Important for devices without direct input
+ // devices.
+ private boolean mShowDialogs = true;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -285,813 +291,12 @@
final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
= new ArrayList<PendingActivityLaunch>();
- /**
- * BROADCASTS
- *
- * We keep two broadcast queues and associated bookkeeping, one for those at
- * foreground priority, and one for normal (background-priority) broadcasts.
- */
- public class BroadcastQueue {
- static final String TAG = "BroadcastQueue";
- static final int MAX_BROADCAST_HISTORY = 25;
-
- /**
- * Recognizable moniker for this queue
- */
- String mQueueName;
-
- /**
- * Timeout period for this queue's broadcasts
- */
- long mTimeoutPeriod;
-
- /**
- * Lists of all active broadcasts that are to be executed immediately
- * (without waiting for another broadcast to finish). Currently this only
- * contains broadcasts to registered receivers, to avoid spinning up
- * a bunch of processes to execute IntentReceiver components. Background-
- * and foreground-priority broadcasts are queued separately.
- */
- final ArrayList<BroadcastRecord> mParallelBroadcasts
- = new ArrayList<BroadcastRecord>();
- /**
- * List of all active broadcasts that are to be executed one at a time.
- * The object at the top of the list is the currently activity broadcasts;
- * those after it are waiting for the top to finish. As with parallel
- * broadcasts, separate background- and foreground-priority queues are
- * maintained.
- */
- final ArrayList<BroadcastRecord> mOrderedBroadcasts
- = new ArrayList<BroadcastRecord>();
-
- /**
- * Historical data of past broadcasts, for debugging.
- */
- final BroadcastRecord[] mBroadcastHistory
- = new BroadcastRecord[MAX_BROADCAST_HISTORY];
-
- /**
- * Set when we current have a BROADCAST_INTENT_MSG in flight.
- */
- boolean mBroadcastsScheduled = false;
-
- /**
- * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
- */
- boolean mPendingBroadcastTimeoutMessage;
-
- /**
- * Intent broadcasts that we have tried to start, but are
- * waiting for the application's process to be created. We only
- * need one per scheduling class (instead of a list) because we always
- * process broadcasts one at a time, so no others can be started while
- * waiting for this one.
- */
- BroadcastRecord mPendingBroadcast = null;
-
- /**
- * The receiver index that is pending, to restart the broadcast if needed.
- */
- int mPendingBroadcastRecvIndex;
-
- BroadcastQueue(String name, long timeoutPeriod) {
- mQueueName = name;
- mTimeoutPeriod = timeoutPeriod;
- }
-
- public boolean isPendingBroadcastProcessLocked(int pid) {
- return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
- }
-
- public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
- mParallelBroadcasts.add(r);
- }
-
- public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
- mOrderedBroadcasts.add(r);
- }
-
- public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
- if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "***** DROPPING PARALLEL ["
- + mQueueName + "]: " + r.intent);
- mParallelBroadcasts.set(i, r);
- return true;
- }
- }
- return false;
- }
-
- public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
- for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
- if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "***** DROPPING ORDERED ["
- + mQueueName + "]: " + r.intent);
- mOrderedBroadcasts.set(i, r);
- return true;
- }
- }
- return false;
- }
-
- public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
- boolean didSomething = false;
- final BroadcastRecord br = mPendingBroadcast;
- if (br != null && br.curApp.pid == app.pid) {
- try {
- mPendingBroadcast = null;
- processCurBroadcastLocked(br, app);
- didSomething = true;
- } catch (Exception e) {
- Slog.w(TAG, "Exception in new application when starting receiver "
- + br.curComponent.flattenToShortString(), e);
- logBroadcastReceiverDiscardLocked(br);
- finishReceiverLocked(br, br.resultCode, br.resultData,
- br.resultExtras, br.resultAbort, true);
- scheduleBroadcastsLocked();
- // We need to reset the state if we fails to start the receiver.
- br.state = BroadcastRecord.IDLE;
- throw new RuntimeException(e.getMessage());
- }
- }
- return didSomething;
- }
-
- public void skipPendingBroadcastLocked(int pid) {
- final BroadcastRecord br = mPendingBroadcast;
- if (br != null && br.curApp.pid == pid) {
- br.state = BroadcastRecord.IDLE;
- br.nextReceiver = mPendingBroadcastRecvIndex;
- mPendingBroadcast = null;
- scheduleBroadcastsLocked();
- }
- }
-
- public void skipCurrentReceiverLocked(ProcessRecord app) {
- boolean reschedule = false;
- BroadcastRecord r = app.curReceiver;
- if (r != null) {
- // The current broadcast is waiting for this app's receiver
- // to be finished. Looks like that's not going to happen, so
- // let the broadcast continue.
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- reschedule = true;
- }
-
- r = mPendingBroadcast;
- if (r != null && r.curApp == app) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "[" + mQueueName + "] skip & discard pending app " + r);
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- reschedule = true;
- }
- if (reschedule) {
- scheduleBroadcastsLocked();
- }
- }
-
- public void scheduleBroadcastsLocked() {
- if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
- + mQueueName + "]: current="
- + mBroadcastsScheduled);
-
- if (mBroadcastsScheduled) {
- return;
- }
- mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
- mBroadcastsScheduled = true;
- }
-
- public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
- if (mOrderedBroadcasts.size() > 0) {
- final BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (r != null && r.receiver == receiver) {
- return r;
- }
- }
- return null;
- }
-
- public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
- String resultData, Bundle resultExtras, boolean resultAbort,
- boolean explicit) {
- int state = r.state;
- r.state = BroadcastRecord.IDLE;
- if (state == BroadcastRecord.IDLE) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
- }
- }
- r.receiver = null;
- r.intent.setComponent(null);
- if (r.curApp != null) {
- r.curApp.curReceiver = null;
- }
- if (r.curFilter != null) {
- r.curFilter.receiverList.curBroadcast = null;
- }
- r.curFilter = null;
- r.curApp = null;
- r.curComponent = null;
- r.curReceiver = null;
- mPendingBroadcast = null;
-
- r.resultCode = resultCode;
- r.resultData = resultData;
- r.resultExtras = resultExtras;
- r.resultAbort = resultAbort;
-
- // We will process the next receiver right now if this is finishing
- // an app receiver (which is always asynchronous) or after we have
- // come back from calling a receiver.
- return state == BroadcastRecord.APP_RECEIVE
- || state == BroadcastRecord.CALL_DONE_RECEIVE;
- }
-
- private final void processNextBroadcast(boolean fromMsg) {
- synchronized(ActivityManagerService.this) {
- BroadcastRecord r;
-
- if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
- + mQueueName + "]: "
- + mParallelBroadcasts.size() + " broadcasts, "
- + mOrderedBroadcasts.size() + " ordered broadcasts");
-
- updateCpuStats();
-
- if (fromMsg) {
- mBroadcastsScheduled = false;
- }
-
- // First, deliver any non-serialized broadcasts right away.
- while (mParallelBroadcasts.size() > 0) {
- r = mParallelBroadcasts.remove(0);
- r.dispatchTime = SystemClock.uptimeMillis();
- r.dispatchClockTime = System.currentTimeMillis();
- final int N = r.receivers.size();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
- + mQueueName + "] " + r);
- for (int i=0; i<N; i++) {
- Object target = r.receivers.get(i);
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Delivering non-ordered on [" + mQueueName + "] to registered "
- + target + ": " + r);
- deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
- }
- addBroadcastToHistoryLocked(r);
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
- + mQueueName + "] " + r);
- }
-
- // Now take care of the next serialized one...
-
- // If we are waiting for a process to come up to handle the next
- // broadcast, then do nothing at this point. Just in case, we
- // check that the process we're waiting for still exists.
- if (mPendingBroadcast != null) {
- if (DEBUG_BROADCAST_LIGHT) {
- Slog.v(TAG, "processNextBroadcast ["
- + mQueueName + "]: waiting for "
- + mPendingBroadcast.curApp);
- }
-
- boolean isDead;
- synchronized (mPidsSelfLocked) {
- isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
- }
- if (!isDead) {
- // It's still alive, so keep waiting
- return;
- } else {
- Slog.w(TAG, "pending app ["
- + mQueueName + "]" + mPendingBroadcast.curApp
- + " died before responding to broadcast");
- mPendingBroadcast.state = BroadcastRecord.IDLE;
- mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
- mPendingBroadcast = null;
- }
- }
-
- boolean looped = false;
-
- do {
- if (mOrderedBroadcasts.size() == 0) {
- // No more broadcasts pending, so all done!
- scheduleAppGcsLocked();
- if (looped) {
- // If we had finished the last ordered broadcast, then
- // make sure all processes have correct oom and sched
- // adjustments.
- updateOomAdjLocked();
- }
- return;
- }
- r = mOrderedBroadcasts.get(0);
- boolean forceReceive = false;
-
- // Ensure that even if something goes awry with the timeout
- // detection, we catch "hung" broadcasts here, discard them,
- // and continue to make progress.
- //
- // This is only done if the system is ready so that PRE_BOOT_COMPLETED
- // receivers don't get executed with timeouts. They're intended for
- // one time heavy lifting after system upgrades and can take
- // significant amounts of time.
- int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
- if (mProcessesReady && r.dispatchTime > 0) {
- long now = SystemClock.uptimeMillis();
- if ((numReceivers > 0) &&
- (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
- Slog.w(TAG, "Hung broadcast ["
- + mQueueName + "] discarded after timeout failure:"
- + " now=" + now
- + " dispatchTime=" + r.dispatchTime
- + " startTime=" + r.receiverTime
- + " intent=" + r.intent
- + " numReceivers=" + numReceivers
- + " nextReceiver=" + r.nextReceiver
- + " state=" + r.state);
- broadcastTimeoutLocked(false); // forcibly finish this broadcast
- forceReceive = true;
- r.state = BroadcastRecord.IDLE;
- }
- }
-
- if (r.state != BroadcastRecord.IDLE) {
- if (DEBUG_BROADCAST) Slog.d(TAG,
- "processNextBroadcast("
- + mQueueName + ") called when not idle (state="
- + r.state + ")");
- return;
- }
-
- if (r.receivers == null || r.nextReceiver >= numReceivers
- || r.resultAbort || forceReceive) {
- // No more receivers for this broadcast! Send the final
- // result if requested...
- if (r.resultTo != null) {
- try {
- if (DEBUG_BROADCAST) {
- int seq = r.intent.getIntExtra("seq", -1);
- Slog.i(TAG, "Finishing broadcast ["
- + mQueueName + "] " + r.intent.getAction()
- + " seq=" + seq + " app=" + r.callerApp);
- }
- performReceiveLocked(r.callerApp, r.resultTo,
- new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, false, false);
- // Set this to null so that the reference
- // (local and remote) isnt kept in the mBroadcastHistory.
- r.resultTo = null;
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure ["
- + mQueueName + "] sending broadcast result of "
- + r.intent, e);
- }
- }
-
- if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
- cancelBroadcastTimeoutLocked();
-
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
- + r);
-
- // ... and on to the next...
- addBroadcastToHistoryLocked(r);
- mOrderedBroadcasts.remove(0);
- r = null;
- looped = true;
- continue;
- }
- } while (r == null);
-
- // Get the next receiver...
- int recIdx = r.nextReceiver++;
-
- // Keep track of when this receiver started, and make sure there
- // is a timeout message pending to kill it if need be.
- r.receiverTime = SystemClock.uptimeMillis();
- if (recIdx == 0) {
- r.dispatchTime = r.receiverTime;
- r.dispatchClockTime = System.currentTimeMillis();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
- + mQueueName + "] " + r);
- }
- if (! mPendingBroadcastTimeoutMessage) {
- long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Submitting BROADCAST_TIMEOUT_MSG ["
- + mQueueName + "] for " + r + " at " + timeoutTime);
- setBroadcastTimeoutLocked(timeoutTime);
- }
-
- Object nextReceiver = r.receivers.get(recIdx);
- if (nextReceiver instanceof BroadcastFilter) {
- // Simple case: this is a registered receiver who gets
- // a direct call.
- BroadcastFilter filter = (BroadcastFilter)nextReceiver;
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Delivering ordered ["
- + mQueueName + "] to registered "
- + filter + ": " + r);
- deliverToRegisteredReceiverLocked(r, filter, r.ordered);
- if (r.receiver == null || !r.ordered) {
- // The receiver has already finished, so schedule to
- // process the next one.
- if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
- + mQueueName + "]: ordered="
- + r.ordered + " receiver=" + r.receiver);
- r.state = BroadcastRecord.IDLE;
- scheduleBroadcastsLocked();
- }
- return;
- }
-
- // Hard case: need to instantiate the receiver, possibly
- // starting its application process to host it.
-
- ResolveInfo info =
- (ResolveInfo)nextReceiver;
-
- boolean skip = false;
- int perm = checkComponentPermission(info.activityInfo.permission,
- r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
- info.activityInfo.exported);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- if (!info.activityInfo.exported) {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " is not exported from uid " + info.activityInfo.applicationInfo.uid
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
- } else {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " requires " + info.activityInfo.permission
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
- }
- skip = true;
- }
- if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
- r.requiredPermission != null) {
- try {
- perm = AppGlobals.getPackageManager().
- checkPermission(r.requiredPermission,
- info.activityInfo.applicationInfo.packageName);
- } catch (RemoteException e) {
- perm = PackageManager.PERMISSION_DENIED;
- }
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
- + r.intent + " to "
- + info.activityInfo.applicationInfo.packageName
- + " requires " + r.requiredPermission
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- }
- }
- if (r.curApp != null && r.curApp.crashing) {
- // If the target process is crashing, just skip it.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping deliver ordered ["
- + mQueueName + "] " + r + " to " + r.curApp
- + ": process crashing");
- skip = true;
- }
-
- if (skip) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping delivery of ordered ["
- + mQueueName + "] " + r + " for whatever reason");
- r.receiver = null;
- r.curFilter = null;
- r.state = BroadcastRecord.IDLE;
- scheduleBroadcastsLocked();
- return;
- }
-
- r.state = BroadcastRecord.APP_RECEIVE;
- String targetProcess = info.activityInfo.processName;
- r.curComponent = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- if (r.callingUid != Process.SYSTEM_UID) {
- info.activityInfo = getActivityInfoForUser(info.activityInfo, UserId
- .getUserId(r.callingUid));
- }
- r.curReceiver = info.activityInfo;
- if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
- Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
- + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
- + info.activityInfo.applicationInfo.uid);
- }
-
- // Broadcast is being executed, its package can't be stopped.
- try {
- AppGlobals.getPackageManager().setPackageStoppedState(
- r.curComponent.getPackageName(), false);
- } catch (RemoteException e) {
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed trying to unstop package "
- + r.curComponent.getPackageName() + ": " + e);
- }
-
- // Is this receiver's application already running?
- ProcessRecord app = getProcessRecordLocked(targetProcess,
- info.activityInfo.applicationInfo.uid);
- if (app != null && app.thread != null) {
- try {
- app.addPackage(info.activityInfo.packageName);
- processCurBroadcastLocked(r, app);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when sending broadcast to "
- + r.curComponent, e);
- }
-
- // If a dead object exception was thrown -- fall through to
- // restart the application.
- }
-
- // Not running -- get it started, to be executed when the app comes up.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Need to start app ["
- + mQueueName + "] " + targetProcess + " for broadcast " + r);
- if ((r.curApp=startProcessLocked(targetProcess,
- info.activityInfo.applicationInfo, true,
- r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
- "broadcast", r.curComponent,
- (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
- == null) {
- // Ah, this recipient is unavailable. Finish it if necessary,
- // and mark the broadcast record as ready for the next.
- Slog.w(TAG, "Unable to launch app "
- + info.activityInfo.applicationInfo.packageName + "/"
- + info.activityInfo.applicationInfo.uid + " for broadcast "
- + r.intent + ": process is bad");
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- scheduleBroadcastsLocked();
- r.state = BroadcastRecord.IDLE;
- return;
- }
-
- mPendingBroadcast = r;
- mPendingBroadcastRecvIndex = recIdx;
- }
- }
-
- final void setBroadcastTimeoutLocked(long timeoutTime) {
- if (! mPendingBroadcastTimeoutMessage) {
- Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
- mHandler.sendMessageAtTime(msg, timeoutTime);
- mPendingBroadcastTimeoutMessage = true;
- }
- }
-
- final void cancelBroadcastTimeoutLocked() {
- if (mPendingBroadcastTimeoutMessage) {
- mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
- mPendingBroadcastTimeoutMessage = false;
- }
- }
-
- final void broadcastTimeoutLocked(boolean fromMsg) {
- if (fromMsg) {
- mPendingBroadcastTimeoutMessage = false;
- }
-
- if (mOrderedBroadcasts.size() == 0) {
- return;
- }
-
- long now = SystemClock.uptimeMillis();
- BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (fromMsg) {
- if (mDidDexOpt) {
- // Delay timeouts until dexopt finishes.
- mDidDexOpt = false;
- long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- if (! mProcessesReady) {
- // Only process broadcast timeouts if the system is ready. That way
- // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
- // to do heavy lifting for system up.
- return;
- }
-
- long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (timeoutTime > now) {
- // We can observe premature timeouts because we do not cancel and reset the
- // broadcast timeout message after each receiver finishes. Instead, we set up
- // an initial timeout then kick it down the road a little further as needed
- // when it expires.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Premature timeout ["
- + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
- + timeoutTime);
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- }
-
- Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
- + ", started " + (now - r.receiverTime) + "ms ago");
- r.receiverTime = now;
- r.anrCount++;
-
- // Current receiver has passed its expiration date.
- if (r.nextReceiver <= 0) {
- Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
- return;
- }
-
- ProcessRecord app = null;
- String anrMessage = null;
-
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- Slog.w(TAG, "Receiver during timeout: " + curReceiver);
- logBroadcastReceiverDiscardLocked(r);
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter)curReceiver;
- if (bf.receiverList.pid != 0
- && bf.receiverList.pid != MY_PID) {
- synchronized (ActivityManagerService.this.mPidsSelfLocked) {
- app = ActivityManagerService.this.mPidsSelfLocked.get(
- bf.receiverList.pid);
- }
- }
- } else {
- app = r.curApp;
- }
-
- if (app != null) {
- anrMessage = "Broadcast of " + r.intent.toString();
- }
-
- if (mPendingBroadcast == r) {
- mPendingBroadcast = null;
- }
-
- // Move on to the next receiver.
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- scheduleBroadcastsLocked();
-
- if (anrMessage != null) {
- // Post the ANR to the handler since we do not want to process ANRs while
- // potentially holding our lock.
- mHandler.post(new AppNotResponding(app, anrMessage));
- }
- }
-
- private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
- if (r.callingUid < 0) {
- // This was from a registerReceiver() call; ignore it.
- return;
- }
- System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
- MAX_BROADCAST_HISTORY-1);
- r.finishTime = SystemClock.uptimeMillis();
- mBroadcastHistory[0] = r;
- }
-
- final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
- if (r.nextReceiver > 0) {
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter) curReceiver;
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- System.identityHashCode(bf));
- } else {
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- ((ResolveInfo)curReceiver).toString());
- }
- } else {
- Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
- + r);
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver,
- "NONE");
- }
- }
-
- final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
- if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
- || mPendingBroadcast != null) {
- boolean printed = false;
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
- BroadcastRecord br = mParallelBroadcasts.get(i);
- if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- printed = true;
- pw.println(" Active broadcasts [" + mQueueName + "]:");
- }
- pw.println(" Broadcast #" + i + ":");
- br.dump(pw, " ");
- }
- printed = false;
- needSep = true;
- for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
- BroadcastRecord br = mOrderedBroadcasts.get(i);
- if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
- }
- pw.println(" Ordered Broadcast #" + i + ":");
- mOrderedBroadcasts.get(i).dump(pw, " ");
- }
- if (dumpPackage == null || (mPendingBroadcast != null
- && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
- if (needSep) {
- pw.println();
- }
- pw.println(" Pending broadcast [" + mQueueName + "]:");
- if (mPendingBroadcast != null) {
- mPendingBroadcast.dump(pw, " ");
- } else {
- pw.println(" (null)");
- }
- needSep = true;
- }
- }
-
- boolean printed = false;
- for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
- BroadcastRecord r = mBroadcastHistory[i];
- if (r == null) {
- break;
- }
- if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Historical broadcasts [" + mQueueName + "]:");
- printed = true;
- }
- if (dumpAll) {
- pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
- r.dump(pw, " ");
- } else {
- if (i >= 50) {
- pw.println(" ...");
- break;
- }
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
- }
- }
-
- return needSep;
- }
- }
-
- final BroadcastQueue mFgBroadcastQueue = new BroadcastQueue("foreground", BROADCAST_FG_TIMEOUT);
- final BroadcastQueue mBgBroadcastQueue = new BroadcastQueue("background", BROADCAST_BG_TIMEOUT);
+ BroadcastQueue mFgBroadcastQueue;
+ BroadcastQueue mBgBroadcastQueue;
// Convenient for easy iteration over the queues. Foreground is first
// so that dispatch of foreground broadcasts gets precedence.
- final BroadcastQueue[] mBroadcastQueues = { mFgBroadcastQueue, mBgBroadcastQueue };
+ final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
BroadcastQueue broadcastQueueForIntent(Intent intent) {
final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
@@ -1362,24 +567,6 @@
*/
final ArrayList mCancelledThumbnails = new ArrayList();
- /**
- * All of the currently running global content providers. Keys are a
- * string containing the provider name and values are a
- * ContentProviderRecord object containing the data about it. Note
- * that a single provider may be published under multiple names, so
- * there may be multiple entries here for a single one in mProvidersByClass.
- */
- final HashMap<String, ContentProviderRecord> mProvidersByName
- = new HashMap<String, ContentProviderRecord>();
-
- /**
- * All of the currently running global content providers. Keys are a
- * string containing the provider's implementation class and values are a
- * ContentProviderRecord object containing the data about it.
- */
- final HashMap<ComponentName, ContentProviderRecord> mProvidersByClass
- = new HashMap<ComponentName, ContentProviderRecord>();
-
final ProviderMap mProviderMap = new ProviderMap();
/**
@@ -1560,9 +747,6 @@
int mProfileType = 0;
boolean mAutoStopProfiler = false;
- final RemoteCallbackList<IActivityWatcher> mWatchers
- = new RemoteCallbackList<IActivityWatcher>();
-
final RemoteCallbackList<IProcessObserver> mProcessObservers
= new RemoteCallbackList<IProcessObserver>();
@@ -1639,8 +823,6 @@
static final int UPDATE_CONFIGURATION_MSG = 4;
static final int GC_BACKGROUND_PROCESSES_MSG = 5;
static final int WAIT_FOR_DEBUGGER_MSG = 6;
- static final int BROADCAST_INTENT_MSG = 7;
- static final int BROADCAST_TIMEOUT_MSG = 8;
static final int SERVICE_TIMEOUT_MSG = 12;
static final int UPDATE_TIME_ZONE = 13;
static final int SHOW_UID_ERROR_MSG = 14;
@@ -1660,6 +842,10 @@
static final int DISPATCH_PROCESS_DIED = 32;
static final int REPORT_MEM_USAGE = 33;
+ static final int FIRST_ACTIVITY_STACK_MSG = 100;
+ static final int FIRST_BROADCAST_QUEUE_MSG = 200;
+ static final int FIRST_COMPAT_MODE_MSG = 300;
+
AlertDialog mUidAlert;
CompatModeDialog mCompatModeDialog;
long mLastMemUsageReportTime = 0;
@@ -1680,7 +866,7 @@
return;
}
AppErrorResult res = (AppErrorResult) data.get("result");
- if (!mSleeping && !mShuttingDown) {
+ if (mShowDialogs && !mSleeping && !mShuttingDown) {
Dialog d = new AppErrorDialog(mContext, res, proc);
d.show();
proc.crashDialog = d;
@@ -1732,7 +918,7 @@
return;
}
AppErrorResult res = (AppErrorResult) data.get("result");
- if (!mSleeping && !mShuttingDown) {
+ if (mShowDialogs && !mSleeping && !mShuttingDown) {
Dialog d = new StrictModeViolationDialog(mContext, res, proc);
d.show();
proc.crashDialog = d;
@@ -1779,18 +965,6 @@
}
}
} break;
- case BROADCAST_INTENT_MSG: {
- if (DEBUG_BROADCAST) Slog.v(
- TAG, "Received BROADCAST_INTENT_MSG");
- BroadcastQueue queue = (BroadcastQueue) msg.obj;
- queue.processNextBroadcast(true);
- } break;
- case BROADCAST_TIMEOUT_MSG: {
- final BroadcastQueue queue = (BroadcastQueue) msg.obj;
- synchronized (ActivityManagerService.this) {
- queue.broadcastTimeoutLocked(true);
- }
- } break;
case SERVICE_TIMEOUT_MSG: {
if (mDidDexOpt) {
mDidDexOpt = false;
@@ -1854,16 +1028,22 @@
}
} break;
case SHOW_UID_ERROR_MSG: {
- // XXX This is a temporary dialog, no need to localize.
- AlertDialog d = new BaseErrorDialog(mContext);
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
- d.setCancelable(false);
- d.setTitle("System UIDs Inconsistent");
- d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
- d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
- mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
- mUidAlert = d;
- d.show();
+ String title = "System UIDs Inconsistent";
+ String text = "UIDs on the system are inconsistent, you need to wipe your"
+ + " data partition or your device will be unstable.";
+ Log.e(TAG, title + ": " + text);
+ if (mShowDialogs) {
+ // XXX This is a temporary dialog, no need to localize.
+ AlertDialog d = new BaseErrorDialog(mContext);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.setCancelable(false);
+ d.setTitle(title);
+ d.setMessage(text);
+ d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
+ mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
+ mUidAlert = d;
+ d.show();
+ }
} break;
case IM_FEELING_LUCKY_MSG: {
if (mUidAlert != null) {
@@ -2093,7 +1273,7 @@
try {
ActivityManagerService m = mSelf;
- ServiceManager.addService("activity", m);
+ ServiceManager.addService("activity", m, true);
ServiceManager.addService("meminfo", new MemBinder(m));
ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
ServiceManager.addService("dbinfo", new DbBinder(m));
@@ -2298,6 +1478,11 @@
private ActivityManagerService() {
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
+ mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
+ mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+ mBroadcastQueues[0] = mFgBroadcastQueue;
+ mBroadcastQueues[1] = mBgBroadcastQueue;
+
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
@@ -2311,6 +1496,7 @@
mUsageStatsService = new UsageStatsService(new File(
systemDir, "usagestats").toString());
+ mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -2870,6 +2056,13 @@
}
boolean startHomeActivityLocked(int userId) {
+ if (mHeadless) {
+ // Added because none of the other calls to ensureBootCompleted seem to fire
+ // when running headless.
+ ensureBootCompleted();
+ return false;
+ }
+
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
// We are running in factory test mode, but unable to find
@@ -2964,37 +2157,52 @@
return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
}
+ void enforceNotIsolatedCaller(String caller) {
+ if (UserId.isIsolated(Binder.getCallingUid())) {
+ throw new SecurityException("Isolated process not allowed to call " + caller);
+ }
+ }
+
public int getFrontActivityScreenCompatMode() {
+ enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
synchronized (this) {
return mCompatModePackages.getFrontActivityScreenCompatModeLocked();
}
}
public void setFrontActivityScreenCompatMode(int mode) {
+ enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setFrontActivityScreenCompatMode");
synchronized (this) {
mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
}
}
public int getPackageScreenCompatMode(String packageName) {
+ enforceNotIsolatedCaller("getPackageScreenCompatMode");
synchronized (this) {
return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
}
}
public void setPackageScreenCompatMode(String packageName, int mode) {
+ enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setPackageScreenCompatMode");
synchronized (this) {
mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
}
}
public boolean getPackageAskScreenCompat(String packageName) {
+ enforceNotIsolatedCaller("getPackageAskScreenCompat");
synchronized (this) {
return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
}
}
public void setPackageAskScreenCompat(String packageName, boolean ask) {
+ enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+ "setPackageAskScreenCompat");
synchronized (this) {
mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
}
@@ -3005,19 +2213,6 @@
final int identHash = System.identityHashCode(r);
updateUsageStats(r, true);
-
- int i = mWatchers.beginBroadcast();
- while (i > 0) {
- i--;
- IActivityWatcher w = mWatchers.getBroadcastItem(i);
- if (w != null) {
- try {
- w.activityResuming(identHash);
- } catch (RemoteException e) {
- }
- }
- }
- mWatchers.finishBroadcast();
}
private void dispatchForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
@@ -3069,6 +2264,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ enforceNotIsolatedCaller("startActivity");
int userId = 0;
if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
// Requesting home, set the identity to the current user
@@ -3093,6 +2289,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ enforceNotIsolatedCaller("startActivityAndWait");
WaitResult res = new WaitResult();
int userId = Binder.getOrigCallingUser();
mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
@@ -3107,6 +2304,7 @@
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, Configuration config) {
+ enforceNotIsolatedCaller("startActivityWithConfig");
int ret = mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded,
@@ -3118,6 +2316,7 @@
IntentSender intent, Intent fillInIntent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues) {
+ enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -3259,6 +2458,7 @@
public final int startActivities(IApplicationThread caller,
Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
+ enforceNotIsolatedCaller("startActivities");
int ret = mMainStack.startActivities(caller, -1, intents, resolvedTypes, resultTo,
Binder.getOrigCallingUser());
return ret;
@@ -3551,7 +2751,13 @@
}
// Just in case...
- mMainStack.appDiedLocked(app);
+ if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
+ mMainStack.mPausingActivity = null;
+ }
+ if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
+ mMainStack.mLastPausedActivity = null;
+ }
// Remove this application's activities from active lists.
mMainStack.removeHistoryRecordsForAppLocked(app);
@@ -3828,21 +3034,6 @@
}
}
- private final class AppNotResponding implements Runnable {
- private final ProcessRecord mApp;
- private final String mAnnotation;
-
- public AppNotResponding(ProcessRecord app, String annotation) {
- mApp = app;
- mAnnotation = annotation;
- }
-
- @Override
- public void run() {
- appNotResponding(mApp, null, null, mAnnotation);
- }
- }
-
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
@@ -4020,6 +3211,7 @@
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, final int userId) {
+ enforceNotIsolatedCaller("clearApplicationUserData");
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
long callingId = Binder.clearCallingIdentity();
@@ -4208,6 +3400,7 @@
}
public void closeSystemDialogs(String reason) {
+ enforceNotIsolatedCaller("closeSystemDialogs");
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
if (reason != null) {
@@ -4217,22 +3410,9 @@
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int i = mWatchers.beginBroadcast();
- while (i > 0) {
- i--;
- IActivityWatcher w = mWatchers.getBroadcastItem(i);
- if (w != null) {
- try {
- w.closingSystemDialogs(reason);
- } catch (RemoteException e) {
- }
- }
- }
- mWatchers.finishBroadcast();
-
mWindowManager.closeSystemDialogs(reason);
- for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+ for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
r.stack.finishActivityLocked(r, i,
@@ -4248,6 +3428,7 @@
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
throws RemoteException {
+ enforceNotIsolatedCaller("getProcessMemoryInfo");
Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
for (int i=pids.length-1; i>=0; i--) {
infos[i] = new Debug.MemoryInfo();
@@ -4257,6 +3438,7 @@
}
public long[] getProcessPss(int[] pids) throws RemoteException {
+ enforceNotIsolatedCaller("getProcessPss");
long[] pss = new long[pids.length];
for (int i=pids.length-1; i>=0; i--) {
pss[i] = Debug.getPss(pids[i]);
@@ -4430,7 +3612,7 @@
}
ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
- for (ContentProviderRecord provider : mProvidersByClass.values()) {
+ for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
if (provider.info.packageName.equals(name)
&& (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
if (!doit) {
@@ -4716,7 +3898,9 @@
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
- if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
+ if (mHeadless) {
+ Slog.e(TAG, "Starting activities not supported on headless device: " + hr);
+ } else if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
@@ -4825,10 +4009,12 @@
}
public void showBootMessage(final CharSequence msg, final boolean always) {
+ enforceNotIsolatedCaller("showBootMessage");
mWindowManager.showBootMessage(msg, always);
}
public void dismissKeyguardOnNextActivity() {
+ enforceNotIsolatedCaller("dismissKeyguardOnNextActivity");
synchronized (this) {
mMainStack.dismissKeyguardOnNextActivityLocked();
}
@@ -4991,6 +4177,7 @@
public IIntentSender getIntentSender(int type,
String packageName, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+ enforceNotIsolatedCaller("getIntentSender");
// Refuse possible leaked file descriptors
if (intents != null) {
if (intents.length < 1) {
@@ -5293,6 +4480,10 @@
if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
+ // Isolated processes don't get any permissions.
+ if (UserId.isIsolated(uid)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
// If there is a uid that owns whatever is being accessed, it has
// blanket access to it regardless of the permissions it requires.
if (owningUid >= 0 && UserId.isSameApp(uid, owningUid)) {
@@ -5445,6 +4636,8 @@
}
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ enforceNotIsolatedCaller("checkUriPermission");
+
// Another redirected-binder-call permissions check as in
// {@link checkComponentPermission}.
Identity tlsIdentity = sCallerIdentity.get();
@@ -5595,6 +4788,7 @@
public int checkGrantUriPermission(int callingUid, String targetPkg,
Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("checkGrantUriPermission");
synchronized(this) {
return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
}
@@ -5703,6 +4897,7 @@
public void grantUriPermission(IApplicationThread caller, String targetPkg,
Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("grantUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
@@ -5826,6 +5021,7 @@
public void revokeUriPermission(IApplicationThread caller, Uri uri,
int modeFlags) {
+ enforceNotIsolatedCaller("revokeUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
@@ -5870,6 +5066,7 @@
@Override
public IBinder newUriPermissionOwner(String name) {
+ enforceNotIsolatedCaller("newUriPermissionOwner");
synchronized(this) {
UriPermissionOwner owner = new UriPermissionOwner(this, name);
return owner.getExternalTokenLocked();
@@ -6406,6 +5603,7 @@
* @return Returns true if the move completed, false if not.
*/
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
+ enforceNotIsolatedCaller("moveActivityTaskToBack");
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
int taskId = getTaskForActivityLocked(token, !nonRoot);
@@ -6459,29 +5657,6 @@
return -1;
}
- public void finishOtherInstances(IBinder token, ComponentName className) {
- synchronized(this) {
- final long origId = Binder.clearCallingIdentity();
-
- int N = mMainStack.mHistory.size();
- TaskRecord lastTask = null;
- for (int i=0; i<N; i++) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.realActivity.equals(className)
- && r.appToken != token && lastTask != r.task) {
- if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "others")) {
- i--;
- N--;
- }
- }
- lastTask = r.task;
- }
-
- Binder.restoreCallingIdentity(origId);
- }
- }
-
// =========================================================
// THUMBNAILS
// =========================================================
@@ -6584,7 +5759,7 @@
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
- cpr = new ContentProviderRecord(cpi, app.info, comp);
+ cpr = new ContentProviderRecord(this, cpi, app.info, comp);
mProviderMap.putProviderByClass(comp, cpr);
}
if (DEBUG_MU)
@@ -6656,7 +5831,8 @@
return msg;
}
- boolean incProviderCount(ProcessRecord r, ContentProviderRecord cpr) {
+ boolean incProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
+ IBinder externalProcessToken) {
if (r != null) {
Integer cnt = r.conProviders.get(cpr);
if (DEBUG_PROVIDER) Slog.v(TAG,
@@ -6672,12 +5848,13 @@
r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
}
} else {
- cpr.externals++;
+ cpr.addExternalProcessHandleLocked(externalProcessToken);
}
return false;
}
- boolean decProviderCount(ProcessRecord r, ContentProviderRecord cpr) {
+ boolean decProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
+ IBinder externalProcessToken) {
if (r != null) {
Integer cnt = r.conProviders.get(cpr);
if (DEBUG_PROVIDER) Slog.v(TAG,
@@ -6693,13 +5870,13 @@
r.conProviders.put(cpr, new Integer(cnt.intValue()-1));
}
} else {
- cpr.externals++;
+ cpr.removeExternalProcessHandleLocked(externalProcessToken);
}
return false;
}
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name) {
+ String name, IBinder token) {
ContentProviderRecord cpr;
ProviderInfo cpi = null;
@@ -6743,7 +5920,7 @@
// In this case the provider instance already exists, so we can
// return it right away.
- final boolean countChanged = incProviderCount(r, cpr);
+ final boolean countChanged = incProviderCount(r, cpr, token);
if (countChanged) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
@@ -6777,7 +5954,7 @@
Slog.i(TAG,
"Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
- boolean lastRef = decProviderCount(r, cpr);
+ boolean lastRef = decProviderCount(r, cpr, token);
appDiedLocked(cpr.proc, cpr.proc.pid, cpr.proc.thread);
if (!lastRef) {
// This wasn't the last ref our process had on
@@ -6835,7 +6012,7 @@
return null;
}
ai = getAppInfoForUser(ai, Binder.getOrigCallingUser());
- cpr = new ContentProviderRecord(cpi, ai, comp);
+ cpr = new ContentProviderRecord(this, cpi, ai, comp);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
@@ -6905,8 +6082,9 @@
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
+
mProviderMap.putProviderByName(name, cpr);
- incProviderCount(r, cpr);
+ incProviderCount(r, cpr, token);
}
}
@@ -6938,6 +6116,7 @@
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name) {
+ enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
@@ -6945,12 +6124,17 @@
throw new SecurityException(msg);
}
- ContentProviderHolder contentProvider = getContentProviderImpl(caller, name);
- return contentProvider;
+ return getContentProviderImpl(caller, name, null);
}
- private ContentProviderHolder getContentProviderExternal(String name) {
- return getContentProviderImpl(null, name);
+ public ContentProviderHolder getContentProviderExternal(String name, IBinder token) {
+ enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+ "Do not have permission in call getContentProviderExternal()");
+ return getContentProviderExternalUnchecked(name, token);
+ }
+
+ private ContentProviderHolder getContentProviderExternalUnchecked(String name,IBinder token) {
+ return getContentProviderImpl(null, name, token);
}
/**
@@ -6958,6 +6142,7 @@
* @param cpr
*/
public void removeContentProvider(IApplicationThread caller, String name) {
+ enforceNotIsolatedCaller("removeContentProvider");
synchronized (this) {
int userId = UserId.getUserId(Binder.getCallingUid());
ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
@@ -6985,14 +6170,20 @@
+ cpr.info.name + " in process " + r.processName);
return;
} else {
- if (decProviderCount(r, localCpr)) {
+ if (decProviderCount(r, localCpr, null)) {
updateOomAdjLocked();
}
}
}
}
- private void removeContentProviderExternal(String name) {
+ public void removeContentProviderExternal(String name, IBinder token) {
+ enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+ "Do not have permission in call removeContentProviderExternal()");
+ removeContentProviderExternalUnchecked(name, token);
+ }
+
+ private void removeContentProviderExternalUnchecked(String name, IBinder token) {
synchronized (this) {
ContentProviderRecord cpr = mProviderMap.getProviderByName(name,
Binder.getOrigCallingUser());
@@ -7006,11 +6197,18 @@
ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp,
Binder.getOrigCallingUser());
- localCpr.externals--;
- if (localCpr.externals < 0) {
- Slog.e(TAG, "Externals < 0 for content provider " + localCpr);
+ if (localCpr.hasExternalProcessHandles()) {
+ if (localCpr.removeExternalProcessHandleLocked(token)) {
+ updateOomAdjLocked();
+ } else {
+ Slog.e(TAG, "Attmpt to remove content provider " + localCpr
+ + " with no external reference for token: "
+ + token + ".");
+ }
+ } else {
+ Slog.e(TAG, "Attmpt to remove content provider: " + localCpr
+ + " with no external references.");
}
- updateOomAdjLocked();
}
}
@@ -7020,6 +6218,7 @@
return;
}
+ enforceNotIsolatedCaller("publishContentProviders");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU)
@@ -7107,12 +6306,13 @@
* src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
*/
public String getProviderMimeType(Uri uri) {
+ enforceNotIsolatedCaller("getProviderMimeType");
final String name = uri.getAuthority();
final long ident = Binder.clearCallingIdentity();
ContentProviderHolder holder = null;
try {
- holder = getContentProviderExternal(name);
+ holder = getContentProviderExternalUnchecked(name, null);
if (holder != null) {
return holder.provider.getType(uri);
}
@@ -7121,7 +6321,7 @@
return null;
} finally {
if (holder != null) {
- removeContentProviderExternal(name);
+ removeContentProviderExternalUnchecked(name, null);
}
Binder.restoreCallingIdentity(ident);
}
@@ -7224,8 +6424,9 @@
}
public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
+ enforceNotIsolatedCaller("openContentUri");
String name = uri.getAuthority();
- ContentProviderHolder cph = getContentProviderExternal(name);
+ ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null);
ParcelFileDescriptor pfd = null;
if (cph != null) {
// We record the binder invoker's uid in thread-local storage before
@@ -7247,7 +6448,7 @@
}
// We've got the fd now, so we're done with the provider.
- removeContentProviderExternal(name);
+ removeContentProviderExternalUnchecked(name, null);
} else {
Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
}
@@ -7292,7 +6493,7 @@
mMainStack.stopIfSleepingLocked();
final long endTime = System.currentTimeMillis() + timeout;
while (mMainStack.mResumedActivity != null
- || mMainStack.mPausingActivities.size() > 0) {
+ || mMainStack.mPausingActivity != null) {
long delay = endTime - System.currentTimeMillis();
if (delay <= 0) {
Slog.w(TAG, "Activity manager shutdown timed out");
@@ -7476,24 +6677,18 @@
}
}
- public void registerActivityWatcher(IActivityWatcher watcher) {
- synchronized (this) {
- mWatchers.register(watcher);
- }
- }
-
- public void unregisterActivityWatcher(IActivityWatcher watcher) {
- synchronized (this) {
- mWatchers.unregister(watcher);
- }
- }
-
public void registerProcessObserver(IProcessObserver observer) {
- mProcessObservers.register(observer);
+ enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+ "registerProcessObserver()");
+ synchronized (this) {
+ mProcessObservers.register(observer);
+ }
}
public void unregisterProcessObserver(IProcessObserver observer) {
- mProcessObservers.unregister(observer);
+ synchronized (this) {
+ mProcessObservers.unregister(observer);
+ }
}
public void setImmersive(IBinder token, boolean immersive) {
@@ -7517,6 +6712,7 @@
}
public boolean isTopActivityImmersive() {
+ enforceNotIsolatedCaller("startActivity");
synchronized (this) {
ActivityRecord r = mMainStack.topRunningActivityLocked(null);
return (r != null) ? r.immersive : false;
@@ -7825,7 +7021,7 @@
/* TODO: Send this to all users */
broadcastIntentLocked(null, null, intent, null, finisher,
0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
- Process.SYSTEM_UID);
+ 0 /* UserId zero */);
if (finisher != null) {
mWaitingUpdate = true;
}
@@ -8701,6 +7897,7 @@
}
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
+ enforceNotIsolatedCaller("getProcessesInErrorState");
// assume our apps are happy - lazy create the list
List<ActivityManager.ProcessErrorStateInfo> errList = null;
@@ -8763,6 +7960,7 @@
}
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
+ enforceNotIsolatedCaller("getRunningAppProcesses");
// Lazy instantiation of list
List<ActivityManager.RunningAppProcessInfo> runList = null;
synchronized (this) {
@@ -8808,6 +8006,7 @@
}
public List<ApplicationInfo> getRunningExternalApplications() {
+ enforceNotIsolatedCaller("getRunningExternalApplications");
List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
if (runningApps != null && runningApps.size() > 0) {
@@ -9101,13 +8300,8 @@
}
pw.println(" ");
- if (mMainStack.mPausingActivities.size() > 0) {
- pw.println(" mPausingActivities: " + Arrays.toString(
- mMainStack.mPausingActivities.toArray()));
- }
- if (mMainStack.mInputPausedActivities.size() > 0) {
- pw.println(" mInputPausedActivities: " + Arrays.toString(
- mMainStack.mInputPausedActivities.toArray()));
+ if (mMainStack.mPausingActivity != null) {
+ pw.println(" mPausingActivity: " + mMainStack.mPausingActivity);
}
pw.println(" mResumedActivity: " + mMainStack.mResumedActivity);
pw.println(" mFocusedActivity: " + mFocusedActivity);
@@ -9595,98 +8789,7 @@
*/
protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
- ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-
- if ("all".equals(name)) {
- synchronized (this) {
- for (ContentProviderRecord r1 : mProvidersByClass.values()) {
- providers.add(r1);
- }
- }
- } else {
- ComponentName componentName = name != null
- ? ComponentName.unflattenFromString(name) : null;
- int objectId = 0;
- if (componentName == null) {
- // Not a '/' separated full component name; maybe an object ID?
- try {
- objectId = Integer.parseInt(name, 16);
- name = null;
- componentName = null;
- } catch (RuntimeException e) {
- }
- }
-
- synchronized (this) {
- for (ContentProviderRecord r1 : mProvidersByClass.values()) {
- if (componentName != null) {
- if (r1.name.equals(componentName)) {
- providers.add(r1);
- }
- } else if (name != null) {
- if (r1.name.flattenToString().contains(name)) {
- providers.add(r1);
- }
- } else if (System.identityHashCode(r1) == objectId) {
- providers.add(r1);
- }
- }
- }
- }
-
- if (providers.size() <= 0) {
- return false;
- }
-
- boolean needSep = false;
- for (int i=0; i<providers.size(); i++) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
- }
- return true;
- }
-
- /**
- * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
- * there is a thread associated with the provider.
- */
- private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
- final ContentProviderRecord r, String[] args, boolean dumpAll) {
- String innerPrefix = prefix + " ";
- synchronized (this) {
- pw.print(prefix); pw.print("PROVIDER ");
- pw.print(r);
- pw.print(" pid=");
- if (r.proc != null) pw.println(r.proc.pid);
- else pw.println("(not running)");
- if (dumpAll) {
- r.dump(pw, innerPrefix);
- }
- }
- if (r.proc != null && r.proc.thread != null) {
- pw.println(" Client:");
- pw.flush();
- try {
- TransferPipe tp = new TransferPipe();
- try {
- r.proc.thread.dumpProvider(
- tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
- tp.setBufferPrefix(" ");
- // Short timeout, since blocking here can
- // deadlock with the application.
- tp.go(fd, 2000);
- } finally {
- tp.kill();
- }
- } catch (IOException ex) {
- pw.println(" Failure while dumping the provider: " + ex);
- } catch (RemoteException ex) {
- pw.println(" Got a RemoteException while dumping the service");
- }
- }
+ return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
}
static class ItemMatcher {
@@ -11171,7 +10274,7 @@
for (int i=0; i<NL; i++) {
ContentProviderRecord cpr = (ContentProviderRecord)
mLaunchingProviders.get(i);
- if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
+ if (cpr.clients.size() <= 0 && !cpr.hasExternalProcessHandles()) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll();
@@ -11323,6 +10426,7 @@
public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
int flags) {
+ enforceNotIsolatedCaller("getServices");
synchronized (this) {
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
@@ -11349,6 +10453,7 @@
}
public PendingIntent getRunningServiceControlPanel(ComponentName name) {
+ enforceNotIsolatedCaller("getRunningServiceControlPanel");
synchronized (this) {
int userId = UserId.getUserId(Binder.getCallingUid());
ServiceRecord r = mServiceMap.getServiceByName(name, userId);
@@ -11450,18 +10555,18 @@
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
- String resolvedType, int callingPid, int callingUid) {
+ String resolvedType, int callingPid, int callingUid, int userId) {
ServiceRecord r = null;
if (DEBUG_SERVICE)
Slog.v(TAG, "retrieveServiceLocked: " + service + " type=" + resolvedType
- + " origCallingUid=" + callingUid);
+ + " callingUid=" + callingUid);
if (service.getComponent() != null) {
- r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByName(service.getComponent(), userId);
}
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
- r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByIntent(filter, userId);
}
if (r == null) {
try {
@@ -11475,13 +10580,12 @@
": not found");
return null;
}
- if (Binder.getOrigCallingUser() > 0) {
- sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo,
- Binder.getOrigCallingUser());
+ if (userId > 0) {
+ sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
- r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByName(name, userId);
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(
service.cloneFilter());
@@ -12045,7 +11149,7 @@
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- callingPid, callingUid);
+ callingPid, callingUid, UserId.getUserId(callingUid));
if (res == null) {
return null;
}
@@ -12076,6 +11180,7 @@
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType) {
+ enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12118,6 +11223,7 @@
public int stopService(IApplicationThread caller, Intent service,
String resolvedType) {
+ enforceNotIsolatedCaller("stopService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12155,6 +11261,7 @@
}
public IBinder peekService(Intent service, String resolvedType) {
+ enforceNotIsolatedCaller("peekService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12292,12 +11399,15 @@
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
- IServiceConnection connection, int flags) {
+ IServiceConnection connection, int flags, int userId) {
+ enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ checkValidCaller(Binder.getCallingUid(), userId);
+
synchronized(this) {
if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -12347,7 +11457,7 @@
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getOrigCallingUid());
+ Binder.getCallingPid(), Binder.getCallingUid(), userId);
if (res == null) {
return 0;
}
@@ -12949,6 +12059,7 @@
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission) {
+ enforceNotIsolatedCaller("registerReceiver");
synchronized(this) {
ProcessRecord callerApp = null;
if (caller != null) {
@@ -13458,6 +12569,7 @@
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, boolean serialized, boolean sticky, int userId) {
+ enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -13565,138 +12677,7 @@
Binder.restoreCallingIdentity(origId);
}
}
-
- private final void processCurBroadcastLocked(BroadcastRecord r,
- ProcessRecord app) throws RemoteException {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Process cur broadcast " + r + " for app " + app);
- if (app.thread == null) {
- throw new RemoteException();
- }
- r.receiver = app.thread.asBinder();
- r.curApp = app;
- app.curReceiver = r;
- updateLruProcessLocked(app, true, true);
-
- // Tell the application to launch this receiver.
- r.intent.setComponent(r.curComponent);
-
- boolean started = false;
- try {
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
- "Delivering to component " + r.curComponent
- + ": " + r);
- ensurePackageDexOpt(r.intent.getComponent().getPackageName());
- app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
- compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
- r.resultCode, r.resultData, r.resultExtras, r.ordered);
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Process cur broadcast " + r + " DELIVERED for app " + app);
- started = true;
- } finally {
- if (!started) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Process cur broadcast " + r + ": NOT STARTED!");
- r.receiver = null;
- r.curApp = null;
- app.curReceiver = null;
- }
- }
-
- }
-
- static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
- Intent intent, int resultCode, String data, Bundle extras,
- boolean ordered, boolean sticky) throws RemoteException {
- // Send the intent to the receiver asynchronously using one-way binder calls.
- if (app != null && app.thread != null) {
- // If we have an app thread, do the call through that so it is
- // correctly ordered with other one-way calls.
- app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
- data, extras, ordered, sticky);
- } else {
- receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
- }
- }
- private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
- BroadcastFilter filter, boolean ordered) {
- boolean skip = false;
- if (filter.requiredPermission != null) {
- int perm = checkComponentPermission(filter.requiredPermission,
- r.callingPid, r.callingUid, -1, true);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid="
- + r.callingPid + ", uid=" + r.callingUid + ")"
- + " requires " + filter.requiredPermission
- + " due to registered receiver " + filter);
- skip = true;
- }
- }
- if (r.requiredPermission != null) {
- int perm = checkComponentPermission(r.requiredPermission,
- filter.receiverList.pid, filter.receiverList.uid, -1, true);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
- + r.intent.toString()
- + " to " + filter.receiverList.app
- + " (pid=" + filter.receiverList.pid
- + ", uid=" + filter.receiverList.uid + ")"
- + " requires " + r.requiredPermission
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- }
- }
-
- if (!skip) {
- // If this is not being sent as an ordered broadcast, then we
- // don't want to touch the fields that keep track of the current
- // state of ordered broadcasts.
- if (ordered) {
- r.receiver = filter.receiverList.receiver.asBinder();
- r.curFilter = filter;
- filter.receiverList.curBroadcast = r;
- r.state = BroadcastRecord.CALL_IN_RECEIVE;
- if (filter.receiverList.app != null) {
- // Bump hosting application to no longer be in background
- // scheduling class. Note that we can't do that if there
- // isn't an app... but we can only be in that case for
- // things that directly call the IActivityManager API, which
- // are already core system stuff so don't matter for this.
- r.curApp = filter.receiverList.app;
- filter.receiverList.app.curReceiver = r;
- updateOomAdjLocked();
- }
- }
- try {
- if (DEBUG_BROADCAST_LIGHT) {
- int seq = r.intent.getIntExtra("seq", -1);
- Slog.i(TAG, "Delivering to " + filter
- + " (seq=" + seq + "): " + r);
- }
- performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
- new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, r.ordered, r.initialSticky);
- if (ordered) {
- r.state = BroadcastRecord.CALL_DONE_RECEIVE;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
- if (ordered) {
- r.receiver = null;
- r.curFilter = null;
- filter.receiverList.curBroadcast = null;
- if (filter.receiverList.app != null) {
- filter.receiverList.app.curReceiver = null;
- }
- }
- }
- }
- }
-
// =========================================================
// INSTRUMENTATION
// =========================================================
@@ -13704,6 +12685,7 @@
public boolean startInstrumentation(ComponentName className,
String profileFile, int flags, Bundle arguments,
IInstrumentationWatcher watcher) {
+ enforceNotIsolatedCaller("startInstrumentation");
// Refuse possible leaked file descriptors
if (arguments != null && arguments.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
@@ -13901,8 +12883,11 @@
* configuration.
* @param persistent TODO
*/
- public boolean updateConfigurationLocked(Configuration values,
+ boolean updateConfigurationLocked(Configuration values,
ActivityRecord starting, boolean persistent, boolean initLocale) {
+ // do nothing if we are headless
+ if (mHeadless) return true;
+
int changes = 0;
boolean kept = true;
@@ -13932,6 +12917,10 @@
Slog.i(TAG, "Config changed: " + newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
+
+ // TODO: If our config changes, should we auto dismiss any currently
+ // showing dialogs?
+ mShowDialogs = shouldShowDialogs(newConfig);
AttributeCache ac = AttributeCache.instance();
if (ac != null) {
@@ -13998,6 +12987,19 @@
return kept;
}
+
+ /**
+ * Decide based on the configuration whether we should shouw the ANR,
+ * crash, etc dialogs. The idea is that if there is no affordnace to
+ * press the on-screen buttons, we shouldn't show the dialog.
+ *
+ * A thought: SystemUI might also want to get told about this, the Power
+ * dialog / global actions also might want different behaviors.
+ */
+ private static final boolean shouldShowDialogs(Configuration config) {
+ return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
+ && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH);
+ }
/**
* Save the locale. You must be inside a synchronized (this) block.
@@ -14474,7 +13476,7 @@
// If the provider has external (non-framework) process
// dependencies, ensure that its adjustment is at least
// FOREGROUND_APP_ADJ.
- if (cpr.externals != 0) {
+ if (cpr.hasExternalProcessHandles()) {
if (adj > ProcessList.FOREGROUND_APP_ADJ) {
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -14874,13 +13876,7 @@
private final ActivityRecord resumedAppLocked() {
ActivityRecord resumedActivity = mMainStack.mResumedActivity;
if (resumedActivity == null || resumedActivity.app == null) {
- for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) {
- ActivityRecord r = mMainStack.mPausingActivities.get(i);
- if (r.app != null) {
- resumedActivity = r;
- break;
- }
- }
+ resumedActivity = mMainStack.mPausingActivity;
if (resumedActivity == null || resumedActivity.app == null) {
resumedActivity = mMainStack.topRunningActivityLocked(null);
}
@@ -15321,7 +14317,7 @@
synchronized (this) { }
}
- public void onCoreSettingsChange(Bundle settings) {
+ void onCoreSettingsChange(Bundle settings) {
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord processRecord = mLruProcesses.get(i);
try {
@@ -15338,6 +14334,25 @@
private int mCurrentUserId;
private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
+ private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
+
+ public interface UserListener {
+ public void onUserChanged(int userId);
+
+ public void onUserAdded(int userId);
+
+ public void onUserRemoved(int userId);
+
+ public void onUserLoggedOut(int userId);
+ }
+
+ public void addUserListener(UserListener listener) {
+ synchronized (this) {
+ if (!mUserListeners.contains(listener)) {
+ mUserListeners.add(listener);
+ }
+ }
+ }
public boolean switchUser(int userId) {
final int callingUid = Binder.getCallingUid();
@@ -15348,6 +14363,8 @@
if (mCurrentUserId == userId)
return true;
+ ArrayList<UserListener> listeners;
+
synchronized (this) {
// Check if user is already logged in, otherwise check if user exists first before
// adding to the list of logged in users.
@@ -15363,6 +14380,12 @@
if (!haveActivities) {
startHomeActivityLocked(userId);
}
+
+ listeners = (ArrayList<UserListener>) mUserListeners.clone();
+ }
+ // Inform the listeners
+ for (UserListener listener : listeners) {
+ listener.onUserChanged(userId);
}
return true;
}
@@ -15382,6 +14405,12 @@
return false;
}
+ private void checkValidCaller(int uid, int userId) {
+ if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
+
+ throw new SecurityException("Caller uid=" + uid
+ + " is not privileged to communicate with user=" + userId);
+ }
private int applyUserId(int uid, int userId) {
return UserId.getUid(userId, uid);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 977ee84..cdab6c6 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -602,7 +602,6 @@
public void windowsDrawn() {
synchronized(service) {
- stack.reportActivityDrawnLocked(this);
if (launchTime != 0) {
final long curTime = SystemClock.uptimeMillis();
final long thisTime = curTime - launchTime;
@@ -691,9 +690,7 @@
// Hmmm, who might we be waiting for?
r = stack.mResumedActivity;
if (r == null) {
- if (stack.mPausingActivities.size() > 0) {
- r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1);
- }
+ r = stack.mPausingActivity;
}
// Both of those null? Fall back to 'this' again
if (r == null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f59f0c1..7b8bc26 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -227,13 +227,7 @@
* When we are in the process of pausing an activity, before starting the
* next one, this variable holds the activity that is currently being paused.
*/
- final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>();
-
- /**
- * These activities currently have their input paused, as they want for
- * the next top activity to have its windows visible.
- */
- final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>();
+ ActivityRecord mPausingActivity = null;
/**
* This is the last activity that we put into the paused state. This is
@@ -283,13 +277,13 @@
private int mCurrentUser;
- static final int SLEEP_TIMEOUT_MSG = 8;
- static final int PAUSE_TIMEOUT_MSG = 9;
- static final int IDLE_TIMEOUT_MSG = 10;
- static final int IDLE_NOW_MSG = 11;
- static final int LAUNCH_TIMEOUT_MSG = 16;
- static final int DESTROY_TIMEOUT_MSG = 17;
- static final int RESUME_TOP_ACTIVITY_MSG = 19;
+ static final int SLEEP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG;
+ static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
+ static final int IDLE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
+ static final int IDLE_NOW_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
+ static final int LAUNCH_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
+ static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
+ static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
final Handler mHandler = new Handler() {
//public Handler() {
@@ -813,9 +807,9 @@
startPausingLocked(false, true);
return;
}
- if (mPausingActivities.size() > 0) {
+ if (mPausingActivity != null) {
// Still waiting for something to pause; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities);
+ if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
return;
}
@@ -878,6 +872,11 @@
}
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
+ if (mPausingActivity != null) {
+ RuntimeException e = new RuntimeException();
+ Slog.e(TAG, "Trying to pause when pause is already pending for "
+ + mPausingActivity, e);
+ }
ActivityRecord prev = mResumedActivity;
if (prev == null) {
RuntimeException e = new RuntimeException();
@@ -885,25 +884,19 @@
resumeTopActivityLocked(null);
return;
}
- if (mPausingActivities.contains(prev)) {
- RuntimeException e = new RuntimeException();
- Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e);
- }
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
- mPausingActivities.add(prev);
+ mPausingActivity = prev;
mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
prev.updateThumbnail(screenshotActivities(prev), null);
mService.updateCpuStats();
- ActivityRecord pausing;
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
- pausing = prev;
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
System.identityHashCode(prev),
@@ -916,14 +909,12 @@
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
- mPausingActivities.remove(prev);
+ mPausingActivity = null;
mLastPausedActivity = null;
- pausing = null;
}
} else {
- mPausingActivities.remove(prev);
+ mPausingActivity = null;
mLastPausedActivity = null;
- pausing = null;
}
// If we are not going to sleep, we want to ensure the device is
@@ -937,28 +928,18 @@
}
}
- if (pausing != null) {
+
+ if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
// the screen is being turned off and the UI is sleeping, don't interrupt
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
- pausing.pauseKeyDispatchingLocked();
- mInputPausedActivities.add(prev);
+ prev.pauseKeyDispatchingLocked();
} else {
if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
}
- if (pausing.configDestroy) {
- // The previous is being paused because the configuration
- // is changing, which means it is actually stopping...
- // To juggle the fact that we are also starting a new
- // instance right now, we need to first completely stop
- // the current instance before starting the new one.
- if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev);
- destroyActivityLocked(pausing, true, false, "pause-config");
- }
-
// Schedule a pause timeout in case the app doesn't respond.
// We don't give it much time because this directly impacts the
// responsiveness seen by the user.
@@ -970,10 +951,7 @@
// This activity failed to schedule the
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
- }
-
- if (!mService.isSleeping()) {
- resumeTopActivityLocked(pausing);
+ resumeTopActivityLocked(null);
}
}
@@ -988,17 +966,16 @@
if (index >= 0) {
r = mHistory.get(index);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- if (mPausingActivities.contains(r)) {
+ if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
r.state = ActivityState.PAUSED;
- completePauseLocked(r);
+ completePauseLocked();
} else {
- ActivityRecord old = mPausingActivities.size() > 0
- ? mPausingActivities.get(0) : null;
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
System.identityHashCode(r), r.shortComponentName,
- old != null ? old.shortComponentName : "(none)");
+ mPausingActivity != null
+ ? mPausingActivity.shortComponentName : "(none)");
}
}
}
@@ -1024,14 +1001,8 @@
ProcessRecord fgApp = null;
if (mResumedActivity != null) {
fgApp = mResumedActivity.app;
- } else {
- for (int i=mPausingActivities.size()-1; i>=0; i--) {
- ActivityRecord pausing = mPausingActivities.get(i);
- if (pausing.app == r.app) {
- fgApp = pausing.app;
- break;
- }
- }
+ } else if (mPausingActivity != null) {
+ fgApp = mPausingActivity.app;
}
if (r.app != null && fgApp != null && r.app != fgApp
&& r.lastVisibleTime > mService.mPreviousProcessVisibleTime
@@ -1043,49 +1014,58 @@
}
}
- private final void completePauseLocked(ActivityRecord prev) {
+ private final void completePauseLocked() {
+ ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
- if (prev.finishing) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
- prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
- } else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
- if (prev.waitingVisible) {
- prev.waitingVisible = false;
- mWaitingVisibleActivities.remove(prev);
- if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
- TAG, "Complete pause, no longer waiting: " + prev);
- }
- if (prev.configDestroy) {
- // The previous is being paused because the configuration
- // is changing, which means it is actually stopping...
- // To juggle the fact that we are also starting a new
- // instance right now, we need to first completely stop
- // the current instance before starting the new one.
- if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
- destroyActivityLocked(prev, true, false, "pause-config");
- } else {
- mStoppingActivities.add(prev);
- if (mStoppingActivities.size() > 3) {
- // If we already have a few activities waiting to stop,
- // then give up on things going idle and start clearing
- // them out.
- if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
- scheduleIdleLocked();
- } else {
- checkReadyForSleepLocked();
+ if (prev != null) {
+ if (prev.finishing) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+ prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
+ } else if (prev.app != null) {
+ if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+ if (prev.waitingVisible) {
+ prev.waitingVisible = false;
+ mWaitingVisibleActivities.remove(prev);
+ if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
+ TAG, "Complete pause, no longer waiting: " + prev);
}
+ if (prev.configDestroy) {
+ // The previous is being paused because the configuration
+ // is changing, which means it is actually stopping...
+ // To juggle the fact that we are also starting a new
+ // instance right now, we need to first completely stop
+ // the current instance before starting the new one.
+ if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
+ destroyActivityLocked(prev, true, false, "pause-config");
+ } else {
+ mStoppingActivities.add(prev);
+ if (mStoppingActivities.size() > 3) {
+ // If we already have a few activities waiting to stop,
+ // then give up on things going idle and start clearing
+ // them out.
+ if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
+ scheduleIdleLocked();
+ } else {
+ checkReadyForSleepLocked();
+ }
+ }
+ } else {
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+ prev = null;
}
- } else {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
- prev = null;
+ mPausingActivity = null;
}
- mPausingActivities.remove(prev);
- if (mService.isSleeping()) {
+ if (!mService.isSleeping()) {
+ resumeTopActivityLocked(prev);
+ } else {
checkReadyForSleepLocked();
}
+
+ if (prev != null) {
+ prev.resumeKeyDispatchingLocked();
+ }
if (prev.app != null && prev.cpuTimeAtResume > 0
&& mService.mBatteryStatsService.isOnBattery()) {
@@ -1142,9 +1122,7 @@
if (mMainStack) {
mService.setFocusedActivityLocked(next);
}
- if (mInputPausedActivities.remove(next)) {
- next.resumeKeyDispatchingLocked();
- }
+ next.resumeKeyDispatchingLocked();
ensureActivitiesVisibleLocked(null, 0);
mService.mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
@@ -1374,6 +1352,13 @@
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
+ // If we are currently pausing an activity, then don't do anything
+ // until that is done.
+ if (mPausingActivity != null) {
+ if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
+ return false;
+ }
+
// Okay we are now going to start a switch, to 'next'. We may first
// have to pause the current activity, but this is an important point
// where we have decided to go to 'next' so keep track of that.
@@ -2455,7 +2440,7 @@
err = startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
- if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) {
+ if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
// Someone asked to have the keyguard dismissed on the next
// activity start, but we are not actually doing an activity
// switch... just dismiss the keyguard now, because we
@@ -3126,18 +3111,7 @@
}
mService.notifyAll();
}
-
- void reportActivityDrawnLocked(ActivityRecord r) {
- if (mResumedActivity == r) {
- // Once the resumed activity has been drawn, we can stop
- // pausing input on all other activities.
- for (int i=mInputPausedActivities.size()-1; i>=0; i--) {
- mInputPausedActivities.get(i).resumeKeyDispatchingLocked();
- }
- mInputPausedActivities.clear();
- }
- }
-
+
void reportActivityVisibleLocked(ActivityRecord r) {
for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
WaitResult w = mWaitingActivityVisible.get(i);
@@ -3196,9 +3170,7 @@
mService.setFocusedActivityLocked(topRunningActivityLocked(null));
}
}
- if (mInputPausedActivities.remove(r)) {
- r.resumeKeyDispatchingLocked();
- }
+ r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
@@ -3524,7 +3496,7 @@
// Tell window manager to prepare for this one to be removed.
mService.mWindowManager.setAppVisibility(r.appToken, false);
- if (!mPausingActivities.contains(r)) {
+ if (mPausingActivity == null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
startPausingLocked(false, false);
@@ -3608,20 +3580,6 @@
return r;
}
- final void appDiedLocked(ProcessRecord app) {
- for (int i=mPausingActivities.size()-1; i>=0; i--) {
- ActivityRecord r = mPausingActivities.get(i);
- if (r.app == app) {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r);
- mPausingActivities.remove(i);
- mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- }
- }
- if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
- mLastPausedActivity = null;
- }
- }
-
/**
* Perform the common clean-up of an activity record. This is called both
* as part of destroyActivityLocked() (when destroying the client-side
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
new file mode 100644
index 0000000..39b63db
--- /dev/null
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserId;
+import android.util.EventLog;
+import android.util.Slog;
+
+/**
+ * BROADCASTS
+ *
+ * We keep two broadcast queues and associated bookkeeping, one for those at
+ * foreground priority, and one for normal (background-priority) broadcasts.
+ */
+public class BroadcastQueue {
+ static final String TAG = "BroadcastQueue";
+ static final String TAG_MU = ActivityManagerService.TAG_MU;
+ static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
+ static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
+ static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+
+ static final int MAX_BROADCAST_HISTORY = 25;
+
+ final ActivityManagerService mService;
+
+ /**
+ * Recognizable moniker for this queue
+ */
+ final String mQueueName;
+
+ /**
+ * Timeout period for this queue's broadcasts
+ */
+ final long mTimeoutPeriod;
+
+ /**
+ * Lists of all active broadcasts that are to be executed immediately
+ * (without waiting for another broadcast to finish). Currently this only
+ * contains broadcasts to registered receivers, to avoid spinning up
+ * a bunch of processes to execute IntentReceiver components. Background-
+ * and foreground-priority broadcasts are queued separately.
+ */
+ final ArrayList<BroadcastRecord> mParallelBroadcasts
+ = new ArrayList<BroadcastRecord>();
+ /**
+ * List of all active broadcasts that are to be executed one at a time.
+ * The object at the top of the list is the currently activity broadcasts;
+ * those after it are waiting for the top to finish. As with parallel
+ * broadcasts, separate background- and foreground-priority queues are
+ * maintained.
+ */
+ final ArrayList<BroadcastRecord> mOrderedBroadcasts
+ = new ArrayList<BroadcastRecord>();
+
+ /**
+ * Historical data of past broadcasts, for debugging.
+ */
+ final BroadcastRecord[] mBroadcastHistory
+ = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+
+ /**
+ * Set when we current have a BROADCAST_INTENT_MSG in flight.
+ */
+ boolean mBroadcastsScheduled = false;
+
+ /**
+ * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
+ */
+ boolean mPendingBroadcastTimeoutMessage;
+
+ /**
+ * Intent broadcasts that we have tried to start, but are
+ * waiting for the application's process to be created. We only
+ * need one per scheduling class (instead of a list) because we always
+ * process broadcasts one at a time, so no others can be started while
+ * waiting for this one.
+ */
+ BroadcastRecord mPendingBroadcast = null;
+
+ /**
+ * The receiver index that is pending, to restart the broadcast if needed.
+ */
+ int mPendingBroadcastRecvIndex;
+
+ static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG;
+ static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
+
+ final Handler mHandler = new Handler() {
+ //public Handler() {
+ // if (localLOGV) Slog.v(TAG, "Handler started!");
+ //}
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case BROADCAST_INTENT_MSG: {
+ if (DEBUG_BROADCAST) Slog.v(
+ TAG, "Received BROADCAST_INTENT_MSG");
+ processNextBroadcast(true);
+ } break;
+ case BROADCAST_TIMEOUT_MSG: {
+ synchronized (mService) {
+ broadcastTimeoutLocked(true);
+ }
+ } break;
+ }
+ }
+ };
+
+ private final class AppNotResponding implements Runnable {
+ private final ProcessRecord mApp;
+ private final String mAnnotation;
+
+ public AppNotResponding(ProcessRecord app, String annotation) {
+ mApp = app;
+ mAnnotation = annotation;
+ }
+
+ @Override
+ public void run() {
+ mService.appNotResponding(mApp, null, null, mAnnotation);
+ }
+ }
+
+ BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+ mService = service;
+ mQueueName = name;
+ mTimeoutPeriod = timeoutPeriod;
+ }
+
+ public boolean isPendingBroadcastProcessLocked(int pid) {
+ return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
+ }
+
+ public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
+ mParallelBroadcasts.add(r);
+ }
+
+ public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+ mOrderedBroadcasts.add(r);
+ }
+
+ public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING PARALLEL ["
+ + mQueueName + "]: " + r.intent);
+ mParallelBroadcasts.set(i, r);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
+ for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
+ if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING ORDERED ["
+ + mQueueName + "]: " + r.intent);
+ mOrderedBroadcasts.set(i, r);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private final void processCurBroadcastLocked(BroadcastRecord r,
+ ProcessRecord app) throws RemoteException {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Process cur broadcast " + r + " for app " + app);
+ if (app.thread == null) {
+ throw new RemoteException();
+ }
+ r.receiver = app.thread.asBinder();
+ r.curApp = app;
+ app.curReceiver = r;
+ mService.updateLruProcessLocked(app, true, true);
+
+ // Tell the application to launch this receiver.
+ r.intent.setComponent(r.curComponent);
+
+ boolean started = false;
+ try {
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+ "Delivering to component " + r.curComponent
+ + ": " + r);
+ mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
+ app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
+ mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
+ r.resultCode, r.resultData, r.resultExtras, r.ordered);
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Process cur broadcast " + r + " DELIVERED for app " + app);
+ started = true;
+ } finally {
+ if (!started) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Process cur broadcast " + r + ": NOT STARTED!");
+ r.receiver = null;
+ r.curApp = null;
+ app.curReceiver = null;
+ }
+ }
+ }
+
+ public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+ boolean didSomething = false;
+ final BroadcastRecord br = mPendingBroadcast;
+ if (br != null && br.curApp.pid == app.pid) {
+ try {
+ mPendingBroadcast = null;
+ processCurBroadcastLocked(br, app);
+ didSomething = true;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception in new application when starting receiver "
+ + br.curComponent.flattenToShortString(), e);
+ logBroadcastReceiverDiscardLocked(br);
+ finishReceiverLocked(br, br.resultCode, br.resultData,
+ br.resultExtras, br.resultAbort, true);
+ scheduleBroadcastsLocked();
+ // We need to reset the state if we fails to start the receiver.
+ br.state = BroadcastRecord.IDLE;
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ return didSomething;
+ }
+
+ public void skipPendingBroadcastLocked(int pid) {
+ final BroadcastRecord br = mPendingBroadcast;
+ if (br != null && br.curApp.pid == pid) {
+ br.state = BroadcastRecord.IDLE;
+ br.nextReceiver = mPendingBroadcastRecvIndex;
+ mPendingBroadcast = null;
+ scheduleBroadcastsLocked();
+ }
+ }
+
+ public void skipCurrentReceiverLocked(ProcessRecord app) {
+ boolean reschedule = false;
+ BroadcastRecord r = app.curReceiver;
+ if (r != null) {
+ // The current broadcast is waiting for this app's receiver
+ // to be finished. Looks like that's not going to happen, so
+ // let the broadcast continue.
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ reschedule = true;
+ }
+
+ r = mPendingBroadcast;
+ if (r != null && r.curApp == app) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "[" + mQueueName + "] skip & discard pending app " + r);
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ reschedule = true;
+ }
+ if (reschedule) {
+ scheduleBroadcastsLocked();
+ }
+ }
+
+ public void scheduleBroadcastsLocked() {
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ + mQueueName + "]: current="
+ + mBroadcastsScheduled);
+
+ if (mBroadcastsScheduled) {
+ return;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
+ mBroadcastsScheduled = true;
+ }
+
+ public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+ if (mOrderedBroadcasts.size() > 0) {
+ final BroadcastRecord r = mOrderedBroadcasts.get(0);
+ if (r != null && r.receiver == receiver) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
+ String resultData, Bundle resultExtras, boolean resultAbort,
+ boolean explicit) {
+ int state = r.state;
+ r.state = BroadcastRecord.IDLE;
+ if (state == BroadcastRecord.IDLE) {
+ if (explicit) {
+ Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
+ }
+ }
+ r.receiver = null;
+ r.intent.setComponent(null);
+ if (r.curApp != null) {
+ r.curApp.curReceiver = null;
+ }
+ if (r.curFilter != null) {
+ r.curFilter.receiverList.curBroadcast = null;
+ }
+ r.curFilter = null;
+ r.curApp = null;
+ r.curComponent = null;
+ r.curReceiver = null;
+ mPendingBroadcast = null;
+
+ r.resultCode = resultCode;
+ r.resultData = resultData;
+ r.resultExtras = resultExtras;
+ r.resultAbort = resultAbort;
+
+ // We will process the next receiver right now if this is finishing
+ // an app receiver (which is always asynchronous) or after we have
+ // come back from calling a receiver.
+ return state == BroadcastRecord.APP_RECEIVE
+ || state == BroadcastRecord.CALL_DONE_RECEIVE;
+ }
+
+ private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
+ Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky) throws RemoteException {
+ // Send the intent to the receiver asynchronously using one-way binder calls.
+ if (app != null && app.thread != null) {
+ // If we have an app thread, do the call through that so it is
+ // correctly ordered with other one-way calls.
+ app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+ data, extras, ordered, sticky);
+ } else {
+ receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
+ }
+ }
+
+ private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
+ BroadcastFilter filter, boolean ordered) {
+ boolean skip = false;
+ if (filter.requiredPermission != null) {
+ int perm = mService.checkComponentPermission(filter.requiredPermission,
+ r.callingPid, r.callingUid, -1, true);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid="
+ + r.callingPid + ", uid=" + r.callingUid + ")"
+ + " requires " + filter.requiredPermission
+ + " due to registered receiver " + filter);
+ skip = true;
+ }
+ }
+ if (r.requiredPermission != null) {
+ int perm = mService.checkComponentPermission(r.requiredPermission,
+ filter.receiverList.pid, filter.receiverList.uid, -1, true);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: receiving "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " requires " + r.requiredPermission
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
+ if (!skip) {
+ // If this is not being sent as an ordered broadcast, then we
+ // don't want to touch the fields that keep track of the current
+ // state of ordered broadcasts.
+ if (ordered) {
+ r.receiver = filter.receiverList.receiver.asBinder();
+ r.curFilter = filter;
+ filter.receiverList.curBroadcast = r;
+ r.state = BroadcastRecord.CALL_IN_RECEIVE;
+ if (filter.receiverList.app != null) {
+ // Bump hosting application to no longer be in background
+ // scheduling class. Note that we can't do that if there
+ // isn't an app... but we can only be in that case for
+ // things that directly call the IActivityManager API, which
+ // are already core system stuff so don't matter for this.
+ r.curApp = filter.receiverList.app;
+ filter.receiverList.app.curReceiver = r;
+ mService.updateOomAdjLocked();
+ }
+ }
+ try {
+ if (DEBUG_BROADCAST_LIGHT) {
+ int seq = r.intent.getIntExtra("seq", -1);
+ Slog.i(TAG, "Delivering to " + filter
+ + " (seq=" + seq + "): " + r);
+ }
+ performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
+ new Intent(r.intent), r.resultCode,
+ r.resultData, r.resultExtras, r.ordered, r.initialSticky);
+ if (ordered) {
+ r.state = BroadcastRecord.CALL_DONE_RECEIVE;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
+ if (ordered) {
+ r.receiver = null;
+ r.curFilter = null;
+ filter.receiverList.curBroadcast = null;
+ if (filter.receiverList.app != null) {
+ filter.receiverList.app.curReceiver = null;
+ }
+ }
+ }
+ }
+ }
+
+ final void processNextBroadcast(boolean fromMsg) {
+ synchronized(mService) {
+ BroadcastRecord r;
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+ + mQueueName + "]: "
+ + mParallelBroadcasts.size() + " broadcasts, "
+ + mOrderedBroadcasts.size() + " ordered broadcasts");
+
+ mService.updateCpuStats();
+
+ if (fromMsg) {
+ mBroadcastsScheduled = false;
+ }
+
+ // First, deliver any non-serialized broadcasts right away.
+ while (mParallelBroadcasts.size() > 0) {
+ r = mParallelBroadcasts.remove(0);
+ r.dispatchTime = SystemClock.uptimeMillis();
+ r.dispatchClockTime = System.currentTimeMillis();
+ final int N = r.receivers.size();
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+ + mQueueName + "] " + r);
+ for (int i=0; i<N; i++) {
+ Object target = r.receivers.get(i);
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering non-ordered on [" + mQueueName + "] to registered "
+ + target + ": " + r);
+ deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
+ }
+ addBroadcastToHistoryLocked(r);
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+ + mQueueName + "] " + r);
+ }
+
+ // Now take care of the next serialized one...
+
+ // If we are waiting for a process to come up to handle the next
+ // broadcast, then do nothing at this point. Just in case, we
+ // check that the process we're waiting for still exists.
+ if (mPendingBroadcast != null) {
+ if (DEBUG_BROADCAST_LIGHT) {
+ Slog.v(TAG, "processNextBroadcast ["
+ + mQueueName + "]: waiting for "
+ + mPendingBroadcast.curApp);
+ }
+
+ boolean isDead;
+ synchronized (mService.mPidsSelfLocked) {
+ isDead = (mService.mPidsSelfLocked.get(
+ mPendingBroadcast.curApp.pid) == null);
+ }
+ if (!isDead) {
+ // It's still alive, so keep waiting
+ return;
+ } else {
+ Slog.w(TAG, "pending app ["
+ + mQueueName + "]" + mPendingBroadcast.curApp
+ + " died before responding to broadcast");
+ mPendingBroadcast.state = BroadcastRecord.IDLE;
+ mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
+ mPendingBroadcast = null;
+ }
+ }
+
+ boolean looped = false;
+
+ do {
+ if (mOrderedBroadcasts.size() == 0) {
+ // No more broadcasts pending, so all done!
+ mService.scheduleAppGcsLocked();
+ if (looped) {
+ // If we had finished the last ordered broadcast, then
+ // make sure all processes have correct oom and sched
+ // adjustments.
+ mService.updateOomAdjLocked();
+ }
+ return;
+ }
+ r = mOrderedBroadcasts.get(0);
+ boolean forceReceive = false;
+
+ // Ensure that even if something goes awry with the timeout
+ // detection, we catch "hung" broadcasts here, discard them,
+ // and continue to make progress.
+ //
+ // This is only done if the system is ready so that PRE_BOOT_COMPLETED
+ // receivers don't get executed with timeouts. They're intended for
+ // one time heavy lifting after system upgrades and can take
+ // significant amounts of time.
+ int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+ if (mService.mProcessesReady && r.dispatchTime > 0) {
+ long now = SystemClock.uptimeMillis();
+ if ((numReceivers > 0) &&
+ (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+ Slog.w(TAG, "Hung broadcast ["
+ + mQueueName + "] discarded after timeout failure:"
+ + " now=" + now
+ + " dispatchTime=" + r.dispatchTime
+ + " startTime=" + r.receiverTime
+ + " intent=" + r.intent
+ + " numReceivers=" + numReceivers
+ + " nextReceiver=" + r.nextReceiver
+ + " state=" + r.state);
+ broadcastTimeoutLocked(false); // forcibly finish this broadcast
+ forceReceive = true;
+ r.state = BroadcastRecord.IDLE;
+ }
+ }
+
+ if (r.state != BroadcastRecord.IDLE) {
+ if (DEBUG_BROADCAST) Slog.d(TAG,
+ "processNextBroadcast("
+ + mQueueName + ") called when not idle (state="
+ + r.state + ")");
+ return;
+ }
+
+ if (r.receivers == null || r.nextReceiver >= numReceivers
+ || r.resultAbort || forceReceive) {
+ // No more receivers for this broadcast! Send the final
+ // result if requested...
+ if (r.resultTo != null) {
+ try {
+ if (DEBUG_BROADCAST) {
+ int seq = r.intent.getIntExtra("seq", -1);
+ Slog.i(TAG, "Finishing broadcast ["
+ + mQueueName + "] " + r.intent.getAction()
+ + " seq=" + seq + " app=" + r.callerApp);
+ }
+ performReceiveLocked(r.callerApp, r.resultTo,
+ new Intent(r.intent), r.resultCode,
+ r.resultData, r.resultExtras, false, false);
+ // Set this to null so that the reference
+ // (local and remote) isnt kept in the mBroadcastHistory.
+ r.resultTo = null;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure ["
+ + mQueueName + "] sending broadcast result of "
+ + r.intent, e);
+ }
+ }
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+ cancelBroadcastTimeoutLocked();
+
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+ + r);
+
+ // ... and on to the next...
+ addBroadcastToHistoryLocked(r);
+ mOrderedBroadcasts.remove(0);
+ r = null;
+ looped = true;
+ continue;
+ }
+ } while (r == null);
+
+ // Get the next receiver...
+ int recIdx = r.nextReceiver++;
+
+ // Keep track of when this receiver started, and make sure there
+ // is a timeout message pending to kill it if need be.
+ r.receiverTime = SystemClock.uptimeMillis();
+ if (recIdx == 0) {
+ r.dispatchTime = r.receiverTime;
+ r.dispatchClockTime = System.currentTimeMillis();
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+ + mQueueName + "] " + r);
+ }
+ if (! mPendingBroadcastTimeoutMessage) {
+ long timeoutTime = r.receiverTime + mTimeoutPeriod;
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Submitting BROADCAST_TIMEOUT_MSG ["
+ + mQueueName + "] for " + r + " at " + timeoutTime);
+ setBroadcastTimeoutLocked(timeoutTime);
+ }
+
+ Object nextReceiver = r.receivers.get(recIdx);
+ if (nextReceiver instanceof BroadcastFilter) {
+ // Simple case: this is a registered receiver who gets
+ // a direct call.
+ BroadcastFilter filter = (BroadcastFilter)nextReceiver;
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering ordered ["
+ + mQueueName + "] to registered "
+ + filter + ": " + r);
+ deliverToRegisteredReceiverLocked(r, filter, r.ordered);
+ if (r.receiver == null || !r.ordered) {
+ // The receiver has already finished, so schedule to
+ // process the next one.
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+ + mQueueName + "]: ordered="
+ + r.ordered + " receiver=" + r.receiver);
+ r.state = BroadcastRecord.IDLE;
+ scheduleBroadcastsLocked();
+ }
+ return;
+ }
+
+ // Hard case: need to instantiate the receiver, possibly
+ // starting its application process to host it.
+
+ ResolveInfo info =
+ (ResolveInfo)nextReceiver;
+
+ boolean skip = false;
+ int perm = mService.checkComponentPermission(info.activityInfo.permission,
+ r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+ info.activityInfo.exported);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ if (!info.activityInfo.exported) {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ } else {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " requires " + info.activityInfo.permission
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ }
+ skip = true;
+ }
+ if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
+ r.requiredPermission != null) {
+ try {
+ perm = AppGlobals.getPackageManager().
+ checkPermission(r.requiredPermission,
+ info.activityInfo.applicationInfo.packageName);
+ } catch (RemoteException e) {
+ perm = PackageManager.PERMISSION_DENIED;
+ }
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: receiving "
+ + r.intent + " to "
+ + info.activityInfo.applicationInfo.packageName
+ + " requires " + r.requiredPermission
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+ if (r.curApp != null && r.curApp.crashing) {
+ // If the target process is crashing, just skip it.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Skipping deliver ordered ["
+ + mQueueName + "] " + r + " to " + r.curApp
+ + ": process crashing");
+ skip = true;
+ }
+
+ if (skip) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Skipping delivery of ordered ["
+ + mQueueName + "] " + r + " for whatever reason");
+ r.receiver = null;
+ r.curFilter = null;
+ r.state = BroadcastRecord.IDLE;
+ scheduleBroadcastsLocked();
+ return;
+ }
+
+ r.state = BroadcastRecord.APP_RECEIVE;
+ String targetProcess = info.activityInfo.processName;
+ r.curComponent = new ComponentName(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ if (r.callingUid != Process.SYSTEM_UID) {
+ info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, UserId
+ .getUserId(r.callingUid));
+ }
+ r.curReceiver = info.activityInfo;
+ if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
+ Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
+ + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+ + info.activityInfo.applicationInfo.uid);
+ }
+
+ // Broadcast is being executed, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ r.curComponent.getPackageName(), false);
+ } catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + r.curComponent.getPackageName() + ": " + e);
+ }
+
+ // Is this receiver's application already running?
+ ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
+ info.activityInfo.applicationInfo.uid);
+ if (app != null && app.thread != null) {
+ try {
+ app.addPackage(info.activityInfo.packageName);
+ processCurBroadcastLocked(r, app);
+ return;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception when sending broadcast to "
+ + r.curComponent, e);
+ }
+
+ // If a dead object exception was thrown -- fall through to
+ // restart the application.
+ }
+
+ // Not running -- get it started, to be executed when the app comes up.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Need to start app ["
+ + mQueueName + "] " + targetProcess + " for broadcast " + r);
+ if ((r.curApp=mService.startProcessLocked(targetProcess,
+ info.activityInfo.applicationInfo, true,
+ r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
+ "broadcast", r.curComponent,
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
+ == null) {
+ // Ah, this recipient is unavailable. Finish it if necessary,
+ // and mark the broadcast record as ready for the next.
+ Slog.w(TAG, "Unable to launch app "
+ + info.activityInfo.applicationInfo.packageName + "/"
+ + info.activityInfo.applicationInfo.uid + " for broadcast "
+ + r.intent + ": process is bad");
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+ r.state = BroadcastRecord.IDLE;
+ return;
+ }
+
+ mPendingBroadcast = r;
+ mPendingBroadcastRecvIndex = recIdx;
+ }
+ }
+
+ final void setBroadcastTimeoutLocked(long timeoutTime) {
+ if (! mPendingBroadcastTimeoutMessage) {
+ Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
+ mHandler.sendMessageAtTime(msg, timeoutTime);
+ mPendingBroadcastTimeoutMessage = true;
+ }
+ }
+
+ final void cancelBroadcastTimeoutLocked() {
+ if (mPendingBroadcastTimeoutMessage) {
+ mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
+ mPendingBroadcastTimeoutMessage = false;
+ }
+ }
+
+ final void broadcastTimeoutLocked(boolean fromMsg) {
+ if (fromMsg) {
+ mPendingBroadcastTimeoutMessage = false;
+ }
+
+ if (mOrderedBroadcasts.size() == 0) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ BroadcastRecord r = mOrderedBroadcasts.get(0);
+ if (fromMsg) {
+ if (mService.mDidDexOpt) {
+ // Delay timeouts until dexopt finishes.
+ mService.mDidDexOpt = false;
+ long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
+ setBroadcastTimeoutLocked(timeoutTime);
+ return;
+ }
+ if (!mService.mProcessesReady) {
+ // Only process broadcast timeouts if the system is ready. That way
+ // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
+ // to do heavy lifting for system up.
+ return;
+ }
+
+ long timeoutTime = r.receiverTime + mTimeoutPeriod;
+ if (timeoutTime > now) {
+ // We can observe premature timeouts because we do not cancel and reset the
+ // broadcast timeout message after each receiver finishes. Instead, we set up
+ // an initial timeout then kick it down the road a little further as needed
+ // when it expires.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Premature timeout ["
+ + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ + timeoutTime);
+ setBroadcastTimeoutLocked(timeoutTime);
+ return;
+ }
+ }
+
+ Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+ + ", started " + (now - r.receiverTime) + "ms ago");
+ r.receiverTime = now;
+ r.anrCount++;
+
+ // Current receiver has passed its expiration date.
+ if (r.nextReceiver <= 0) {
+ Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
+ return;
+ }
+
+ ProcessRecord app = null;
+ String anrMessage = null;
+
+ Object curReceiver = r.receivers.get(r.nextReceiver-1);
+ Slog.w(TAG, "Receiver during timeout: " + curReceiver);
+ logBroadcastReceiverDiscardLocked(r);
+ if (curReceiver instanceof BroadcastFilter) {
+ BroadcastFilter bf = (BroadcastFilter)curReceiver;
+ if (bf.receiverList.pid != 0
+ && bf.receiverList.pid != ActivityManagerService.MY_PID) {
+ synchronized (mService.mPidsSelfLocked) {
+ app = mService.mPidsSelfLocked.get(
+ bf.receiverList.pid);
+ }
+ }
+ } else {
+ app = r.curApp;
+ }
+
+ if (app != null) {
+ anrMessage = "Broadcast of " + r.intent.toString();
+ }
+
+ if (mPendingBroadcast == r) {
+ mPendingBroadcast = null;
+ }
+
+ // Move on to the next receiver.
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+
+ if (anrMessage != null) {
+ // Post the ANR to the handler since we do not want to process ANRs while
+ // potentially holding our lock.
+ mHandler.post(new AppNotResponding(app, anrMessage));
+ }
+ }
+
+ private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
+ if (r.callingUid < 0) {
+ // This was from a registerReceiver() call; ignore it.
+ return;
+ }
+ System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
+ MAX_BROADCAST_HISTORY-1);
+ r.finishTime = SystemClock.uptimeMillis();
+ mBroadcastHistory[0] = r;
+ }
+
+ final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
+ if (r.nextReceiver > 0) {
+ Object curReceiver = r.receivers.get(r.nextReceiver-1);
+ if (curReceiver instanceof BroadcastFilter) {
+ BroadcastFilter bf = (BroadcastFilter) curReceiver;
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver - 1,
+ System.identityHashCode(bf));
+ } else {
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver - 1,
+ ((ResolveInfo)curReceiver).toString());
+ }
+ } else {
+ Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+ + r);
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver,
+ "NONE");
+ }
+ }
+
+ final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+ if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+ || mPendingBroadcast != null) {
+ boolean printed = false;
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ BroadcastRecord br = mParallelBroadcasts.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ printed = true;
+ pw.println(" Active broadcasts [" + mQueueName + "]:");
+ }
+ pw.println(" Broadcast #" + i + ":");
+ br.dump(pw, " ");
+ }
+ printed = false;
+ needSep = true;
+ for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+ BroadcastRecord br = mOrderedBroadcasts.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
+ }
+ pw.println(" Ordered Broadcast #" + i + ":");
+ mOrderedBroadcasts.get(i).dump(pw, " ");
+ }
+ if (dumpPackage == null || (mPendingBroadcast != null
+ && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Pending broadcast [" + mQueueName + "]:");
+ if (mPendingBroadcast != null) {
+ mPendingBroadcast.dump(pw, " ");
+ } else {
+ pw.println(" (null)");
+ }
+ needSep = true;
+ }
+ }
+
+ boolean printed = false;
+ for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+ BroadcastRecord r = mBroadcastHistory[i];
+ if (r == null) {
+ break;
+ }
+ if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts [" + mQueueName + "]:");
+ printed = true;
+ }
+ if (dumpAll) {
+ pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
+ r.dump(pw, " ");
+ } else {
+ if (i >= 50) {
+ pw.println(" ...");
+ break;
+ }
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ }
+ }
+
+ return needSep;
+ }
+}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 6738e4f..dd560fc 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -59,7 +59,7 @@
IBinder receiver; // who is currently running, null if none.
int state;
int anrCount; // has this broadcast record hit any ANRs?
- ActivityManagerService.BroadcastQueue queue; // the outbound queue handling this broadcast
+ BroadcastQueue queue; // the outbound queue handling this broadcast
static final int IDLE = 0;
static final int APP_RECEIVE = 1;
@@ -162,7 +162,7 @@
}
}
- BroadcastRecord(ActivityManagerService.BroadcastQueue _queue,
+ BroadcastRecord(BroadcastQueue _queue,
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
int _callingPid, int _callingUid, String _requiredPermission,
List _receivers, IIntentReceiver _resultTo, int _resultCode,
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index f6564862..cd72202 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -41,7 +41,7 @@
private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
- private static final int MSG_WRITE = 1;
+ private static final int MSG_WRITE = ActivityManagerService.FIRST_COMPAT_MODE_MSG;
private final Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 3835553..f338cfc 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -20,24 +20,35 @@
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
import java.io.PrintWriter;
+import java.util.HashMap;
import java.util.HashSet;
class ContentProviderRecord extends ContentProviderHolder {
// All attached clients
final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
+ // Handles for non-framework processes supported by this provider
+ HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
+ // Count for external process for which we have no handles.
+ int externalProcessNoHandleCount;
+ final ActivityManagerService service;
final int uid;
final ApplicationInfo appInfo;
final ComponentName name;
- int externals; // number of non-framework processes supported by this provider
ProcessRecord proc; // if non-null, hosting process.
ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
String stringName;
-
- public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai, ComponentName _name) {
+
+ public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
+ ApplicationInfo ai, ComponentName _name) {
super(_info);
+ service = _service;
uid = ai.uid;
appInfo = ai;
name = _name;
@@ -50,6 +61,7 @@
appInfo = cpr.appInfo;
name = cpr.name;
noReleaseNeeded = cpr.noReleaseNeeded;
+ service = cpr.service;
}
public boolean canRunHere(ProcessRecord app) {
@@ -57,6 +69,57 @@
&& (uid == Process.SYSTEM_UID || uid == app.info.uid);
}
+ public void addExternalProcessHandleLocked(IBinder token) {
+ if (token == null) {
+ externalProcessNoHandleCount++;
+ } else {
+ if (externalProcessTokenToHandle == null) {
+ externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>();
+ }
+ ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
+ if (handle == null) {
+ handle = new ExternalProcessHandle(token);
+ externalProcessTokenToHandle.put(token, handle);
+ }
+ handle.mAcquisitionCount++;
+ }
+ }
+
+ public boolean removeExternalProcessHandleLocked(IBinder token) {
+ if (hasExternalProcessHandles()) {
+ boolean hasHandle = false;
+ if (externalProcessTokenToHandle != null) {
+ ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
+ if (handle != null) {
+ hasHandle = true;
+ handle.mAcquisitionCount--;
+ if (handle.mAcquisitionCount == 0) {
+ removeExternalProcessHandleInternalLocked(token);
+ return true;
+ }
+ }
+ }
+ if (!hasHandle) {
+ externalProcessNoHandleCount--;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void removeExternalProcessHandleInternalLocked(IBinder token) {
+ ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
+ handle.unlinkFromOwnDeathLocked();
+ externalProcessTokenToHandle.remove(token);
+ if (externalProcessTokenToHandle.size() == 0) {
+ externalProcessTokenToHandle = null;
+ }
+ }
+
+ public boolean hasExternalProcessHandles() {
+ return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("package=");
pw.print(info.applicationInfo.packageName);
@@ -73,8 +136,9 @@
pw.print("multiprocess="); pw.print(info.multiprocess);
pw.print(" initOrder="); pw.println(info.initOrder);
}
- if (externals != 0) {
- pw.print(prefix); pw.print("externals="); pw.println(externals);
+ if (hasExternalProcessHandles()) {
+ pw.print(prefix); pw.print("externals=");
+ pw.println(externalProcessTokenToHandle.size());
}
if (clients.size() > 0) {
pw.print(prefix); pw.println("Clients:");
@@ -84,6 +148,7 @@
}
}
+ @Override
public String toString() {
if (stringName != null) {
return stringName;
@@ -96,4 +161,35 @@
sb.append('}');
return stringName = sb.toString();
}
+
+ // This class represents a handle from an external process to a provider.
+ private class ExternalProcessHandle implements DeathRecipient {
+ private static final String LOG_TAG = "ExternalProcessHanldle";
+
+ private final IBinder mToken;
+ private int mAcquisitionCount;
+
+ public ExternalProcessHandle(IBinder token) {
+ mToken = token;
+ try {
+ token.linkToDeath(this, 0);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re);
+ }
+ }
+
+ public void unlinkFromOwnDeathLocked() {
+ mToken.unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (service) {
+ if (hasExternalProcessHandles() &&
+ externalProcessTokenToHandle.get(mToken) != null) {
+ removeExternalProcessHandleInternalLocked(mToken);
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 44e7ecc..2021e0d 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -17,17 +17,22 @@
package com.android.server.am;
import android.content.ComponentName;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Process;
+import android.os.RemoteException;
import android.os.UserId;
import android.util.Slog;
import android.util.SparseArray;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
/**
* Keeps track of content providers by authority (name) and class. It separates the mapping by
@@ -153,7 +158,7 @@
}
}
- private HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
+ HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
final int userId = optionalUserId >= 0
? optionalUserId : Binder.getOrigCallingUser();
final HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.get(userId);
@@ -241,4 +246,102 @@
}
}
}
+
+ protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+ int opti, boolean dumpAll) {
+ ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
+
+ if ("all".equals(name)) {
+ synchronized (this) {
+ for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+ providers.add(r1);
+ }
+ }
+ } else {
+ ComponentName componentName = name != null
+ ? ComponentName.unflattenFromString(name) : null;
+ int objectId = 0;
+ if (componentName == null) {
+ // Not a '/' separated full component name; maybe an object ID?
+ try {
+ objectId = Integer.parseInt(name, 16);
+ name = null;
+ componentName = null;
+ } catch (RuntimeException e) {
+ }
+ }
+
+ synchronized (this) {
+ for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+ if (componentName != null) {
+ if (r1.name.equals(componentName)) {
+ providers.add(r1);
+ }
+ } else if (name != null) {
+ if (r1.name.flattenToString().contains(name)) {
+ providers.add(r1);
+ }
+ } else if (System.identityHashCode(r1) == objectId) {
+ providers.add(r1);
+ }
+ }
+ }
+ }
+
+ if (providers.size() <= 0) {
+ return false;
+ }
+
+ boolean needSep = false;
+ for (int i=0; i<providers.size(); i++) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
+ }
+ return true;
+ }
+
+ /**
+ * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
+ * there is a thread associated with the provider.
+ */
+ private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
+ final ContentProviderRecord r, String[] args, boolean dumpAll) {
+ String innerPrefix = prefix + " ";
+ synchronized (this) {
+ pw.print(prefix); pw.print("PROVIDER ");
+ pw.print(r);
+ pw.print(" pid=");
+ if (r.proc != null) pw.println(r.proc.pid);
+ else pw.println("(not running)");
+ if (dumpAll) {
+ r.dump(pw, innerPrefix);
+ }
+ }
+ if (r.proc != null && r.proc.thread != null) {
+ pw.println(" Client:");
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.proc.thread.dumpProvider(
+ tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
+ tp.setBufferPrefix(" ");
+ // Short timeout, since blocking here can
+ // deadlock with the application.
+ tp.go(fd, 2000);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException ex) {
+ pw.println(" Failure while dumping the provider: " + ex);
+ } catch (RemoteException ex) {
+ pw.println(" Got a RemoteException while dumping the service");
+ }
+ }
+ }
+
+
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 38c128c..7169015 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -164,13 +164,9 @@
private static final boolean DEBUG_APP_DIR_OBSERVER = false;
private static final boolean DEBUG_VERIFY = false;
- static final boolean MULTIPLE_APPLICATION_UIDS = true;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
- static final int FIRST_APPLICATION_UID =
- Process.FIRST_APPLICATION_UID;
- static final int MAX_APPLICATION_UIDS = 1000;
private static final boolean GET_CERTIFICATES = true;
@@ -874,18 +870,9 @@
mSettings = new Settings();
mSettings.addSharedUserLPw("android.uid.system",
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.phone",
- MULTIPLE_APPLICATION_UIDS
- ? RADIO_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.log",
- MULTIPLE_APPLICATION_UIDS
- ? LOG_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.nfc",
- MULTIPLE_APPLICATION_UIDS
- ? NFC_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -2274,8 +2261,6 @@
}
}
- final int userId = UserId.getUserId(Binder.getCallingUid());
-
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ActivityInfo ai = getActivityInfo(comp, flags);
@@ -6446,10 +6431,6 @@
// package that we deleted.
if(deletedPkg) {
File restoreFile = new File(deletedPackage.mPath);
- if (restoreFile == null) {
- Slog.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
- return;
- }
// Parse old package
boolean oldOnSd = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 3616aa2..ebf954b 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -200,11 +200,7 @@
return null;
}
s = new SharedUserSetting(name, pkgFlags);
- if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
- s.userId = newUserIdLPw(s);
- } else {
- s.userId = PackageManagerService.FIRST_APPLICATION_UID;
- }
+ s.userId = newUserIdLPw(s);
Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
// < 0 means we couldn't assign a userid; fall out and return
// s, which is currently null
@@ -407,7 +403,7 @@
}
if (sharedUser != null) {
p.userId = sharedUser.userId;
- } else if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+ } else {
// Clone the setting here for disabled system packages
PackageSetting dis = mDisabledSysPackages.get(name);
if (dis != null) {
@@ -430,8 +426,6 @@
// Assign new user id
p.userId = newUserIdLPw(p);
}
- } else {
- p.userId = PackageManagerService.FIRST_APPLICATION_UID;
}
}
if (p.userId < 0) {
@@ -598,13 +592,13 @@
}
private boolean addUserIdLPw(int uid, Object obj, Object name) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS) {
+ if (uid > Process.LAST_APPLICATION_UID) {
return false;
}
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
while (index >= N) {
mUserIds.add(null);
N++;
@@ -629,9 +623,9 @@
}
public Object getUserIdLPr(int uid) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
final int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
return index < N ? mUserIds.get(index) : null;
} else {
return mOtherUserIds.get(uid);
@@ -639,9 +633,9 @@
}
private void removeUserIdLPw(int uid) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
final int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
if (index < N) mUserIds.set(index, null);
} else {
mOtherUserIds.remove(uid);
@@ -649,9 +643,9 @@
}
private void replaceUserIdLPw(int uid, Object obj) {
- if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
final int N = mUserIds.size();
- final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ final int index = uid - Process.FIRST_APPLICATION_UID;
if (index < N) mUserIds.set(index, obj);
} else {
mOtherUserIds.put(uid, obj);
@@ -1898,17 +1892,17 @@
for (int i = 0; i < N; i++) {
if (mUserIds.get(i) == null) {
mUserIds.set(i, obj);
- return PackageManagerService.FIRST_APPLICATION_UID + i;
+ return Process.FIRST_APPLICATION_UID + i;
}
}
// None left?
- if (N >= PackageManagerService.MAX_APPLICATION_UIDS) {
+ if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
return -1;
}
mUserIds.add(obj);
- return PackageManagerService.FIRST_APPLICATION_UID + N;
+ return Process.FIRST_APPLICATION_UID + N;
}
public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() {
@@ -2018,6 +2012,39 @@
return false;
}
+ static final void printFlags(PrintWriter pw, int val, Object[] spec) {
+ pw.print("[ ");
+ for (int i=0; i<spec.length; i+=2) {
+ int mask = (Integer)spec[i];
+ if ((val & mask) != 0) {
+ pw.print(spec[i+1]);
+ pw.print(" ");
+ }
+ }
+ pw.print("]");
+ }
+
+ static final Object[] FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.FLAG_SYSTEM, "SYSTEM",
+ ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE",
+ ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE",
+ ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT",
+ ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST",
+ ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING",
+ ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA",
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP",
+ ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY",
+ ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE",
+ ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP",
+ ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE",
+ ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
+ ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ ApplicationInfo.FLAG_STOPPED, "STOPPED",
+ ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ };
+
void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final Date date = new Date();
@@ -2058,6 +2085,7 @@
pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
pw.print(" versionCode="); pw.println(ps.versionCode);
if (ps.pkg != null) {
+ pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println();
pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 8f51466..ed83fbe 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -46,6 +46,7 @@
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.provider.Settings;
+import android.util.Pair;
import android.util.Slog;
import java.io.File;
@@ -54,7 +55,10 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -88,6 +92,8 @@
// which need debouncing.
private static final int UPDATE_DELAY = 1000;
+ private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+
private UsbHandler mHandler;
private boolean mBootCompleted;
@@ -98,6 +104,7 @@
private final boolean mHasUsbAccessory;
private boolean mUseUsbNotification;
private boolean mAdbEnabled;
+ private Map<String, List<Pair<String, String>>> mOemModeMap;
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
@@ -138,6 +145,8 @@
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
+ readOemUsbOverrideConfig();
+
// create a thread for our Handler
HandlerThread thread = new HandlerThread("UsbDeviceManager",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -259,6 +268,10 @@
// persist.sys.usb.config should never be unset. But if it is, set it to "adb"
// so we have a chance of debugging what happened.
mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
+
+ // Check if USB mode needs to be overridden depending on OEM specific bootmode.
+ mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
+
// sanity check the sys.usb.config system property
// this may be necessary if we crashed while switching USB configurations
String config = SystemProperties.get("sys.usb.config", "none");
@@ -381,7 +394,11 @@
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
- if (functions != null && makeDefault) {
+
+ // Do not update persystent.sys.usb.config if the device is booted up
+ // with OEM specific mode.
+ if (functions != null && makeDefault && !needsOemUsbOverride()) {
+
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
@@ -410,6 +427,10 @@
if (functions == null) {
functions = mDefaultFunctions;
}
+
+ // Override with bootmode specific usb mode if needed
+ functions = processOemUsbOverride(functions);
+
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
@@ -671,6 +692,53 @@
}
}
+ private void readOemUsbOverrideConfig() {
+ String[] configList = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_oemUsbModeOverride);
+
+ if (configList != null) {
+ for (String config: configList) {
+ String[] items = config.split(":");
+ if (items.length == 3) {
+ if (mOemModeMap == null) {
+ mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
+ }
+ List overrideList = mOemModeMap.get(items[0]);
+ if (overrideList == null) {
+ overrideList = new LinkedList<Pair<String, String>>();
+ mOemModeMap.put(items[0], overrideList);
+ }
+ overrideList.add(new Pair<String, String>(items[1], items[2]));
+ }
+ }
+ }
+ }
+
+ private boolean needsOemUsbOverride() {
+ if (mOemModeMap == null) return false;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+ return (mOemModeMap.get(bootMode) != null) ? true : false;
+ }
+
+ private String processOemUsbOverride(String usbFunctions) {
+ if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+
+ List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
+ if (overrides != null) {
+ for (Pair<String, String> pair: overrides) {
+ if (pair.first.equals(usbFunctions)) {
+ Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
+ return pair.second;
+ }
+ }
+ }
+ // return passed in functions as is.
+ return usbFunctions;
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw) {
if (mHandler != null) {
mHandler.dump(fd, pw);
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index a4f0a0c2..56c3519 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -668,25 +668,6 @@
}
@SuppressWarnings("unused")
- public int getMaxEventsPerSecond() {
- int result = 0;
- try {
- result = Integer.parseInt(SystemProperties.get("windowsmgr.max_events_per_sec"));
- } catch (NumberFormatException e) {
- }
- if (result < 1) {
- // This number equates to the refresh rate * 1.5. The rate should be at least
- // equal to the screen refresh rate. We increase the rate by 50% to compensate for
- // the discontinuity between the actual rate that events come in at (they do
- // not necessarily come in constantly and are not handled synchronously).
- // Ideally, we would use Display.getRefreshRate(), but as this does not necessarily
- // return a sensible result, we use '60' as our default assumed refresh rate.
- result = 90;
- }
- return result;
- }
-
- @SuppressWarnings("unused")
public int getPointerLayer() {
return mWindowManagerService.mPolicy.windowTypeToLayerLw(
WindowManager.LayoutParams.TYPE_POINTER)
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 55fb038..04a039f 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import java.io.PrintWriter;
+
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
@@ -96,6 +98,46 @@
final Matrix mTmpMatrix = new Matrix();
final float[] mTmpFloats = new float[9];
+ public void printTo(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
+ pw.print(" mWidth="); pw.print(mWidth);
+ pw.print(" mHeight="); pw.println(mHeight);
+ pw.print(prefix); pw.print("mBlackFrame="); pw.println(mBlackFrame);
+ pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation);
+ pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation);
+ pw.print(" mCurRotation="); pw.println(mCurRotation);
+ pw.print(prefix); pw.print("mOriginalRotation="); pw.print(mOriginalRotation);
+ pw.print(" mOriginalWidth="); pw.print(mOriginalWidth);
+ pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
+ pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
+ pw.print(" mAnimRunning="); pw.print(mAnimRunning);
+ pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
+ pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
+ pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation);
+ pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation);
+ pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation);
+ pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation);
+ pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
+ pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
+ pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mLastRotateExitAnimation=");
+ pw.print(mLastRotateExitAnimation);
+ pw.print(" "); mLastRotateExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mExitTransformation=");
+ mExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mEnterTransformation=");
+ mEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
+ mSnapshotInitialMatrix.printShortString(pw);
+ pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
+ pw.println();
+ }
+
public ScreenRotationAnimation(Context context, SurfaceSession session,
boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
mContext = context;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 04c1c98..80ef0e6 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -142,8 +142,7 @@
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
- implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
- Choreographer.OnAnimateListener {
+ implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
@@ -250,6 +249,7 @@
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+ private static final String SYSTEM_HEADLESS = "ro.config.headless";
/**
* Condition waited on by {@link #reenableKeyguard} to know the call to
@@ -259,6 +259,8 @@
*/
private boolean mKeyguardDisabled = false;
+ private final boolean mHeadless;
+
private static final int ALLOW_DISABLE_YES = 1;
private static final int ALLOW_DISABLE_NO = 0;
private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
@@ -600,6 +602,18 @@
}
private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
+ private final class AnimationRunnable implements Runnable {
+ @Override
+ public void run() {
+ synchronized(mWindowMap) {
+ mAnimationScheduled = false;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+ }
+ final AnimationRunnable mAnimationRunnable = new AnimationRunnable();
+ boolean mAnimationScheduled;
+
final class DragInputEventReceiver extends InputEventReceiver {
public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
@@ -721,7 +735,6 @@
Looper.prepare();
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods, mAllowBootMessages);
- s.mChoreographer.addOnAnimateListener(s);
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_DISPLAY);
android.os.Process.setCanSelfBackground(false);
@@ -789,6 +802,7 @@
mAllowBootMessages = showBootMsgs;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
+ mHeadless = "1".equals(SystemProperties.get(SYSTEM_HEADLESS, "0"));
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
@@ -4889,7 +4903,7 @@
public void performBootTimeout() {
synchronized(mWindowMap) {
- if (mDisplayEnabled) {
+ if (mDisplayEnabled || mHeadless) {
return;
}
Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5057,6 +5071,8 @@
// TODO: more accounting of which pid(s) turned it on, keep count,
// only allow disables from pids which have count on, etc.
public void showStrictModeViolation(boolean on) {
+ if (mHeadless) return;
+
int pid = Binder.getCallingPid();
synchronized(mWindowMap) {
// Ignoring requests to enable the red border from clients
@@ -5435,7 +5451,7 @@
if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
MAX_ANIMATION_DURATION, mTransitionAnimationScale,
mCurDisplayWidth, mCurDisplayHeight)) {
- mChoreographer.scheduleAnimation();
+ scheduleAnimationLocked();
}
}
Surface.setOrientation(0, rotation);
@@ -6361,7 +6377,7 @@
INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result);
+ return reportInjectionResult(result, pid);
}
/**
@@ -6391,7 +6407,7 @@
INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result);
+ return reportInjectionResult(result, pid);
}
/**
@@ -6421,7 +6437,7 @@
INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result);
+ return reportInjectionResult(result, pid);
}
/**
@@ -6442,24 +6458,23 @@
INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result);
+ return reportInjectionResult(result, pid);
}
- private boolean reportInjectionResult(int result) {
+ private boolean reportInjectionResult(int result, int pid) {
switch (result) {
case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
- Slog.w(TAG, "Input event injection permission denied.");
+ Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
throw new SecurityException(
"Injecting to another application requires INJECT_EVENTS permission");
case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
- //Slog.v(TAG, "Input event injection succeeded.");
return true;
case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
- Slog.w(TAG, "Input event injection timed out.");
+ Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
return false;
case InputManager.INPUT_EVENT_INJECTION_FAILED:
default:
- Slog.w(TAG, "Input event injection failed.");
+ Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
return false;
}
}
@@ -6876,7 +6891,7 @@
case FORCE_GC: {
synchronized(mWindowMap) {
- if (mChoreographer.isAnimationScheduled()) {
+ if (mAnimationScheduled) {
// If we are animating, don't do the gc now but
// delay a bit so we don't interrupt the animation.
mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
@@ -7630,6 +7645,8 @@
mInnerFields.mAnimating = true;
} else {
updateRotation = true;
+ mScreenRotationAnimation.kill();
+ mScreenRotationAnimation = null;
}
}
}
@@ -8702,7 +8719,7 @@
mInnerFields.mAnimating = false;
// SECOND LOOP: Execute animations and update visibility of windows.
- updateRotation =
+ updateRotation |=
updateAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
@@ -8972,7 +8989,7 @@
if (needRelayout) {
requestTraversalLocked();
} else if (mInnerFields.mAnimating) {
- mChoreographer.scheduleAnimation();
+ scheduleAnimationLocked();
}
// Finally update all input windows now that the window changes have stabilized.
@@ -9006,11 +9023,6 @@
mTurnOnScreen = false;
}
- if (updateRotation && mScreenRotationAnimation != null) {
- mScreenRotationAnimation.kill();
- mScreenRotationAnimation = null;
- }
-
if (updateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
if (updateRotationUncheckedLocked(false)) {
@@ -9097,10 +9109,10 @@
}
}
- @Override
- public void onAnimate() {
- synchronized(mWindowMap) {
- performLayoutAndPlaceSurfacesLocked();
+ void scheduleAnimationLocked() {
+ if (!mAnimationScheduled) {
+ mChoreographer.postAnimationCallback(mAnimationRunnable);
+ mAnimationScheduled = true;
}
}
@@ -9381,7 +9393,7 @@
}
if (CUSTOM_SCREEN_ROTATION) {
- if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
+ if (mScreenRotationAnimation != null) {
mScreenRotationAnimation.kill();
mScreenRotationAnimation = null;
}
@@ -9420,7 +9432,7 @@
if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
- mChoreographer.scheduleAnimation();
+ scheduleAnimationLocked();
} else {
mScreenRotationAnimation = null;
updateRotation = true;
@@ -9912,11 +9924,15 @@
pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
- pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled);
- pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
- pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
+ if (mScreenRotationAnimation != null) {
+ pw.println(" mScreenRotationAnimation:");
+ mScreenRotationAnimation.printTo(" ", pw);
+ }
+ pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
+ pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
- pw.print(" mNextAppTransition=0x");
+ pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled);
+ pw.print(" mNextAppTransition=0x");
pw.print(Integer.toHexString(mNextAppTransition));
pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6868cf6..b013d27 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1593,7 +1593,7 @@
mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
}
if (requestAnim) {
- mService.mChoreographer.scheduleAnimation();
+ mService.scheduleAnimationLocked();
}
return true;
}
@@ -1634,7 +1634,7 @@
}
}
if (requestAnim) {
- mService.mChoreographer.scheduleAnimation();
+ mService.scheduleAnimationLocked();
}
return true;
}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 6fa5dfa..c63b84d 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -9,6 +9,7 @@
com_android_server_InputWindowHandle.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
+ com_android_server_SerialService.cpp \
com_android_server_SystemServer.cpp \
com_android_server_UsbDeviceManager.cpp \
com_android_server_UsbHostManager.cpp \
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 1cadc4e..ca6f206 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -233,75 +233,75 @@
DIR* dir = opendir(POWER_SUPPLY_PATH);
if (dir == NULL) {
ALOGE("Could not open %s\n", POWER_SUPPLY_PATH);
- return -1;
- }
- while ((entry = readdir(dir))) {
- const char* name = entry->d_name;
+ } else {
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
- // ignore "." and ".."
- if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
- continue;
- }
-
- char buf[20];
- // Look for "type" file in each subdirectory
- snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
- int length = readFromFile(path, buf, sizeof(buf));
- if (length > 0) {
- if (buf[length - 1] == '\n')
- buf[length - 1] = 0;
-
- if (strcmp(buf, "Mains") == 0) {
- snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.acOnlinePath = strdup(path);
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
}
- else if (strcmp(buf, "USB") == 0) {
- snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.usbOnlinePath = strdup(path);
- }
- else if (strcmp(buf, "Battery") == 0) {
- snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryStatusPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryHealthPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryPresentPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryCapacityPath = strdup(path);
- snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0) {
- gPaths.batteryVoltagePath = strdup(path);
- // voltage_now is in microvolts, not millivolts
- gVoltageDivisor = 1000;
- } else {
- snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+ char buf[20];
+ // Look for "type" file in each subdirectory
+ snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
+ int length = readFromFile(path, buf, sizeof(buf));
+ if (length > 0) {
+ if (buf[length - 1] == '\n')
+ buf[length - 1] = 0;
+
+ if (strcmp(buf, "Mains") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
+ gPaths.acOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "USB") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.usbOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "Battery") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryStatusPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryHealthPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryPresentPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryCapacityPath = strdup(path);
+
+ snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
gPaths.batteryVoltagePath = strdup(path);
- }
+ // voltage_now is in microvolts, not millivolts
+ gVoltageDivisor = 1000;
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryVoltagePath = strdup(path);
+ }
- snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0) {
- gPaths.batteryTemperaturePath = strdup(path);
- } else {
- snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
+ snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
gPaths.batteryTemperaturePath = strdup(path);
- }
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTemperaturePath = strdup(path);
+ }
- snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryTechnologyPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTechnologyPath = strdup(path);
+ }
}
}
+ closedir(dir);
}
- closedir(dir);
if (!gPaths.acOnlinePath)
ALOGE("acOnlinePath not found");
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index e163826..5c3e002 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -71,7 +71,6 @@
jmethodID getExcludedDeviceNames;
jmethodID getKeyRepeatTimeout;
jmethodID getKeyRepeatDelay;
- jmethodID getMaxEventsPerSecond;
jmethodID getHoverTapTimeout;
jmethodID getHoverTapSlop;
jmethodID getDoubleTapTimeout;
@@ -586,12 +585,6 @@
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
}
-
- jint maxEventsPerSecond = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.getMaxEventsPerSecond);
- if (!checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) {
- outConfig->maxEventsPerSecond = maxEventsPerSecond;
- }
}
bool NativeInputManager::isKeyRepeatEnabled() {
@@ -1480,9 +1473,6 @@
GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, clazz,
"getLongPressTimeout", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
- "getMaxEventsPerSecond", "()I");
-
GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, clazz,
"getPointerLayer", "()I");
diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h
index af10711..cc3b5ef5 100644
--- a/services/jni/com_android_server_PowerManagerService.h
+++ b/services/jni/com_android_server_PowerManagerService.h
@@ -20,7 +20,7 @@
#include "JNIHelp.h"
#include "jni.h"
-#include <ui/PowerManager.h>
+#include <androidfw/PowerManager.h>
namespace android {
diff --git a/services/jni/com_android_server_SerialService.cpp b/services/jni/com_android_server_SerialService.cpp
new file mode 100644
index 0000000..b889b78
--- /dev/null
+++ b/services/jni/com_android_server_SerialService.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SerialServiceJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android
+{
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
+{
+ const char *pathStr = env->GetStringUTFChars(path, NULL);
+
+ int fd = open(pathStr, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ ALOGE("could not open %s", pathStr);
+ env->ReleaseStringUTFChars(path, pathStr);
+ return NULL;
+ }
+ env->ReleaseStringUTFChars(path, pathStr);
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ if (fileDescriptor == NULL) {
+ return NULL;
+ }
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+
+static JNINativeMethod method_table[] = {
+ { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
+ (void*)android_server_SerialService_open },
+};
+
+int register_android_server_SerialService(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/SerialService");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/SerialService");
+ return -1;
+ }
+
+ clazz = env->FindClass("android/os/ParcelFileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+ "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+ return jniRegisterNativeMethods(env, "com/android/server/SerialService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index c7beb5f..423ebd1 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -27,6 +27,7 @@
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_SerialService(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
@@ -49,6 +50,7 @@
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_PowerManagerService(env);
+ register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index c127fa6..c7cf46e 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -70,6 +70,8 @@
glBindTexture(GL_TEXTURE_2D, mTextureName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
mTexCoords[0] = 0; mTexCoords[1] = v;
mTexCoords[2] = 0; mTexCoords[3] = 0;
mTexCoords[4] = u; mTexCoords[5] = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 40717f4..9e3f548 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1922,6 +1922,8 @@
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vtx);
@@ -2094,6 +2096,8 @@
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vtx);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 5da3d97..8cfdb79 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -292,6 +292,20 @@
}
/**
+ * Translates keypad letters to actual digits (e.g. 1-800-GOOG-411 will
+ * become 1-800-4664-411), and then strips all separators (e.g. 1-800-4664-411 will become
+ * 18004664411).
+ *
+ * @see #convertKeypadLettersToDigits(String)
+ * @see #stripSeparators(String)
+ *
+ * @hide
+ */
+ public static String convertAndStrip(String phoneNumber) {
+ return stripSeparators(convertKeypadLettersToDigits(phoneNumber));
+ }
+
+ /**
* Converts pause and tonewait pause characters
* to Android representation.
* RFC 3601 says pause is 'p' and tonewait is 'w'.
@@ -1438,7 +1452,8 @@
* phoneNumber doesn't have the country code.
* @param defaultCountryIso
* the ISO 3166-1 two letters country code whose convention will
- * be used if the phoneNumberE164 is null or invalid.
+ * be used if the phoneNumberE164 is null or invalid, or if phoneNumber
+ * contains IDD.
* @return the formatted number if the given number has been formatted,
* otherwise, return the given number.
*
@@ -1457,9 +1472,13 @@
if (phoneNumberE164 != null && phoneNumberE164.length() >= 2
&& phoneNumberE164.charAt(0) == '+') {
try {
- PhoneNumber pn = util.parse(phoneNumberE164, defaultCountryIso);
+ // The number to be parsed is in E164 format, so the default region used doesn't
+ // matter.
+ PhoneNumber pn = util.parse(phoneNumberE164, "ZZ");
String regionCode = util.getRegionCodeForNumber(pn);
- if (!TextUtils.isEmpty(regionCode)) {
+ if (!TextUtils.isEmpty(regionCode) &&
+ // This makes sure phoneNumber doesn't contain an IDD
+ normalizeNumber(phoneNumber).indexOf(phoneNumberE164.substring(1)) <= 0) {
defaultCountryIso = regionCode;
}
} catch (NumberParseException e) {
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 5d76484..2b9fb91 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -1040,7 +1040,8 @@
}
}
if (didDisable) {
- if (enabledCount == 0) {
+ if ((enabledCount == 0) || (apnId == APN_DUN_ID)) {
+ mRequestedApnType = Phone.APN_TYPE_DEFAULT;
onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 3fe57ae..6e4dd58 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -95,6 +95,9 @@
Phone.APN_TYPE_MMS,
Phone.APN_TYPE_HIPRI };
+ private String[] mDunApnTypes = {
+ Phone.APN_TYPE_DUN };
+
private static final int mDefaultApnId = DataConnectionTracker.APN_DEFAULT_ID;
/* Constructor */
@@ -121,11 +124,26 @@
createAllDataConnectionList();
broadcastMessenger();
+
+ Context c = mCdmaPhone.getContext();
+ String[] t = c.getResources().getStringArray(
+ com.android.internal.R.array.config_cdma_dun_supported_types);
+ if (t != null && t.length > 0) {
+ ArrayList<String> temp = new ArrayList<String>();
+ for(int i=0; i< t.length; i++) {
+ if (!Phone.APN_TYPE_DUN.equalsIgnoreCase(t[i])) {
+ temp.add(t[i]);
+ }
+ }
+ temp.add(0, Phone.APN_TYPE_DUN);
+ mDunApnTypes = temp.toArray(t);
+ }
+
}
@Override
public void dispose() {
- cleanUpConnection(false, null);
+ cleanUpConnection(false, null, false);
super.dispose();
@@ -282,7 +300,7 @@
* @param tearDown true if the underlying DataConnection should be disconnected.
* @param reason for the clean up.
*/
- private void cleanUpConnection(boolean tearDown, String reason) {
+ private void cleanUpConnection(boolean tearDown, String reason, boolean doAll) {
if (DBG) log("cleanUpConnection: reason: " + reason);
// Clear the reconnect alarm, if set.
@@ -302,9 +320,15 @@
DataConnectionAc dcac =
mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
if (tearDown) {
- if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
- conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE,
- conn.getDataConnectionId(), 0, reason));
+ if (doAll) {
+ if (DBG) log("cleanUpConnection: teardown, conn.tearDownAll");
+ conn.tearDownAll(reason, obtainMessage(EVENT_DISCONNECT_DONE,
+ conn.getDataConnectionId(), 0, reason));
+ } else {
+ if (DBG) log("cleanUpConnection: teardown, conn.tearDown");
+ conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE,
+ conn.getDataConnectionId(), 0, reason));
+ }
notificationDeferred = true;
} else {
if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
@@ -348,8 +372,7 @@
String[] types;
int apnId;
if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) {
- types = new String[1];
- types[0] = Phone.APN_TYPE_DUN;
+ types = mDunApnTypes;
apnId = DataConnectionTracker.APN_DUN_ID;
} else {
types = mDefaultApnTypes;
@@ -587,7 +610,7 @@
@Override
protected void onEnableNewApn() {
// No mRequestedApnType check; only one connection is supported
- cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
+ cleanUpConnection(true, Phone.REASON_APN_SWITCHED, false);
}
/**
@@ -769,13 +792,13 @@
@Override
protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
// No apnId check; only one connection is supported
- cleanUpConnection(tearDown, reason);
+ cleanUpConnection(tearDown, reason, (apnId == APN_DUN_ID));
}
@Override
protected void onCleanUpAllConnections(String cause) {
// Only one CDMA connection is supported
- cleanUpConnection(true, cause);
+ cleanUpConnection(true, cause, false);
}
private void createAllDataConnectionList() {
@@ -821,7 +844,7 @@
notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED);
} else {
if (mState == State.FAILED) {
- cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
+ cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED, false);
mDataConnections.get(0).resetRetryCount();
CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation());
@@ -900,7 +923,7 @@
log("onDataStateChanged: No active connection"
+ "state is CONNECTED, disconnecting/cleanup");
writeEventLogCdmaDataDrop();
- cleanUpConnection(true, null);
+ cleanUpConnection(true, null, false);
return;
}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 5b76272..db670f8 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -512,6 +512,9 @@
public void testFormatNumber() {
assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US"));
+ assertEquals("011 86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("011861088880000", "US"));
+ assertEquals("010 8888 0000", PhoneNumberUtils.formatNumber("01088880000", "CN"));
// formatNumber doesn't format alpha numbers, but keep them as they are.
assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
}
@@ -542,6 +545,16 @@
// Using the phoneNumberE164's country code
assertEquals("(650) 291-0000",
PhoneNumberUtils.formatNumber("6502910000", "+16502910000", "CN"));
+ // Using the default country code for a phone number containing the IDD
+ assertEquals("011 86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "US"));
+ assertEquals("00 86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("00861088880000", "+861088880000", "GB"));
+ assertEquals("+86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("+861088880000", "+861088880000", "GB"));
+ // Wrong default country, so no formatting is done
+ assertEquals("011861088880000",
+ PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "GB"));
// The phoneNumberE164 is null
assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("6502910000", null, "US"));
// The given number has a country code.
@@ -553,7 +566,11 @@
// An invalid Polish number should be left as it is. Note Poland doesn't use '0' as a
// national prefix; therefore, the leading '0' makes the number invalid.
assertEquals("0506128687", PhoneNumberUtils.formatNumber("0506128687", null, "PL"));
+ // Wrong default country, so no formatting is done
+ assertEquals("011861088880000",
+ PhoneNumberUtils.formatNumber("011861088880000", "", "GB"));
}
+
@SmallTest
public void testIsEmergencyNumber() {
// There are two parallel sets of tests here: one for the
@@ -606,4 +623,35 @@
// Brazil.
assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "BR"));
}
+
+ @SmallTest
+ public void testStripSeparators() {
+ // Smoke tests which should never fail.
+ assertEquals("1234567890", PhoneNumberUtils.stripSeparators("1234567890"));
+ assertEquals("911", PhoneNumberUtils.stripSeparators("911"));
+ assertEquals("112", PhoneNumberUtils.stripSeparators("112"));
+
+ // Separators should be removed, while '+' or any other digits should not.
+ assertEquals("+16502910000", PhoneNumberUtils.stripSeparators("+1 (650) 291-0000"));
+
+ // WAIT, PAUSE should *not* be stripped
+ assertEquals("+16502910000,300;",
+ PhoneNumberUtils.stripSeparators("+1 (650) 291-0000, 300;"));
+ }
+
+ @SmallTest
+ public void testConvertAndStrip() {
+ // Smoke tests which should never fail.
+ assertEquals("1234567890", PhoneNumberUtils.convertAndStrip("1234567890"));
+ assertEquals("911", PhoneNumberUtils.convertAndStrip("911"));
+ assertEquals("112", PhoneNumberUtils.convertAndStrip("112"));
+
+ // It should convert keypad characters into digits, and strip separators
+ assertEquals("22233344455566677778889999",
+ PhoneNumberUtils.convertAndStrip("ABC DEF GHI JKL MNO PQR STUV WXYZ"));
+
+ // Test real cases.
+ assertEquals("18004664411", PhoneNumberUtils.convertAndStrip("1-800-GOOG-411"));
+ assertEquals("8002223334", PhoneNumberUtils.convertAndStrip("(800) ABC-DEFG"));
+ }
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0b4fc51..5fab2bb 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -267,6 +267,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void sendBroadcast(Intent intent, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
throw new UnsupportedOperationException();
@@ -333,6 +339,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void unbindService(ServiceConnection conn) {
throw new UnsupportedOperationException();
diff --git a/tests/BiDiTests/res/layout/grid_layout_code.xml b/tests/BiDiTests/res/layout/grid_layout_code.xml
new file mode 100644
index 0000000..87a0ec0
--- /dev/null
+++ b/tests/BiDiTests/res/layout/grid_layout_code.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/grid_layout_code"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/grid_layout_ltr.xml b/tests/BiDiTests/res/layout/grid_layout_ltr.xml
index 46ea658..e320809 100644
--- a/tests/BiDiTests/res/layout/grid_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/grid_layout_ltr.xml
@@ -57,6 +57,27 @@
<EditText
android:ems="8"/>
+ <TextView
+ android:text="You can configure email in just a few steps:"
+ android:textSize="16dip"
+ android:layout_columnSpan="4"
+ android:layout_gravity="start"/>
+
+ <TextView
+ android:text="Email address:"
+ android:layout_gravity="end"/>
+
+ <EditText
+ android:ems="10"/>
+
+ <TextView
+ android:text="Password:"
+ android:layout_column="0"
+ android:layout_gravity="end"/>
+
+ <EditText
+ android:ems="8"/>
+
<Space
android:layout_row="4"
android:layout_column="0"
diff --git a/tests/BiDiTests/res/layout/grid_layout_rtl.xml b/tests/BiDiTests/res/layout/grid_layout_rtl.xml
index 947e13c..6d3aae6 100644
--- a/tests/BiDiTests/res/layout/grid_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/grid_layout_rtl.xml
@@ -57,6 +57,27 @@
<EditText
android:ems="8"/>
+ <TextView
+ android:text="You can configure email in just a few steps:"
+ android:textSize="16dip"
+ android:layout_columnSpan="4"
+ android:layout_gravity="end"/>
+
+ <TextView
+ android:text="Email address:"
+ android:layout_gravity="start"/>
+
+ <EditText
+ android:ems="10"/>
+
+ <TextView
+ android:text="Password:"
+ android:layout_column="0"
+ android:layout_gravity="start"/>
+
+ <EditText
+ android:ems="8"/>
+
<Space
android:layout_row="4"
android:layout_column="0"
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 4d7ace1..c5a1235 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -111,6 +111,8 @@
addItem(result, "Grid LTR", BiDiTestGridLayoutLtr.class, R.id.grid_layout_ltr);
addItem(result, "Grid RTL", BiDiTestGridLayoutRtl.class, R.id.grid_layout_rtl);
addItem(result, "Grid LOC", BiDiTestGridLayoutLocale.class, R.id.grid_layout_locale);
+ addItem(result, "Grid C-LTR", BiDiTestGridLayoutCodeLtr.class, R.id.grid_layout_code);
+ addItem(result, "Grid C-RTL", BiDiTestGridLayoutCodeRtl.class, R.id.grid_layout_code);
addItem(result, "Frame LTR", BiDiTestFrameLayoutLtr.class, R.id.frame_layout_ltr);
addItem(result, "Frame RTL", BiDiTestFrameLayoutRtl.class, R.id.frame_layout_rtl);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
new file mode 100644
index 0000000..2b5e674
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+public class BiDiTestGridLayoutCodeLtr extends Fragment {
+
+ private FrameLayout currentView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = (FrameLayout) inflater.inflate(R.layout.grid_layout_code, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ currentView.addView(create(currentView.getContext()));
+ }
+
+ public static View create(Context context) {
+ GridLayout layout = new GridLayout(context);
+ layout.setUseDefaultMargins(true);
+ layout.setAlignmentMode(ALIGN_BOUNDS);
+ layout.setRowOrderPreserved(false);
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+
+ Spec row1 = spec(0);
+ Spec row2 = spec(1);
+ Spec row3 = spec(2, BASELINE);
+ Spec row4 = spec(3, BASELINE);
+ Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+ Spec row6 = spec(5);
+ Spec row7 = spec(6);
+
+ Spec col1a = spec(0, 4, CENTER);
+ Spec col1b = spec(0, 4, LEFT);
+ Spec col1c = spec(0, RIGHT);
+ Spec col2 = spec(1, START);
+ Spec col3 = spec(2, FILL);
+ Spec col4a = spec(3);
+ Spec col4b = spec(3, FILL);
+
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(32);
+ c.setText("Email setup");
+ layout.addView(c, new GridLayout.LayoutParams(row1, col1a));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(16);
+ c.setText("You can configure email in just a few steps:");
+ layout.addView(c, new GridLayout.LayoutParams(row2, col1b));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Email address:");
+ layout.addView(c, new GridLayout.LayoutParams(row3, col1c));
+ }
+ {
+ EditText c = new EditText(context);
+ c.setEms(10);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ layout.addView(c, new GridLayout.LayoutParams(row3, col2));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Password:");
+ layout.addView(c, new GridLayout.LayoutParams(row4, col1c));
+ }
+ {
+ TextView c = new EditText(context);
+ c.setEms(8);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+ layout.addView(c, new GridLayout.LayoutParams(row4, col2));
+ }
+ {
+ Space c = new Space(context);
+ layout.addView(c, new GridLayout.LayoutParams(row5, col3));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Manual setup");
+ layout.addView(c, new GridLayout.LayoutParams(row6, col4a));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Next");
+ layout.addView(c, new GridLayout.LayoutParams(row7, col4b));
+ }
+
+ return layout;
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
new file mode 100644
index 0000000..3a03c6c
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+public class BiDiTestGridLayoutCodeRtl extends Fragment {
+
+ private FrameLayout currentView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = (FrameLayout) inflater.inflate(R.layout.grid_layout_code, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ currentView.addView(create(currentView.getContext()));
+ }
+
+ public static View create(Context context) {
+ GridLayout layout = new GridLayout(context);
+ layout.setUseDefaultMargins(true);
+ layout.setAlignmentMode(ALIGN_BOUNDS);
+ layout.setRowOrderPreserved(false);
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+
+ Spec row1 = spec(0);
+ Spec row2 = spec(1);
+ Spec row3 = spec(2, BASELINE);
+ Spec row4 = spec(3, BASELINE);
+ Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+ Spec row6 = spec(5);
+ Spec row7 = spec(6);
+
+ Spec col1a = spec(0, 4, CENTER);
+ Spec col1b = spec(0, 4, LEFT);
+ Spec col1c = spec(0, RIGHT);
+ Spec col2 = spec(1, START);
+ Spec col3 = spec(2, FILL);
+ Spec col4a = spec(3);
+ Spec col4b = spec(3, FILL);
+
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(32);
+ c.setText("Email setup");
+ layout.addView(c, new GridLayout.LayoutParams(row1, col1a));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(16);
+ c.setText("You can configure email in just a few steps:");
+ layout.addView(c, new GridLayout.LayoutParams(row2, col1b));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Email address:");
+ layout.addView(c, new GridLayout.LayoutParams(row3, col1c));
+ }
+ {
+ EditText c = new EditText(context);
+ c.setEms(10);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ layout.addView(c, new GridLayout.LayoutParams(row3, col2));
+ }
+ {
+ TextView c = new TextView(context);
+ c.setText("Password:");
+ layout.addView(c, new GridLayout.LayoutParams(row4, col1c));
+ }
+ {
+ TextView c = new EditText(context);
+ c.setEms(8);
+ c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+ layout.addView(c, new GridLayout.LayoutParams(row4, col2));
+ }
+ {
+ Space c = new Space(context);
+ layout.addView(c, new GridLayout.LayoutParams(row5, col3));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Manual setup");
+ layout.addView(c, new GridLayout.LayoutParams(row6, col4a));
+ }
+ {
+ Button c = new Button(context);
+ c.setText("Next");
+ layout.addView(c, new GridLayout.LayoutParams(row7, col4b));
+ }
+
+ return layout;
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index c0ba8cf..83c9c3d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -22,12 +22,12 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Environment;
@@ -36,7 +36,6 @@
import android.util.Log;
import android.view.ViewGroup;
import android.view.Window;
-import android.webkit.CookieManager;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
@@ -904,9 +903,7 @@
settings.setWorkersEnabled(false);
settings.setXSSAuditorEnabled(false);
settings.setPageCacheCapacity(0);
- // this enables cpu upload path (as opposed to gpu upload path)
- // and it's only meant to be a temporary workaround!
- settings.setProperty("enable_cpu_upload_path", "true");
+ settings.setProperty("use_minimal_memory", "false");
}
private WebView mWebView;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index 4037a69..0a868fa 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -21,6 +21,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
+import android.text.TextPaint;
import android.view.View;
@SuppressWarnings({"UnusedDeclaration"})
@@ -39,6 +40,7 @@
private final Paint mScaledPaint;
private final Paint mSkewPaint;
private final Paint mHugePaint;
+ private final TextPaint mEventPaint;
CustomTextView(Context c) {
super(c);
@@ -70,6 +72,11 @@
mHugePaint.setAntiAlias(true);
mHugePaint.setColor(0xff000000);
mHugePaint.setTextSize(300f);
+
+ mEventPaint = new TextPaint();
+ mEventPaint.setFakeBoldText(true);
+ mEventPaint.setAntiAlias(true);
+ mEventPaint.setTextSize(14);
}
@Override
@@ -77,6 +84,8 @@
super.onDraw(canvas);
canvas.drawRGB(255, 255, 255);
+ canvas.drawText("Hello OpenGL renderer!", 300, 20, mEventPaint);
+
mMediumPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mMediumPaint.setStrokeWidth(2.0f);
canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint);
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
index a7987b3..0ffb0e5 100644
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
@@ -25,13 +25,14 @@
p.y = -1.f + ((float)y / gDimY) * 2.f;
float2 t = 0;
+ float2 t2 = t * t;
int iteration = 0;
- while((t.x*t.x + t.y*t.y < 4.f) && (iteration < gMaxIteration)) {
- float2 t2 = t * t;
+ while((t2.x + t2.y < 4.f) && (iteration < gMaxIteration)) {
float xtemp = t2.x - t2.y + p.x;
t.y = 2 * t.x * t.y + p.y;
t.x = xtemp;
iteration++;
+ t2 = t * t;
}
if(iteration >= gMaxIteration) {
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 3615f60..7368260 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -283,6 +283,9 @@
mRadius = MAX_RADIUS;
mScript.set_radius(mRadius);
+ mScript.invoke_filter();
+ mRS.finish();
+
long t = java.lang.System.currentTimeMillis();
mScript.invoke_filter();
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
new file mode 100644
index 0000000..656961c
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
@@ -0,0 +1,8 @@
+varying vec2 varTex0;
+
+void main() {
+ lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb;
+ gl_FragColor.xyz = col0 * UNI_modulate.rgb;
+ gl_FragColor.w = UNI_modulate.a;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index ba70c71..41f664a 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -35,18 +35,22 @@
// Custom shaders
private ProgramFragment mProgFragmentMultitex;
private ProgramFragment mProgFragmentSingletex;
+ private ProgramFragment mProgFragmentSingletexModulate;
private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
int mBenchmarkDimX;
int mBenchmarkDimY;
private ScriptC_fill_test mFillScript;
ScriptField_TestScripts_s.Item[] mTests;
+ ScriptField_FillTestFragData_s mFragData;
private final String[] mNames = {
"Fill screen 10x singletexture",
"Fill screen 10x 3tex multitexture",
"Fill screen 10x blended singletexture",
- "Fill screen 10x blended 3tex multitexture"
+ "Fill screen 10x blended 3tex multitexture",
+ "Fill screen 3x modulate blended singletexture",
+ "Fill screen 1x modulate blended singletexture",
};
public FillTest() {
@@ -88,6 +92,8 @@
addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/);
addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
+ addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/);
+ addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/);
return true;
}
@@ -112,6 +118,14 @@
pfbCustom.setShader(mRes, R.raw.singletexf);
pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
mProgFragmentSingletex = pfbCustom.create();
+
+ pfbCustom = new ProgramFragment.Builder(mRS);
+ pfbCustom.setShader(mRes, R.raw.singletexfm);
+ pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+ mFragData = new ScriptField_FillTestFragData_s(mRS, 1);
+ pfbCustom.addConstant(mFragData.getType());
+ mProgFragmentSingletexModulate = pfbCustom.create();
+ mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0);
}
private Allocation loadTextureARGB(int id) {
@@ -140,6 +154,7 @@
mFillScript.set_gProgVertex(progVertex);
mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex);
+ mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate);
mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS));
mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS));
@@ -150,5 +165,7 @@
mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf));
mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker));
+
+ mFillScript.bind_gFragData(mFragData);
}
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
index 23832d3..281f830 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
@@ -21,6 +21,7 @@
rs_program_vertex gProgVertex;
rs_program_fragment gProgFragmentTexture;
+rs_program_fragment gProgFragmentTextureModulate;
rs_program_fragment gProgFragmentMultitex;
rs_program_store gProgStoreBlendNone;
@@ -41,6 +42,11 @@
} FillTestData;
FillTestData *gData;
+typedef struct FillTestFragData_s {
+ float4 modulate;
+} FillTestFragData;
+FillTestFragData *gFragData;
+
static float gDt = 0.0f;
void init() {
@@ -58,7 +64,7 @@
rsgProgramVertexLoadProjectionMatrix(&proj);
}
-static void displaySingletexFill(bool blend, int quadCount) {
+static void displaySingletexFill(bool blend, int quadCount, bool modulate) {
bindProgramVertexOrtho();
rs_matrix4x4 matrix;
rsMatrixLoadIdentity(&matrix);
@@ -70,9 +76,21 @@
} else {
rsgBindProgramStore(gProgStoreBlendAlpha);
}
- rsgBindProgramFragment(gProgFragmentTexture);
- rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+ if (modulate) {
+ rsgBindProgramFragment(gProgFragmentTextureModulate);
+ rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque);
+
+ gFragData->modulate.r = 0.8f;
+ gFragData->modulate.g = 0.7f;
+ gFragData->modulate.b = 0.8f;
+ gFragData->modulate.a = 0.5f;
+ rsgAllocationSyncAll(rsGetAllocation(gFragData));
+ } else {
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+ }
for (int i = 0; i < quadCount; i ++) {
float startX = 5 * i, startY = 5 * i;
@@ -128,7 +146,10 @@
displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount);
break;
case 1:
- displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount);
+ displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false);
+ break;
+ case 2:
+ displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true);
break;
default:
rsDebug("Wrong test number", 0);
diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk
new file mode 100644
index 0000000..ba4b3c5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/Android.mk
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := SceneGraphTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
new file mode 100644
index 0000000..e8d1e8e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testapp">
+ <uses-permission
+ android:name="android.permission.INTERNET" />
+ <application android:label="SceneGraphTest">
+ <activity android:name="TestApp"
+ android:label="SceneGraphTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="FileSelector"
+ android:label="FileSelector"
+ android:hardwareAccelerated="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
new file mode 100644
index 0000000..494e77a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
new file mode 100644
index 0000000..2fcecb0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
new file mode 100644
index 0000000..a86a754
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
new file mode 100644
index 0000000..5870b1a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
new file mode 100644
index 0000000..7dbe942
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
new file mode 100644
index 0000000..07318ae
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
new file mode 100644
index 0000000..7eef443f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
@@ -0,0 +1,1102 @@
+<?xml version="1.0" ?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+ <asset>
+ <contributor>
+ <author>alexst</author>
+ <authoring_tool>OpenCOLLADA2010</authoring_tool>
+ <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments>
+ <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data>
+ </contributor>
+ <created>2011-09-30T15:31:38</created>
+ <modified>2011-09-30T15:31:38</modified>
+ <unit meter="0.01" name="centimeter" />
+ <up_axis>Y_UP</up_axis>
+ </asset>
+ <library_cameras>
+ <camera id="cameraShape1" name="cameraShape1">
+ <optics>
+ <technique_common>
+ <perspective>
+ <yfov>37.8493</yfov>
+ <aspect_ratio>1.5</aspect_ratio>
+ <znear>1</znear>
+ <zfar>400</zfar>
+ </perspective>
+ </technique_common>
+ </optics>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <film_fit>0</film_fit>
+ <film_fit_offset>0</film_fit_offset>
+ <film_offsetX>0</film_offsetX>
+ <film_offsetY>0</film_offsetY>
+ <horizontal_aperture>3.599993</horizontal_aperture>
+ <lens_squeeze>1</lens_squeeze>
+ <originalMayaNodeId>cameraShape1</originalMayaNodeId>
+ <vertical_aperture>2.399995</vertical_aperture>
+ </technique>
+ </extra>
+ </camera>
+ <camera id="CameraDistShape" name="CameraDistShape">
+ <optics>
+ <technique_common>
+ <perspective>
+ <yfov>37.8493</yfov>
+ <aspect_ratio>1.5</aspect_ratio>
+ <znear>1</znear>
+ <zfar>1000</zfar>
+ </perspective>
+ </technique_common>
+ </optics>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <film_fit>0</film_fit>
+ <film_fit_offset>0</film_fit_offset>
+ <film_offsetX>0</film_offsetX>
+ <film_offsetY>0</film_offsetY>
+ <horizontal_aperture>3.599993</horizontal_aperture>
+ <lens_squeeze>1</lens_squeeze>
+ <originalMayaNodeId>CameraDistShape</originalMayaNodeId>
+ <vertical_aperture>2.399995</vertical_aperture>
+ </technique>
+ </extra>
+ </camera>
+ </library_cameras>
+ <library_materials>
+ <material id="Paint1" name="Paint1">
+ <instance_effect url="#Paint1-fx" />
+ </material>
+ <material id="lambert2" name="lambert2">
+ <instance_effect url="#lambert2-fx" />
+ </material>
+ <material id="Plastic" name="Plastic">
+ <instance_effect url="#Plastic-fx" />
+ </material>
+ <material id="Metal" name="Metal">
+ <instance_effect url="#Metal-fx" />
+ </material>
+ <material id="PlasticCenter" name="PlasticCenter">
+ <instance_effect url="#PlasticCenter-fx" />
+ </material>
+ <material id="PlasticRed" name="PlasticRed">
+ <instance_effect url="#PlasticRed-fx" />
+ </material>
+ <material id="lambert10" name="lambert10">
+ <instance_effect url="#lambert10-fx" />
+ </material>
+ <material id="lambert11" name="lambert11">
+ <instance_effect url="#lambert11-fx" />
+ </material>
+ </library_materials>
+ <library_effects>
+ <effect id="Metal-fx">
+ <profile_COMMON>
+ <newparam sid="file23-surface">
+ <surface type="2D">
+ <init_from>file23</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file23-sampler">
+ <sampler2D>
+ <source>file23-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file23-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="Paint1-fx">
+ <profile_COMMON>
+ <newparam sid="file25-surface">
+ <surface type="2D">
+ <init_from>file25</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file25-sampler">
+ <sampler2D>
+ <source>file25-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file25-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="Plastic-fx">
+ <profile_COMMON>
+ <newparam sid="file24-surface">
+ <surface type="2D">
+ <init_from>file24</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file24-sampler">
+ <sampler2D>
+ <source>file24-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file24-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="PlasticCenter-fx">
+ <profile_COMMON>
+ <newparam sid="file24-surface">
+ <surface type="2D">
+ <init_from>file24</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file24-sampler">
+ <sampler2D>
+ <source>file24-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file24-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="PlasticRed-fx">
+ <profile_COMMON>
+ <newparam sid="file23-surface">
+ <surface type="2D">
+ <init_from>file23</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file23-sampler">
+ <sampler2D>
+ <source>file23-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file23-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="lambert10-fx">
+ <profile_COMMON>
+ <newparam sid="file28-surface">
+ <surface type="2D">
+ <init_from>file28</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file28-sampler">
+ <sampler2D>
+ <source>file28-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file28-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="lambert11-fx">
+ <profile_COMMON>
+ <newparam sid="file29-surface">
+ <surface type="2D">
+ <init_from>file29</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file29-sampler">
+ <sampler2D>
+ <source>file29-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file29-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="lambert2-fx">
+ <profile_COMMON>
+ <newparam sid="file22-surface">
+ <surface type="2D">
+ <init_from>file22</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file22-sampler">
+ <sampler2D>
+ <source>file22-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file22-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ </library_effects>
+ <library_images>
+ <image id="file29" name="file29" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file29</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file25" name="file25" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file25</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file28" name="file28" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file28</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file22" name="file22" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file22</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file24" name="file24" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file24</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file23" name="file23" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file23</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ </library_images>
+ <library_visual_scenes>
+ <visual_scene id="VisualSceneNode" name="orientation_test">
+ <node id="camera1" name="camera1">
+ <translate sid="translate">24.5791 14.1321 31.4654</translate>
+ <rotate sid="rotateZ">0 0 1 0</rotate>
+ <rotate sid="rotateY">0 1 0 42</rotate>
+ <rotate sid="rotateX">1 0 0 -16.2</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_camera url="#cameraShape1" />
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>camera1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="CameraAim" name="CameraAim">
+ <translate sid="translate">0.0209301 3.68542 2.06912</translate>
+ <rotate sid="rotateY">0 1 0 43.2561</rotate>
+ <rotate sid="rotateX">1 0 0 -20</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <node id="CameraDist" name="CameraDist">
+ <translate sid="translate">0 0 45</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_camera url="#CameraDistShape" />
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>CameraDist</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>CameraAim</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere4" name="pSphere4">
+ <translate sid="translate">-9.69237 0 7.70498</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape4">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere4</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere1" name="pSphere1">
+ <translate sid="translate">13.0966 0 5.76254</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape1">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere2" name="pSphere2">
+ <translate sid="translate">21.7661 0 -13.6375</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape2">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere2</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere3" name="pSphere3">
+ <translate sid="translate">-13.862 0 -13.6154</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape3">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere3</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere5" name="pSphere5">
+ <translate sid="translate">31.0862 0 18.5992</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape5">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere5</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube1" name="pCube1">
+ <translate sid="translate">0 0 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape1">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert4SG" target="#lambert2">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="group1" name="group1">
+ <translate sid="translate">0 0 0</translate>
+ <rotate sid="rotateZ">0 0 1 -162.693</rotate>
+ <rotate sid="rotateY">0 1 0 21.3345</rotate>
+ <rotate sid="rotateX">1 0 0 -100.567</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <node id="pSphere6" name="pSphere6">
+ <translate sid="translate">-13.862 0 -13.6154</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape6">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere6</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere7" name="pSphere7">
+ <translate sid="translate">-9.69237 0 7.70498</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape7">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere7</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere8" name="pSphere8">
+ <translate sid="translate">21.7661 0 -13.6375</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape8">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere8</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere9" name="pSphere9">
+ <translate sid="translate">13.0966 0 5.76254</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape9">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere9</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>group1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="group2" name="group2">
+ <translate sid="translate">0 0 0</translate>
+ <rotate sid="rotateZ">0 0 1 45.4017</rotate>
+ <rotate sid="rotateY">0 1 0 79.393</rotate>
+ <rotate sid="rotateX">1 0 0 5.10889</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <node id="pSphere10" name="pSphere10">
+ <translate sid="translate">31.0862 0 18.5992</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape10">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere10</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere11" name="pSphere11">
+ <translate sid="translate">13.0966 0 5.76254</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape11">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere11</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere12" name="pSphere12">
+ <translate sid="translate">7.4784 16.3496 7.36882</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape12">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere12</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere13" name="pSphere13">
+ <translate sid="translate">-9.69237 0 7.70498</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape13">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere13</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere14" name="pSphere14">
+ <translate sid="translate">11.3635 -4.3926 2.21012</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape14">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere14</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere15" name="pSphere15">
+ <translate sid="translate">21.7661 0 -13.6375</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape15">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere15</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere16" name="pSphere16">
+ <translate sid="translate">-9.5945 -8.92317 -5.74901</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape16">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere16</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere17" name="pSphere17">
+ <translate sid="translate">-13.862 0 -13.6154</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape17">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere17</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere18" name="pSphere18">
+ <translate sid="translate">-24.2135 6.497 -5.58935</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape18">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere18</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>group2</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube2" name="pCube2">
+ <translate sid="translate">0 0 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape2">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert8SG" target="#PlasticCenter">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube2</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube3" name="pCube3">
+ <translate sid="translate">15 0 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape3">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert9SG" target="#PlasticRed">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube3</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube4" name="pCube4">
+ <translate sid="translate">0 15 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape4">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert10SG" target="#lambert10">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube4</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube5" name="pCube5">
+ <translate sid="translate">0 0 15</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape5">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert11SG" target="#lambert11">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube5</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ </visual_scene>
+ </library_visual_scenes>
+ <scene>
+ <instance_visual_scene url="#VisualSceneNode" />
+ </scene>
+</COLLADA>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
new file mode 100644
index 0000000..0791045
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
new file mode 100644
index 0000000..320a2a6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
new file mode 100644
index 0000000..f7353fd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
new file mode 100644
index 0000000..9ea30107
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
@@ -0,0 +1,25 @@
+<?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/load_model"
+ android:title="@string/load_model" />
+ <item android:id="@+id/use_blur"
+ android:title="@string/use_blur" />
+</menu>
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
new file mode 100644
index 0000000..fa468cc
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
@@ -0,0 +1,15 @@
+varying vec2 varTex0;
+
+void main() {
+ vec2 blurCoord = varTex0;
+ blurCoord.x = varTex0.x + UNI_blurOffset0;
+ vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.x = varTex0.x + UNI_blurOffset1;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.x = varTex0.x + UNI_blurOffset2;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.x = varTex0.x + UNI_blurOffset3;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+ gl_FragColor = vec4(col * 0.25, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
new file mode 100644
index 0000000..a644a3e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
@@ -0,0 +1,17 @@
+varying vec2 varTex0;
+
+void main() {
+ vec2 blurCoord = varTex0;
+ blurCoord.y = varTex0.y + UNI_blurOffset0;
+ vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.y = varTex0.y + UNI_blurOffset1;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.y = varTex0.y + UNI_blurOffset2;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.y = varTex0.y + UNI_blurOffset3;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+ col = col * 0.25;
+
+ gl_FragColor = vec4(col, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
new file mode 100644
index 0000000..bc824b6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+ gl_Position = ATTRIB_position;
+ varTex0 = ATTRIB_texture0;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
new file mode 100644
index 0000000..5d8938b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
@@ -0,0 +1,19 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = (varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = dot(worldNorm, light0Vec);
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * light0_Diffuse * 1.2;
+ gl_FragColor = col; //vec4(0.0, 1.0, 0.0, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
new file mode 100644
index 0000000..51f0612
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
@@ -0,0 +1,23 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 15.0) * 0.5;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * (textureCube(UNI_Tex1, worldNorm).rgb * 0.5 + vec3(light0_Diffuse));
+ col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
new file mode 100644
index 0000000..893d553
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
@@ -0,0 +1,26 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 150.0) * 0.5;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * light0_Diffuse * 1.1;
+ col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+ float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1);
+ col.xyz = mix(col.xyz, textureCube(UNI_Tex1, -light0R).rgb * 2.4, fresnel);
+ col.w = 0.8;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
new file mode 100644
index 0000000..ceb53bd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
@@ -0,0 +1,22 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 10.0) * 0.5;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * light0_Diffuse * 1.2;
+ col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
new file mode 100644
index 0000000..b253622
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz);
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 10.0) * 0.7;
+
+ vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz);
+ vec3 light1R = reflect(light1Vec, worldNorm);
+ float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0);
+ float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0);
+ float light1_Specular = pow(light1Spec, 10.0) * 0.7;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = UNI_diffuse;
+ col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz +
+ light1_Diffuse * UNI_lightColor_1.xyz);
+ col.xyz += (light0_Specular + light1_Specular);
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
new file mode 100644
index 0000000..f48895c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
new file mode 100644
index 0000000..42b231a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+ vec3 col = texture2D(UNI_Tex0, varTex0).rgb;
+
+ vec3 desat = vec3(0.299, 0.587, 0.114);
+ float lum = dot(desat, col);
+ float stepVal = step(lum, 0.8);
+ col = mix(col, vec3(0.0), stepVal)*0.5;
+
+ gl_FragColor = vec4(col, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
new file mode 100644
index 0000000..1ea234f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+ vec4 objPos = ATTRIB_position;
+ vec4 worldPos = UNI_model * objPos;
+ gl_Position = UNI_viewProj * worldPos;
+
+ mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+ vec3 worldNorm = model3 * ATTRIB_normal;
+
+ varWorldPos = worldPos.xyz;
+ varWorldNormal = worldNorm;
+ varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
new file mode 100644
index 0000000..dd709cf
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+ lowp vec4 col = texture2D(UNI_Tex0, varTex0).rgba;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
new file mode 100644
index 0000000..c916d79
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <skip />
+ <string name="load_model">Load Model</string>
+ <string name="use_blur">Use Blur</string>
+</resources>
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
new file mode 100644
index 0000000..42f2be5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Camera extends SceneGraphBase {
+
+ Transform mTransform;
+
+ ScriptField_Camera_s.Item mData;
+ ScriptField_Camera_s mField;
+
+ public Camera() {
+ mData = new ScriptField_Camera_s.Item();
+ mData.near = 0.1f;
+ mData.far = 1000.0f;
+ mData.horizontalFOV = 60.0f;
+ mData.aspect = 0;
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ if (mField != null) {
+ mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+ public void setFOV(float fov) {
+ mData.horizontalFOV = fov;
+ if (mField != null) {
+ mField.set_horizontalFOV(0, fov, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ public void setNear(float n) {
+ mData.near = n;
+ if (mField != null) {
+ mField.set_near(0, n, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ public void setFar(float f) {
+ mData.far = f;
+ if (mField != null) {
+ mField.set_far(0, f, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ public void setName(String n) {
+ super.setName(n);
+ if (mField != null) {
+ RenderScriptGL rs = SceneManager.getRS();
+ mData.name = getNameAlloc(rs);
+ mField.set_name(0, mData.name, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ ScriptField_Camera_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+
+ if (mTransform == null) {
+ throw new RuntimeException("Cameras without transforms are invalid");
+ }
+
+ mField = new ScriptField_Camera_s(rs, 1);
+
+ mData.transformMatrix = mTransform.getRSData().getAllocation();
+ mData.transformTimestamp = 1;
+ mData.timestamp = 1;
+ mData.isDirty = 1;
+ mData.name = getNameAlloc(rs);
+ mField.set(mData, 0, true);
+
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
new file mode 100644
index 0000000..d954313
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.ScaleComponent;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.HashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import android.renderscript.*;
+import android.util.Log;
+
+public class ColladaParser {
+ static final String TAG = "ColladaParser";
+ Document mDom;
+
+ HashMap<String, LightBase> mLights;
+ HashMap<String, Camera> mCameras;
+ HashMap<String, ArrayList<ShaderParam> > mEffectsParams;
+ HashMap<String, Texture2D> mImages;
+ HashMap<String, Texture2D> mSamplerImageMap;
+ HashMap<String, String> mMeshIdNameMap;
+ Scene mScene;
+
+ String mRootDir;
+
+ String toString(Float3 v) {
+ String valueStr = v.x + " " + v.y + " " + v.z;
+ return valueStr;
+ }
+
+ String toString(Float4 v) {
+ String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;
+ return valueStr;
+ }
+
+ public ColladaParser(){
+ mLights = new HashMap<String, LightBase>();
+ mCameras = new HashMap<String, Camera>();
+ mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();
+ mImages = new HashMap<String, Texture2D>();
+ mMeshIdNameMap = new HashMap<String, String>();
+ }
+
+ public void init(InputStream is, String rootDir) {
+ mLights.clear();
+ mCameras.clear();
+ mEffectsParams.clear();
+
+ mRootDir = rootDir;
+
+ long start = System.currentTimeMillis();
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ mDom = db.parse(is);
+ } catch(ParserConfigurationException e) {
+ e.printStackTrace();
+ } catch(SAXException e) {
+ e.printStackTrace();
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", " Parse time: " + (end - start));
+ exportSceneData();
+ }
+
+ Scene getScene() {
+ return mScene;
+ }
+
+ private void exportSceneData(){
+ mScene = new Scene();
+
+ Element docEle = mDom.getDocumentElement();
+ NodeList nl = docEle.getElementsByTagName("light");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element l = (Element)nl.item(i);
+ convertLight(l);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("camera");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element c = (Element)nl.item(i);
+ convertCamera(c);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("image");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element img = (Element)nl.item(i);
+ convertImage(img);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("effect");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element e = (Element)nl.item(i);
+ convertEffects(e);
+ }
+ }
+
+ // Material is just a link to the effect
+ nl = docEle.getElementsByTagName("material");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element m = (Element)nl.item(i);
+ convertMaterials(m);
+ }
+ }
+
+ // Look through the geometry list and build up a correlation between id's and names
+ nl = docEle.getElementsByTagName("geometry");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element m = (Element)nl.item(i);
+ convertGeometries(m);
+ }
+ }
+
+
+ nl = docEle.getElementsByTagName("visual_scene");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element s = (Element)nl.item(i);
+ getScene(s);
+ }
+ }
+ }
+
+ private void getRenderable(Element shape, Transform t) {
+ String geoURL = shape.getAttribute("url").substring(1);
+ String geoName = mMeshIdNameMap.get(geoURL);
+ if (geoName != null) {
+ geoURL = geoName;
+ }
+ //RenderableGroup group = new RenderableGroup();
+ //group.setName(geoURL.substring(1));
+ //mScene.appendRenderable(group);
+ NodeList nl = shape.getElementsByTagName("instance_material");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element materialRef = (Element)nl.item(i);
+ String meshIndexName = materialRef.getAttribute("symbol");
+ String materialName = materialRef.getAttribute("target");
+
+ Renderable d = new Renderable();
+ d.setMesh(geoURL, meshIndexName);
+ d.setMaterialName(materialName.substring(1));
+ d.setName(geoURL);
+
+ //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);
+
+ d.setTransform(t);
+ //Log.v(TAG, "Set source param " + t.getName());
+
+ // Now find all the parameters that exist on the material
+ ArrayList<ShaderParam> materialParams;
+ materialParams = mEffectsParams.get(materialName.substring(1));
+ for (int pI = 0; pI < materialParams.size(); pI ++) {
+ d.appendSourceParams(materialParams.get(pI));
+ //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());
+ }
+ mScene.appendRenderable(d);
+ //group.appendChildren(d);
+ }
+ }
+ }
+
+ private void updateLight(Element shape, Transform t) {
+ String lightURL = shape.getAttribute("url");
+ // collada uses a uri structure to link things,
+ // but we ignore it for now and do a simple search
+ LightBase light = mLights.get(lightURL.substring(1));
+ if (light != null) {
+ light.setTransform(t);
+ //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());
+ }
+ }
+
+ private void updateCamera(Element shape, Transform t) {
+ String camURL = shape.getAttribute("url");
+ // collada uses a uri structure to link things,
+ // but we ignore it for now and do a simple search
+ Camera cam = mCameras.get(camURL.substring(1));
+ if (cam != null) {
+ cam.setTransform(t);
+ //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());
+ }
+ }
+
+ private void getNode(Element node, Transform parent, String indent) {
+ String name = node.getAttribute("name");
+ String id = node.getAttribute("id");
+ CompoundTransform current = new CompoundTransform();
+ current.setName(name);
+ if (parent != null) {
+ parent.appendChild(current);
+ } else {
+ mScene.appendTransform(current);
+ }
+
+ mScene.addToTransformMap(current);
+
+ //Log.v(TAG, indent + "|");
+ //Log.v(TAG, indent + "[" + name + "]");
+
+ Node childNode = node.getFirstChild();
+ while (childNode != null) {
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element field = (Element)childNode;
+ String fieldName = field.getTagName();
+ String description = field.getAttribute("sid");
+ if (fieldName.equals("translate")) {
+ Float3 value = getFloat3(field);
+ current.addComponent(new TranslateComponent(description, value));
+ //Log.v(TAG, indent + " translate " + description + toString(value));
+ } else if (fieldName.equals("rotate")) {
+ Float4 value = getFloat4(field);
+ //Log.v(TAG, indent + " rotate " + description + toString(value));
+ Float3 axis = new Float3(value.x, value.y, value.z);
+ current.addComponent(new RotateComponent(description, axis, value.w));
+ } else if (fieldName.equals("scale")) {
+ Float3 value = getFloat3(field);
+ //Log.v(TAG, indent + " scale " + description + toString(value));
+ current.addComponent(new ScaleComponent(description, value));
+ } else if (fieldName.equals("instance_geometry")) {
+ getRenderable(field, current);
+ } else if (fieldName.equals("instance_light")) {
+ updateLight(field, current);
+ } else if (fieldName.equals("instance_camera")) {
+ updateCamera(field, current);
+ } else if (fieldName.equals("node")) {
+ getNode(field, current, indent + " ");
+ }
+ }
+ childNode = childNode.getNextSibling();
+ }
+ }
+
+ // This will find the actual texture node, which is sometimes hidden behind a sampler
+ // and sometimes referenced directly
+ Texture2D getTexture(String samplerName) {
+ String texName = samplerName;
+
+ // Check to see if the image file is hidden by a sampler surface link combo
+ Element sampler = mDom.getElementById(samplerName);
+ if (sampler != null) {
+ NodeList nl = sampler.getElementsByTagName("source");
+ if (nl != null && nl.getLength() == 1) {
+ Element ref = (Element)nl.item(0);
+ String surfaceName = getString(ref);
+ if (surfaceName == null) {
+ return null;
+ }
+
+ Element surface = mDom.getElementById(surfaceName);
+ if (surface == null) {
+ return null;
+ }
+ nl = surface.getElementsByTagName("init_from");
+ if (nl != null && nl.getLength() == 1) {
+ ref = (Element)nl.item(0);
+ texName = getString(ref);
+ }
+ }
+ }
+
+ //Log.v(TAG, "Extracted texture name " + texName);
+ return mImages.get(texName);
+ }
+
+ void extractParams(Element fx, ArrayList<ShaderParam> params) {
+ Node paramNode = fx.getFirstChild();
+ while (paramNode != null) {
+ if (paramNode.getNodeType() == Node.ELEMENT_NODE) {
+ String name = paramNode.getNodeName();
+ // Now find what type it is
+ Node typeNode = paramNode.getFirstChild();
+ while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {
+ typeNode = typeNode.getNextSibling();
+ }
+ String paramType = typeNode.getNodeName();
+ Element typeElem = (Element)typeNode;
+ ShaderParam sceneParam = null;
+ if (paramType.equals("color")) {
+ Float4Param f4p = new Float4Param(name);
+ Float4 value = getFloat4(typeElem);
+ f4p.setValue(value);
+ sceneParam = f4p;
+ //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));
+ } else if (paramType.equals("float")) {
+ Float4Param f4p = new Float4Param(name);
+ float value = getFloat(typeElem);
+ f4p.setValue(new Float4(value, value, value, value));
+ sceneParam = f4p;
+ //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);
+ } else if (paramType.equals("texture")) {
+ String samplerName = typeElem.getAttribute("texture");
+ Texture2D tex = getTexture(samplerName);
+ TextureParam texP = new TextureParam(name);
+ texP.setTexture(tex);
+ sceneParam = texP;
+ //Log.v(TAG, "Extracted texture " + tex);
+ }
+ if (sceneParam != null) {
+ params.add(sceneParam);
+ }
+ }
+ paramNode = paramNode.getNextSibling();
+ }
+ }
+
+ private void convertMaterials(Element mat) {
+ String id = mat.getAttribute("id");
+ NodeList nl = mat.getElementsByTagName("instance_effect");
+ if (nl != null && nl.getLength() == 1) {
+ Element ref = (Element)nl.item(0);
+ String url = ref.getAttribute("url");
+ ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));
+ mEffectsParams.put(id, params);
+ }
+ }
+
+ private void convertGeometries(Element geo) {
+ String id = geo.getAttribute("id");
+ String name = geo.getAttribute("name");
+ if (!id.equals(name)) {
+ mMeshIdNameMap.put(id, name);
+ }
+ }
+
+ private void convertEffects(Element fx) {
+ String id = fx.getAttribute("id");
+ ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();
+
+ NodeList nl = fx.getElementsByTagName("newparam");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ field.setIdAttribute("sid", true);
+ }
+ }
+
+ nl = fx.getElementsByTagName("blinn");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "blinn");
+ extractParams(field, params);
+ }
+ }
+ nl = fx.getElementsByTagName("lambert");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "lambert");
+ extractParams(field, params);
+ }
+ }
+ nl = fx.getElementsByTagName("phong");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "phong");
+ extractParams(field, params);
+ }
+ }
+ mEffectsParams.put(id, params);
+ }
+
+ private void convertLight(Element light) {
+ String name = light.getAttribute("name");
+ String id = light.getAttribute("id");
+
+ // Determine type
+ String[] knownTypes = { "point", "spot", "directional" };
+ final int POINT_LIGHT = 0;
+ final int SPOT_LIGHT = 1;
+ final int DIR_LIGHT = 2;
+ int type = -1;
+ for (int i = 0; i < knownTypes.length; i ++) {
+ NodeList nl = light.getElementsByTagName(knownTypes[i]);
+ if (nl != null && nl.getLength() != 0) {
+ type = i;
+ break;
+ }
+ }
+
+ //Log.v(TAG, "Found Light Type " + type);
+
+ LightBase sceneLight = null;
+ switch (type) {
+ case POINT_LIGHT:
+ sceneLight = new PointLight();
+ break;
+ case SPOT_LIGHT: // TODO: finish light types
+ break;
+ case DIR_LIGHT: // TODO: finish light types
+ break;
+ }
+
+ if (sceneLight == null) {
+ return;
+ }
+
+ Float3 color = getFloat3(light, "color");
+ sceneLight.setColor(color.x, color.y, color.z);
+ sceneLight.setName(name);
+ mScene.appendLight(sceneLight);
+ mLights.put(id, sceneLight);
+
+ //Log.v(TAG, "Light " + name + " color " + toString(color));
+ }
+
+ private void convertCamera(Element camera) {
+ String name = camera.getAttribute("name");
+ String id = camera.getAttribute("id");
+ float fov = 30.0f;
+ if (getString(camera, "yfov") != null) {
+ fov = getFloat(camera, "yfov");
+ } else if(getString(camera, "xfov") != null) {
+ float aspect = getFloat(camera, "aspect_ratio");
+ fov = getFloat(camera, "xfov") / aspect;
+ }
+
+ float near = getFloat(camera, "znear");
+ float far = getFloat(camera, "zfar");
+
+ Camera sceneCamera = new Camera();
+ sceneCamera.setFOV(fov);
+ sceneCamera.setNear(near);
+ sceneCamera.setFar(far);
+ sceneCamera.setName(name);
+ mScene.appendCamera(sceneCamera);
+ mCameras.put(id, sceneCamera);
+ }
+
+ private void convertImage(Element img) {
+ String name = img.getAttribute("name");
+ String id = img.getAttribute("id");
+ String file = getString(img, "init_from");
+
+ Texture2D tex = new Texture2D();
+ tex.setFileName(file);
+ tex.setFileDir(mRootDir);
+ mScene.appendTextures(tex);
+ mImages.put(id, tex);
+ }
+
+ private void getScene(Element scene) {
+ String name = scene.getAttribute("name");
+ String id = scene.getAttribute("id");
+
+ Node childNode = scene.getFirstChild();
+ while (childNode != null) {
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ String indent = "";
+ getNode((Element)childNode, null, indent);
+ }
+ childNode = childNode.getNextSibling();
+ }
+ }
+
+ private String getString(Element elem, String name) {
+ String text = null;
+ NodeList nl = elem.getElementsByTagName(name);
+ if (nl != null && nl.getLength() != 0) {
+ text = ((Element)nl.item(0)).getFirstChild().getNodeValue();
+ }
+ return text;
+ }
+
+ private String getString(Element elem) {
+ String text = null;
+ text = elem.getFirstChild().getNodeValue();
+ return text;
+ }
+
+ private int getInt(Element elem, String name) {
+ return Integer.parseInt(getString(elem, name));
+ }
+
+ private float getFloat(Element elem, String name) {
+ return Float.parseFloat(getString(elem, name));
+ }
+
+ private float getFloat(Element elem) {
+ return Float.parseFloat(getString(elem));
+ }
+
+ private Float3 parseFloat3(String valueString) {
+ StringTokenizer st = new StringTokenizer(valueString);
+ float x = Float.parseFloat(st.nextToken());
+ float y = Float.parseFloat(st.nextToken());
+ float z = Float.parseFloat(st.nextToken());
+ return new Float3(x, y, z);
+ }
+
+ private Float4 parseFloat4(String valueString) {
+ StringTokenizer st = new StringTokenizer(valueString);
+ float x = Float.parseFloat(st.nextToken());
+ float y = Float.parseFloat(st.nextToken());
+ float z = Float.parseFloat(st.nextToken());
+ float w = Float.parseFloat(st.nextToken());
+ return new Float4(x, y, z, w);
+ }
+
+ private Float3 getFloat3(Element elem, String name) {
+ String valueString = getString(elem, name);
+ return parseFloat3(valueString);
+ }
+
+ private Float4 getFloat4(Element elem, String name) {
+ String valueString = getString(elem, name);
+ return parseFloat4(valueString);
+ }
+
+ private Float3 getFloat3(Element elem) {
+ String valueString = getString(elem);
+ return parseFloat3(valueString);
+ }
+
+ private Float4 getFloat4(Element elem) {
+ String valueString = getString(elem);
+ return parseFloat4(valueString);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
new file mode 100644
index 0000000..301075e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+
+public class ColladaScene {
+
+ private String modelName;
+ private static String TAG = "ColladaScene";
+ private final int STATE_LAST_FOCUS = 1;
+ boolean mLoadFromSD = false;
+
+ SceneLoadedCallback mCallback;
+
+ public ColladaScene(String name, SceneLoadedCallback cb) {
+ modelName = name;
+ mCallback = cb;
+ }
+
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+
+ mLoadFromSD = SceneManager.isSDCardPath(modelName);
+
+ new ColladaLoaderTask().execute(modelName);
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ Scene mActiveScene;
+
+ private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> {
+ ColladaParser sceneSource;
+ protected Boolean doInBackground(String... names) {
+ String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1);
+ long start = System.currentTimeMillis();
+ sceneSource = new ColladaParser();
+ InputStream is = null;
+ try {
+ if (!mLoadFromSD) {
+ is = mRes.getAssets().open(names[0]);
+ } else {
+ File f = new File(names[0]);
+ is = new BufferedInputStream(new FileInputStream(f));
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Could not open collada file");
+ return new Boolean(false);
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "Stream load time: " + (end - start));
+
+ start = System.currentTimeMillis();
+ sceneSource.init(is, rootDir);
+ end = System.currentTimeMillis();
+ Log.v("TIMER", "Collada parse time: " + (end - start));
+ return new Boolean(true);
+ }
+
+ protected void onPostExecute(Boolean result) {
+ mActiveScene = sceneSource.getScene();
+ if (mCallback != null) {
+ mCallback.mLoadedScene = mActiveScene;
+ mCallback.run();
+ }
+
+ String shortName = modelName.substring(0, modelName.lastIndexOf('.'));
+ new A3DLoaderTask().execute(shortName + ".a3d");
+ }
+ }
+
+ private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> {
+ protected Boolean doInBackground(String... names) {
+ long start = System.currentTimeMillis();
+ FileA3D model;
+ if (!mLoadFromSD) {
+ model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]);
+ } else {
+ model = FileA3D.createFromFile(mRS, names[0]);
+ }
+ int numModels = model.getIndexEntryCount();
+ for (int i = 0; i < numModels; i ++) {
+ FileA3D.IndexEntry entry = model.getIndexEntry(i);
+ if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+ mActiveScene.meshLoaded(entry.getMesh());
+ }
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "A3D load time: " + (end - start));
+ return new Boolean(true);
+ }
+
+ protected void onPostExecute(Boolean result) {
+ }
+ }
+
+}
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
new file mode 100644
index 0000000..d995dd0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Float3;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class CompoundTransform extends Transform {
+
+ public static abstract class Component {
+ String mName;
+ CompoundTransform mParent;
+ int mParentIndex;
+ protected ScriptField_TransformComponent_s.Item mData;
+
+ Component(int type, String name) {
+ mData = new ScriptField_TransformComponent_s.Item();
+ mData.type = type;
+ mName = name;
+ }
+
+ void setNameAlloc() {
+ RenderScriptGL rs = SceneManager.getRS();
+ if (mData.name != null) {
+ return;
+ }
+ mData.name = SceneManager.getCachedAlloc(getName());
+ if (mData.name == null) {
+ mData.name = SceneManager.getStringAsAllocation(rs, getName());
+ SceneManager.cacheAlloc(getName(), mData.name);
+ }
+ }
+
+ ScriptField_TransformComponent_s.Item getRSData() {
+ setNameAlloc();
+ return mData;
+ }
+
+ protected void update() {
+ if (mParent != null) {
+ mParent.updateRSComponent(this);
+ }
+ }
+
+ public String getName() {
+ return mName;
+ }
+ }
+
+ public static class TranslateComponent extends Component {
+ public TranslateComponent(String name, Float3 translate) {
+ super(ScriptC_export.const_Transform_TRANSLATE, name);
+ setValue(translate);
+ }
+ public Float3 getValue() {
+ return new Float3(mData.value.x, mData.value.y, mData.value.z);
+ }
+ public void setValue(Float3 val) {
+ mData.value.x = val.x;
+ mData.value.y = val.y;
+ mData.value.z = val.z;
+ update();
+ }
+ }
+
+ public static class RotateComponent extends Component {
+ public RotateComponent(String name, Float3 axis, float angle) {
+ super(ScriptC_export.const_Transform_ROTATE, name);
+ setAxis(axis);
+ setAngle(angle);
+ }
+ public Float3 getAxis() {
+ return new Float3(mData.value.x, mData.value.y, mData.value.z);
+ }
+ public float getAngle() {
+ return mData.value.w;
+ }
+ public void setAxis(Float3 val) {
+ mData.value.x = val.x;
+ mData.value.y = val.y;
+ mData.value.z = val.z;
+ update();
+ }
+ public void setAngle(float val) {
+ mData.value.w = val;
+ update();
+ }
+ }
+
+ public static class ScaleComponent extends Component {
+ public ScaleComponent(String name, Float3 scale) {
+ super(ScriptC_export.const_Transform_SCALE, name);
+ setValue(scale);
+ }
+ public Float3 getValue() {
+ return new Float3(mData.value.x, mData.value.y, mData.value.z);
+ }
+ public void setValue(Float3 val) {
+ mData.value.x = val.x;
+ mData.value.y = val.y;
+ mData.value.z = val.z;
+ update();
+ }
+ }
+
+ ScriptField_TransformComponent_s mComponentField;
+ public ArrayList<Component> mTransformComponents;
+
+ public CompoundTransform() {
+ mTransformComponents = new ArrayList<Component>();
+ }
+
+ public void addComponent(Component c) {
+ if (c.mParent != null) {
+ throw new IllegalArgumentException("Transform components may not be shared");
+ }
+ c.mParent = this;
+ c.mParentIndex = mTransformComponents.size();
+ mTransformComponents.add(c);
+ updateRSComponentAllocation();
+ }
+
+ public void setComponent(int index, Component c) {
+ if (c.mParent != null) {
+ throw new IllegalArgumentException("Transform components may not be shared");
+ }
+ if (index >= mTransformComponents.size()) {
+ throw new IllegalArgumentException("Invalid component index");
+ }
+ c.mParent = this;
+ c.mParentIndex = index;
+ mTransformComponents.set(index, c);
+ updateRSComponent(c);
+ }
+
+ void updateRSComponent(Component c) {
+ if (mField == null || mComponentField == null) {
+ return;
+ }
+ mComponentField.set(c.getRSData(), c.mParentIndex, true);
+ mField.set_isDirty(0, 1, true);
+ }
+
+ void updateRSComponentAllocation() {
+ if (mField == null) {
+ return;
+ }
+ initLocalData();
+
+ mField.set_components(0, mTransformData.components, false);
+ mField.set_isDirty(0, 1, true);
+ }
+
+ void initLocalData() {
+ RenderScriptGL rs = SceneManager.getRS();
+ int numComponenets = mTransformComponents.size();
+ if (numComponenets > 0) {
+ mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets);
+ for (int i = 0; i < numComponenets; i ++) {
+ Component ith = mTransformComponents.get(i);
+ mComponentField.set(ith.getRSData(), i, false);
+ }
+ mComponentField.copyAll();
+
+ mTransformData.components = mComponentField.getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
new file mode 100644
index 0000000..1502458
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.Scene;
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Element;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Float4Param extends ShaderParam {
+ private static String TAG = "Float4Param";
+
+ LightBase mLight;
+
+ public Float4Param(String name) {
+ super(name);
+ }
+
+ public Float4Param(String name, float x) {
+ super(name);
+ set(x, 0, 0, 0);
+ }
+
+ public Float4Param(String name, float x, float y) {
+ super(name);
+ set(x, y, 0, 0);
+ }
+
+ public Float4Param(String name, float x, float y, float z) {
+ super(name);
+ set(x, y, z, 0);
+ }
+
+ public Float4Param(String name, float x, float y, float z, float w) {
+ super(name);
+ set(x, y, z, w);
+ }
+
+ void set(float x, float y, float z, float w) {
+ mData.float_value.x = x;
+ mData.float_value.y = y;
+ mData.float_value.z = z;
+ mData.float_value.w = w;
+ if (mField != null) {
+ mField.set_float_value(0, mData.float_value, true);
+ }
+ incTimestamp();
+ }
+
+ public void setValue(Float4 v) {
+ set(v.x, v.y, v.z, v.w);
+ }
+
+ public Float4 getValue() {
+ return mData.float_value;
+ }
+
+ public void setLight(LightBase l) {
+ mLight = l;
+ if (mField != null) {
+ mData.light = mLight.getRSData().getAllocation();
+ mField.set_light(0, mData.light, true);
+ }
+ incTimestamp();
+ }
+
+ boolean findLight(String property) {
+ String indexStr = mParamName.substring(property.length() + 1);
+ if (indexStr == null) {
+ Log.e(TAG, "Invalid light index.");
+ return false;
+ }
+ int index = Integer.parseInt(indexStr);
+ if (index == -1) {
+ return false;
+ }
+ Scene parentScene = SceneManager.getInstance().getActiveScene();
+ ArrayList<LightBase> allLights = parentScene.getLights();
+ if (index >= allLights.size()) {
+ return false;
+ }
+ mLight = allLights.get(index);
+ if (mLight == null) {
+ return false;
+ }
+ return true;
+ }
+
+ int getTypeFromName() {
+ int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA;
+ if (mParamName.equalsIgnoreCase(cameraPos)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS;
+ } else if(mParamName.equalsIgnoreCase(cameraDir)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR;
+ } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR;
+ } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS;
+ } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR;
+ }
+ return paramType;
+ }
+
+ void initLocalData() {
+ mData.type = getTypeFromName();
+ if (mCamera != null) {
+ mData.camera = mCamera.getRSData().getAllocation();
+ }
+ if (mLight != null) {
+ mData.light = mLight.getRSData().getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
new file mode 100644
index 0000000..c8cc3ac
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class FragmentShader extends Shader {
+ ProgramFragment mProgram;
+ ScriptField_FragmentShader_s mField;
+
+ public static class Builder {
+
+ FragmentShader mShader;
+ ProgramFragment.Builder mBuilder;
+
+ public Builder(RenderScriptGL rs) {
+ mShader = new FragmentShader();
+ mBuilder = new ProgramFragment.Builder(rs);
+ }
+
+ public Builder setShader(Resources resources, int resourceID) {
+ mBuilder.setShader(resources, resourceID);
+ return this;
+ }
+
+ public Builder setObjectConst(Type type) {
+ mShader.mPerObjConstants = type;
+ return this;
+ }
+
+ public Builder setShaderConst(Type type) {
+ mShader.mPerShaderConstants = type;
+ return this;
+ }
+
+ public Builder addShaderTexture(Program.TextureType texType, String name) {
+ mShader.mShaderTextureNames.add(name);
+ mShader.mShaderTextureTypes.add(texType);
+ return this;
+ }
+
+ public Builder addTexture(Program.TextureType texType, String name) {
+ mShader.mTextureNames.add(name);
+ mShader.mTextureTypes.add(texType);
+ return this;
+ }
+
+ public FragmentShader create() {
+ if (mShader.mPerShaderConstants != null) {
+ mBuilder.addConstant(mShader.mPerShaderConstants);
+ }
+ if (mShader.mPerObjConstants != null) {
+ mBuilder.addConstant(mShader.mPerObjConstants);
+ }
+ for (int i = 0; i < mShader.mTextureTypes.size(); i ++) {
+ mBuilder.addTexture(mShader.mTextureTypes.get(i));
+ }
+ for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) {
+ mBuilder.addTexture(mShader.mShaderTextureTypes.get(i));
+ }
+
+ mShader.mProgram = mBuilder.create();
+ return mShader;
+ }
+ }
+
+ public ProgramFragment getProgram() {
+ return mProgram;
+ }
+
+ ScriptField_ShaderParam_s getTextureParams() {
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+ paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+ int shaderTextureStart = mTextureTypes.size();
+ for (int i = 0; i < mShaderTextureNames.size(); i ++) {
+ ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i));
+ if (sp != null && sp instanceof TextureParam) {
+ TextureParam p = (TextureParam)sp;
+ ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+ paramRS.bufferOffset = shaderTextureStart + i;
+ paramRS.transformTimestamp = 0;
+ paramRS.dataTimestamp = 0;
+ paramRS.data = p.getRSData().getAllocation();
+ paramList.add(paramRS);
+ }
+ }
+
+ ScriptField_ShaderParam_s rsParams = null;
+ int paramCount = paramList.size();
+ if (paramCount != 0) {
+ rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+ for (int i = 0; i < paramCount; i++) {
+ rsParams.set(paramList.get(i), i, false);
+ }
+ rsParams.copyAll();
+ }
+ return rsParams;
+ }
+
+ ScriptField_FragmentShader_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item();
+ item.program = mProgram;
+
+ ScriptField_ShaderParam_s texParams = getTextureParams();
+ if (texParams != null) {
+ item.shaderTextureParams = texParams.getAllocation();
+ }
+
+ linkConstants(rs);
+ if (mPerShaderConstants != null) {
+ item.shaderConst = mConstantBuffer;
+ item.shaderConstParams = mConstantBufferParams.getAllocation();
+ mProgram.bindConstants(item.shaderConst, 0);
+ }
+
+ item.objectConstIndex = -1;
+ if (mPerObjConstants != null) {
+ item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+ }
+
+ mField = new ScriptField_FragmentShader_s(rs, 1);
+ mField.set(item, 0, true);
+ return mField;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
new file mode 100644
index 0000000..8f5e2e7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Float3;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class LightBase extends SceneGraphBase {
+ static final int RS_LIGHT_POINT = 0;
+ static final int RS_LIGHT_DIRECTIONAL = 1;
+
+ ScriptField_Light_s mField;
+ ScriptField_Light_s.Item mFieldData;
+ Transform mTransform;
+ Float4 mColor;
+ float mIntensity;
+ public LightBase() {
+ mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+ mIntensity = 1.0f;
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ updateRSData();
+ }
+
+ public void setColor(float r, float g, float b) {
+ mColor.x = r;
+ mColor.y = g;
+ mColor.z = b;
+ updateRSData();
+ }
+
+ public void setColor(Float3 c) {
+ setColor(c.x, c.y, c.z);
+ }
+
+ public void setIntensity(float i) {
+ mIntensity = i;
+ updateRSData();
+ }
+
+ public void setName(String n) {
+ super.setName(n);
+ updateRSData();
+ }
+
+ protected void updateRSData() {
+ if (mField == null) {
+ return;
+ }
+ RenderScriptGL rs = SceneManager.getRS();
+ mFieldData.transformMatrix = mTransform.getRSData().getAllocation();
+ mFieldData.name = getNameAlloc(rs);
+ mFieldData.color = mColor;
+ mFieldData.intensity = mIntensity;
+
+ initLocalData();
+
+ mField.set(mFieldData, 0, true);
+ }
+
+ abstract void initLocalData();
+
+ ScriptField_Light_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+ if (mField == null) {
+ mField = new ScriptField_Light_s(rs, 1);
+ mFieldData = new ScriptField_Light_s.Item();
+ }
+
+ updateRSData();
+
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
new file mode 100644
index 0000000..6d70bc9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class MatrixTransform extends Transform {
+
+ Matrix4f mLocalMatrix;
+ public MatrixTransform() {
+ mLocalMatrix = new Matrix4f();
+ }
+
+ public void setMatrix(Matrix4f matrix) {
+ mLocalMatrix = matrix;
+ updateRSData();
+ }
+
+ public Matrix4f getMatrix() {
+ return new Matrix4f(mLocalMatrix.getArray());
+ }
+
+ void initLocalData() {
+ mTransformData.localMat = mLocalMatrix;
+ }
+
+ void updateRSData() {
+ if (mField == null) {
+ return;
+ }
+ mField.set_localMat(0, mLocalMatrix, false);
+ mField.set_isDirty(0, 1, true);
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
new file mode 100644
index 0000000..574bafc
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class PointLight extends LightBase {
+ public PointLight() {
+ }
+
+ void initLocalData() {
+ mFieldData.type = RS_LIGHT_POINT;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
new file mode 100644
index 0000000..02fd69d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.util.Log;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+
+/**
+ * @hide
+ */
+public class RenderPass extends SceneGraphBase {
+
+ TextureRenderTarget mColorTarget;
+ Float4 mClearColor;
+ boolean mShouldClearColor;
+
+ TextureRenderTarget mDepthTarget;
+ float mClearDepth;
+ boolean mShouldClearDepth;
+
+ ArrayList<RenderableBase> mObjectsToDraw;
+
+ Camera mCamera;
+
+ ScriptField_RenderPass_s.Item mRsField;
+
+ public RenderPass() {
+ mObjectsToDraw = new ArrayList<RenderableBase>();
+ mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+ mShouldClearColor = true;
+ mClearDepth = 1.0f;
+ mShouldClearDepth = true;
+ }
+
+ public void appendRenderable(Renderable d) {
+ mObjectsToDraw.add(d);
+ }
+
+ public void setCamera(Camera c) {
+ mCamera = c;
+ }
+
+ public void setColorTarget(TextureRenderTarget colorTarget) {
+ mColorTarget = colorTarget;
+ }
+ public void setClearColor(Float4 clearColor) {
+ mClearColor = clearColor;
+ }
+ public void setShouldClearColor(boolean shouldClearColor) {
+ mShouldClearColor = shouldClearColor;
+ }
+
+ public void setDepthTarget(TextureRenderTarget depthTarget) {
+ mDepthTarget = depthTarget;
+ }
+ public void setClearDepth(float clearDepth) {
+ mClearDepth = clearDepth;
+ }
+ public void setShouldClearDepth(boolean shouldClearDepth) {
+ mShouldClearDepth = shouldClearDepth;
+ }
+
+ public ArrayList<RenderableBase> getRenderables() {
+ return mObjectsToDraw;
+ }
+
+ ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) {
+ if (mRsField != null) {
+ return mRsField;
+ }
+
+ mRsField = new ScriptField_RenderPass_s.Item();
+ if (mColorTarget != null) {
+ mRsField.color_target = mColorTarget.getRsData(true).get_texture(0);
+ }
+ if (mColorTarget != null) {
+ mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0);
+ }
+ mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null;
+
+ if (mObjectsToDraw.size() != 0) {
+ Allocation drawableData = Allocation.createSized(rs,
+ Element.ALLOCATION(rs),
+ mObjectsToDraw.size());
+ Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()];
+ for (int i = 0; i < mObjectsToDraw.size(); i ++) {
+ Renderable dI = (Renderable)mObjectsToDraw.get(i);
+ drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+ }
+ drawableData.copyFrom(drawableAllocs);
+ mRsField.objects = drawableData;
+ }
+
+ mRsField.clear_color = mClearColor;
+ mRsField.clear_depth = mClearDepth;
+ mRsField.should_clear_color = mShouldClearColor;
+ mRsField.should_clear_depth = mShouldClearDepth;
+ return mRsField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
new file mode 100644
index 0000000..c08a722
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import android.content.res.Resources;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderState extends SceneGraphBase {
+ VertexShader mVertex;
+ FragmentShader mFragment;
+ ProgramStore mStore;
+ ProgramRaster mRaster;
+
+ ScriptField_RenderState_s mField;
+
+ public RenderState(VertexShader pv,
+ FragmentShader pf,
+ ProgramStore ps,
+ ProgramRaster pr) {
+ mVertex = pv;
+ mFragment = pf;
+ mStore = ps;
+ mRaster = pr;
+ }
+
+ public RenderState(RenderState r) {
+ mVertex = r.mVertex;
+ mFragment = r.mFragment;
+ mStore = r.mStore;
+ mRaster = r.mRaster;
+ }
+
+ public void setProgramVertex(VertexShader pv) {
+ mVertex = pv;
+ updateRSData();
+ }
+
+ public void setProgramFragment(FragmentShader pf) {
+ mFragment = pf;
+ updateRSData();
+ }
+
+ public void setProgramStore(ProgramStore ps) {
+ mStore = ps;
+ updateRSData();
+ }
+
+ public void setProgramRaster(ProgramRaster pr) {
+ mRaster = pr;
+ updateRSData();
+ }
+
+ void updateRSData() {
+ if (mField == null) {
+ return;
+ }
+ ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item();
+ item.pv = mVertex.getRSData().getAllocation();
+ item.pf = mFragment.getRSData().getAllocation();
+ item.ps = mStore;
+ item.pr = mRaster;
+
+ mField.set(item, 0, true);
+ }
+
+ public ScriptField_RenderState_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+
+ mField = new ScriptField_RenderState_s(rs, 1);
+ updateRSData();
+
+ return mField;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
new file mode 100644
index 0000000..9f7ab41
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.android.scenegraph.Float4Param;
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.ShaderParam;
+import com.android.scenegraph.TransformParam;
+
+import android.content.res.Resources;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Element.DataType;
+import android.renderscript.Matrix4f;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Renderable extends RenderableBase {
+ HashMap<String, ShaderParam> mSourceParams;
+
+ RenderState mRenderState;
+ Transform mTransform;
+
+ String mMeshName;
+ String mMeshIndexName;
+
+ public String mMaterialName;
+
+ ScriptField_Renderable_s mField;
+ ScriptField_Renderable_s.Item mData;
+
+ public Renderable() {
+ mSourceParams = new HashMap<String, ShaderParam>();
+ mData = new ScriptField_Renderable_s.Item();
+ }
+
+ public void setCullType(int cull) {
+ mData.cullType = cull;
+ }
+
+ public void setRenderState(RenderState renderState) {
+ mRenderState = renderState;
+ if (mField != null) {
+ RenderScriptGL rs = SceneManager.getRS();
+ updateFieldItem(rs);
+ mField.set(mData, 0, true);
+ }
+ }
+
+ public void setMesh(Mesh mesh) {
+ mData.mesh = mesh;
+ if (mField != null) {
+ mField.set_mesh(0, mData.mesh, true);
+ }
+ }
+
+ public void setMesh(String mesh, String indexName) {
+ mMeshName = mesh;
+ mMeshIndexName = indexName;
+ }
+
+ public void setMaterialName(String name) {
+ mMaterialName = name;
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ if (mField != null) {
+ RenderScriptGL rs = SceneManager.getRS();
+ updateFieldItem(rs);
+ mField.set(mData, 0, true);
+ }
+ }
+
+ public void appendSourceParams(ShaderParam p) {
+ mSourceParams.put(p.getParamName(), p);
+ // Possibly lift this restriction later
+ if (mField != null) {
+ throw new RuntimeException("Can't add source params to objects that are rendering");
+ }
+ }
+
+ public void resolveMeshData(Mesh mesh) {
+ mData.mesh = mesh;
+ if (mData.mesh == null) {
+ Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName);
+ return;
+ }
+ int subIndexCount = mData.mesh.getPrimitiveCount();
+ if (subIndexCount == 1 || mMeshIndexName == null) {
+ mData.meshIndex = 0;
+ } else {
+ for (int i = 0; i < subIndexCount; i ++) {
+ if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) {
+ mData.meshIndex = i;
+ break;
+ }
+ }
+ }
+ if (mField != null) {
+ mField.set(mData, 0, true);
+ }
+ }
+
+ void updateTextures(RenderScriptGL rs) {
+ Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator();
+ int paramIndex = 0;
+ while (allParamsIter.hasNext()) {
+ ShaderParam sp = allParamsIter.next();
+ if (sp instanceof TextureParam) {
+ TextureParam p = (TextureParam)sp;
+ TextureBase tex = p.getTexture();
+ if (tex != null) {
+ mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation();
+ }
+ }
+ }
+ ProgramFragment pf = mRenderState.mFragment.mProgram;
+ mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0;
+ if (mField != null) {
+ mField.set_pf_textures(0, mData.pf_textures, true);
+ mField.set_pf_num_textures(0, mData.pf_num_textures, true);
+ }
+ }
+
+ public void setVisible(boolean vis) {
+ mData.cullType = vis ? 0 : 2;
+ if (mField != null) {
+ mField.set_cullType(0, mData.cullType, true);
+ }
+ }
+
+ ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) {
+ if (mField != null) {
+ return mField;
+ }
+ updateFieldItem(rs);
+ updateTextures(rs);
+
+ mField = new ScriptField_Renderable_s(rs, 1);
+ mField.set(mData, 0, true);
+
+ return mField;
+ }
+
+ void updateVertexConstants(RenderScriptGL rs) {
+ Allocation pvParams = null, vertexConstants = null;
+ VertexShader pv = mRenderState.mVertex;
+ if (pv != null && pv.getObjectConstants() != null) {
+ vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants());
+ Element vertexConst = vertexConstants.getType().getElement();
+ pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams,
+ mTransform).getAllocation();
+ }
+ mData.pv_const = vertexConstants;
+ mData.pv_constParams = pvParams;
+ }
+
+ void updateFragmentConstants(RenderScriptGL rs) {
+ Allocation pfParams = null, fragmentConstants = null;
+ FragmentShader pf = mRenderState.mFragment;
+ if (pf != null && pf.getObjectConstants() != null) {
+ fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants());
+ Element fragmentConst = fragmentConstants.getType().getElement();
+ pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams,
+ mTransform).getAllocation();
+ }
+ mData.pf_const = fragmentConstants;
+ mData.pf_constParams = pfParams;
+ }
+
+ void updateFieldItem(RenderScriptGL rs) {
+ updateVertexConstants(rs);
+ updateFragmentConstants(rs);
+
+ if (mTransform != null) {
+ mData.transformMatrix = mTransform.getRSData().getAllocation();
+ }
+ mData.name = getNameAlloc(rs);
+ mData.render_state = mRenderState.getRSData().getAllocation();
+ mData.bVolInitialized = 0;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
new file mode 100644
index 0000000..74535dd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableBase extends SceneGraphBase {
+ public RenderableBase() {
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
new file mode 100644
index 0000000..590bbab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableGroup extends RenderableBase {
+
+ ArrayList<RenderableBase> mChildren;
+
+ public RenderableGroup() {
+ mChildren = new ArrayList<RenderableBase>();
+ }
+
+ public void appendChildren(RenderableBase d) {
+ mChildren.add(d);
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
new file mode 100644
index 0000000..8c09860
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Scene extends SceneGraphBase {
+ private static String TIMER_TAG = "TIMER";
+
+ CompoundTransform mRootTransforms;
+ HashMap<String, Transform> mTransformMap;
+ ArrayList<RenderPass> mRenderPasses;
+ ArrayList<LightBase> mLights;
+ ArrayList<Camera> mCameras;
+ ArrayList<FragmentShader> mFragmentShaders;
+ ArrayList<VertexShader> mVertexShaders;
+ ArrayList<RenderableBase> mRenderables;
+ HashMap<String, RenderableBase> mRenderableMap;
+ ArrayList<Texture2D> mTextures;
+
+ HashMap<String, ArrayList<Renderable> > mRenderableMeshMap;
+
+ // RS Specific stuff
+ ScriptField_SgTransform mTransformRSData;
+
+ RenderScriptGL mRS;
+ Resources mRes;
+
+ ScriptField_RenderPass_s mRenderPassAlloc;
+
+ public Scene() {
+ mRenderPasses = new ArrayList<RenderPass>();
+ mLights = new ArrayList<LightBase>();
+ mCameras = new ArrayList<Camera>();
+ mFragmentShaders = new ArrayList<FragmentShader>();
+ mVertexShaders = new ArrayList<VertexShader>();
+ mRenderables = new ArrayList<RenderableBase>();
+ mRenderableMap = new HashMap<String, RenderableBase>();
+ mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >();
+ mTextures = new ArrayList<Texture2D>();
+ mRootTransforms = new CompoundTransform();
+ mRootTransforms.setName("_scene_root_");
+ mTransformMap = new HashMap<String, Transform>();
+ }
+
+ public void appendTransform(Transform t) {
+ mRootTransforms.appendChild(t);
+ }
+
+ // temporary
+ public void addToTransformMap(Transform t) {
+ mTransformMap.put(t.getName(), t);
+ }
+
+ public Transform getTransformByName(String name) {
+ return mTransformMap.get(name);
+ }
+
+ public void appendRenderPass(RenderPass p) {
+ mRenderPasses.add(p);
+ }
+
+ public void clearRenderPasses() {
+ mRenderPasses.clear();
+ }
+
+ public void appendLight(LightBase l) {
+ mLights.add(l);
+ }
+
+ public void appendCamera(Camera c) {
+ mCameras.add(c);
+ }
+
+ public void appendShader(FragmentShader f) {
+ mFragmentShaders.add(f);
+ }
+
+ public void appendShader(VertexShader v) {
+ mVertexShaders.add(v);
+ }
+
+ public ArrayList<Camera> getCameras() {
+ return mCameras;
+ }
+
+ public ArrayList<LightBase> getLights() {
+ return mLights;
+ }
+
+ public void appendRenderable(RenderableBase d) {
+ mRenderables.add(d);
+ mRenderableMap.put(d.getName(), d);
+ }
+
+ public ArrayList<RenderableBase> getRenderables() {
+ return mRenderables;
+ }
+
+ public RenderableBase getRenderableByName(String name) {
+ return mRenderableMap.get(name);
+ }
+
+ public void appendTextures(Texture2D tex) {
+ mTextures.add(tex);
+ }
+
+ public void assignRenderStateToMaterial(RenderState renderState, String regex) {
+ Pattern pattern = Pattern.compile(regex);
+ int numRenderables = mRenderables.size();
+ for (int i = 0; i < numRenderables; i ++) {
+ Renderable shape = (Renderable)mRenderables.get(i);
+ Matcher m = pattern.matcher(shape.mMaterialName);
+ if (m.find()) {
+ shape.setRenderState(renderState);
+ }
+ }
+ }
+
+ public void assignRenderState(RenderState renderState) {
+ int numRenderables = mRenderables.size();
+ for (int i = 0; i < numRenderables; i ++) {
+ Renderable shape = (Renderable)mRenderables.get(i);
+ shape.setRenderState(renderState);
+ }
+ }
+
+ public void meshLoaded(Mesh m) {
+ ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName());
+ int numEntries = entries.size();
+ for (int i = 0; i < numEntries; i++) {
+ Renderable d = entries.get(i);
+ d.resolveMeshData(m);
+ }
+ }
+
+ void addToMeshMap(Renderable d) {
+ ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName);
+ if (entries == null) {
+ entries = new ArrayList<Renderable>();
+ mRenderableMeshMap.put(d.mMeshName, entries);
+ }
+ entries.add(d);
+ }
+
+ public void destroyRS() {
+ SceneManager sceneManager = SceneManager.getInstance();
+ mTransformRSData = null;
+ sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+ sceneManager.mRenderLoop.set_gRenderableObjects(null);
+ mRenderPassAlloc = null;
+ sceneManager.mRenderLoop.set_gRenderPasses(null);
+ sceneManager.mRenderLoop.bind_gFrontToBack(null);
+ sceneManager.mRenderLoop.bind_gBackToFront(null);
+ sceneManager.mRenderLoop.set_gCameras(null);
+
+ mTransformMap = null;
+ mRenderPasses = null;
+ mLights = null;
+ mCameras = null;
+ mRenderables = null;
+ mRenderableMap = null;
+ mTextures = null;
+ mRenderableMeshMap = null;
+ mRootTransforms = null;
+ }
+
+ public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) {
+ if (mRenderPasses.size() != 0) {
+ mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size());
+ for (int i = 0; i < mRenderPasses.size(); i ++) {
+ mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false);
+ }
+ mRenderPassAlloc.copyAll();
+ sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation());
+ }
+ }
+
+ private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+ Allocation drawableData = Allocation.createSized(rs,
+ Element.ALLOCATION(rs),
+ mRenderables.size());
+ Allocation[] drawableAllocs = new Allocation[mRenderables.size()];
+ for (int i = 0; i < mRenderables.size(); i ++) {
+ Renderable dI = (Renderable)mRenderables.get(i);
+ addToMeshMap(dI);
+ drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+ }
+ drawableData.copyFrom(drawableAllocs);
+ sceneManager.mRenderLoop.set_gRenderableObjects(drawableData);
+
+ initRenderPassRS(rs, sceneManager);
+ }
+
+ private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+ Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+ mVertexShaders.size());
+ Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()];
+ for (int i = 0; i < mVertexShaders.size(); i ++) {
+ VertexShader sI = mVertexShaders.get(i);
+ shaderAllocs[i] = sI.getRSData().getAllocation();
+ }
+ shaderData.copyFrom(shaderAllocs);
+ sceneManager.mRenderLoop.set_gVertexShaders(shaderData);
+
+ shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mFragmentShaders.size());
+ shaderAllocs = new Allocation[mFragmentShaders.size()];
+ for (int i = 0; i < mFragmentShaders.size(); i ++) {
+ FragmentShader sI = mFragmentShaders.get(i);
+ shaderAllocs[i] = sI.getRSData().getAllocation();
+ }
+ shaderData.copyFrom(shaderAllocs);
+ sceneManager.mRenderLoop.set_gFragmentShaders(shaderData);
+ }
+
+ public void initRS() {
+ SceneManager sceneManager = SceneManager.getInstance();
+ mRS = SceneManager.getRS();
+ mRes = SceneManager.getRes();
+ long start = System.currentTimeMillis();
+ mTransformRSData = mRootTransforms.getRSData();
+ long end = System.currentTimeMillis();
+ Log.v(TIMER_TAG, "Transform init time: " + (end - start));
+
+ start = System.currentTimeMillis();
+
+ sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+ end = System.currentTimeMillis();
+ Log.v(TIMER_TAG, "Script init time: " + (end - start));
+
+ start = System.currentTimeMillis();
+ addDrawables(mRS, mRes, sceneManager);
+ end = System.currentTimeMillis();
+ Log.v(TIMER_TAG, "Renderable init time: " + (end - start));
+
+ addShaders(mRS, mRes, sceneManager);
+
+ Allocation opaqueBuffer = null;
+ if (mRenderables.size() > 0) {
+ opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+ }
+ Allocation transparentBuffer = null;
+ if (mRenderables.size() > 0) {
+ transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+ }
+
+ sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer);
+ sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer);
+
+ if (mCameras.size() > 0) {
+ Allocation cameraData;
+ cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size());
+ Allocation[] cameraAllocs = new Allocation[mCameras.size()];
+ for (int i = 0; i < mCameras.size(); i ++) {
+ cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation();
+ }
+ cameraData.copyFrom(cameraAllocs);
+ sceneManager.mRenderLoop.set_gCameras(cameraData);
+ }
+
+ if (mLights.size() > 0) {
+ Allocation lightData = Allocation.createSized(mRS,
+ Element.ALLOCATION(mRS),
+ mLights.size());
+ Allocation[] lightAllocs = new Allocation[mLights.size()];
+ for (int i = 0; i < mLights.size(); i ++) {
+ lightAllocs[i] = mLights.get(i).getRSData().getAllocation();
+ }
+ lightData.copyFrom(lightAllocs);
+ sceneManager.mRenderLoop.set_gLights(lightData);
+ }
+ }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
new file mode 100644
index 0000000..412ffbf
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class SceneGraphBase {
+ String mName;
+ Allocation mNameAlloc;
+ public void setName(String n) {
+ mName = n;
+ mNameAlloc = null;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ Allocation getNameAlloc(RenderScriptGL rs) {
+ if (mNameAlloc == null) {
+ mNameAlloc = SceneManager.getStringAsAllocation(rs, getName());
+ }
+ return mNameAlloc;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
new file mode 100644
index 0000000..f77f483
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.Camera;
+import com.android.scenegraph.MatrixTransform;
+import com.android.scenegraph.Scene;
+import com.android.testapp.R;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Type.Builder;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * @hide
+ */
+public class SceneManager extends SceneGraphBase {
+
+ HashMap<String, Allocation> mAllocationMap;
+
+ ScriptC_render mRenderLoop;
+ ScriptC mCameraScript;
+ ScriptC mLightScript;
+ ScriptC mObjectParamsScript;
+ ScriptC mFragmentParamsScript;
+ ScriptC mVertexParamsScript;
+ ScriptC mCullScript;
+ ScriptC_transform mTransformScript;
+ ScriptC_export mExportScript;
+
+ RenderScriptGL mRS;
+ Resources mRes;
+ Mesh mQuad;
+ int mWidth;
+ int mHeight;
+
+ Scene mActiveScene;
+ private static SceneManager sSceneManager;
+
+ private Allocation sDefault2D;
+ private Allocation sDefaultCube;
+
+ private static Allocation getDefault(boolean isCube) {
+ final int dimension = 4;
+ final int bytesPerPixel = 4;
+ int arraySize = dimension * dimension * bytesPerPixel;
+
+ RenderScriptGL rs = sSceneManager.mRS;
+ Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+ b.setX(dimension).setY(dimension);
+ if (isCube) {
+ b.setFaces(true);
+ arraySize *= 6;
+ }
+ Type bitmapType = b.create();
+
+ Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
+ int usage = Allocation.USAGE_GRAPHICS_TEXTURE;
+ Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage);
+
+ byte imageData[] = new byte[arraySize];
+ defaultImage.copyFrom(imageData);
+ return defaultImage;
+ }
+
+ static Allocation getDefaultTex2D() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ if (sSceneManager.sDefault2D == null) {
+ sSceneManager.sDefault2D = getDefault(false);
+ }
+ return sSceneManager.sDefault2D;
+ }
+
+ static Allocation getDefaultTexCube() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ if (sSceneManager.sDefaultCube == null) {
+ sSceneManager.sDefaultCube = getDefault(true);
+ }
+ return sSceneManager.sDefaultCube;
+ }
+
+ public static boolean isSDCardPath(String path) {
+ int sdCardIndex = path.indexOf("sdcard/");
+ // We are looking for /sdcard/ or sdcard/
+ if (sdCardIndex == 0 || sdCardIndex == 1) {
+ return true;
+ }
+ sdCardIndex = path.indexOf("mnt/sdcard/");
+ if (sdCardIndex == 0 || sdCardIndex == 1) {
+ return true;
+ }
+ return false;
+ }
+
+ static Bitmap loadBitmap(String name, Resources res) {
+ InputStream is = null;
+ boolean loadFromSD = isSDCardPath(name);
+ try {
+ if (!loadFromSD) {
+ is = res.getAssets().open(name);
+ } else {
+ File f = new File(name);
+ is = new BufferedInputStream(new FileInputStream(f));
+ }
+ } catch (IOException e) {
+ Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+ return null;
+ }
+
+ Bitmap b = BitmapFactory.decodeStream(is);
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+ }
+ return b;
+ }
+
+ public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
+ Bitmap b = loadBitmap(name, res);
+ if (b == null) {
+ return null;
+ }
+ return Allocation.createCubemapFromBitmap(rs, b,
+ MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ }
+
+ public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
+ Bitmap b = loadBitmap(name, res);
+ if (b == null) {
+ return null;
+ }
+ return Allocation.createFromBitmap(rs, b,
+ Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ }
+
+ public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+ ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+ builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+ builder.setDitherEnabled(false);
+ builder.setDepthMaskEnabled(false);
+ return builder.create();
+ }
+
+ static Allocation getStringAsAllocation(RenderScript rs, String str) {
+ if (str == null) {
+ return null;
+ }
+ if (str.length() == 0) {
+ return null;
+ }
+ byte[] allocArray = null;
+ byte[] nullChar = new byte[1];
+ nullChar[0] = 0;
+ try {
+ allocArray = str.getBytes("UTF-8");
+ Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+ allocArray.length + 1,
+ Allocation.USAGE_SCRIPT);
+ alloc.copy1DRangeFrom(0, allocArray.length, allocArray);
+ alloc.copy1DRangeFrom(allocArray.length, 1, nullChar);
+ return alloc;
+ }
+ catch (Exception e) {
+ throw new RSRuntimeException("Could not convert string to utf-8.");
+ }
+ }
+
+ static Allocation getCachedAlloc(String str) {
+ if (sSceneManager == null) {
+ throw new RuntimeException("Scene manager not initialized");
+ }
+ return sSceneManager.mAllocationMap.get(str);
+ }
+
+ static void cacheAlloc(String str, Allocation alloc) {
+ if (sSceneManager == null) {
+ throw new RuntimeException("Scene manager not initialized");
+ }
+ sSceneManager.mAllocationMap.put(str, alloc);
+ }
+
+ public static class SceneLoadedCallback implements Runnable {
+ public Scene mLoadedScene;
+ public String mName;
+ public void run() {
+ }
+ }
+
+ public Scene getActiveScene() {
+ return mActiveScene;
+ }
+
+ public void setActiveScene(Scene s) {
+ mActiveScene = s;
+
+ // Do some sanity checking
+ if (mActiveScene.getCameras().size() == 0) {
+ Matrix4f camPos = new Matrix4f();
+ camPos.translate(0, 0, 10);
+ MatrixTransform cameraTransform = new MatrixTransform();
+ cameraTransform.setName("_DefaultCameraTransform");
+ cameraTransform.setMatrix(camPos);
+ mActiveScene.appendTransform(cameraTransform);
+ Camera cam = new Camera();
+ cam.setName("_DefaultCamera");
+ cam.setTransform(cameraTransform);
+ mActiveScene.appendCamera(cam);
+ }
+ }
+
+ static RenderScriptGL getRS() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ return sSceneManager.mRS;
+ }
+
+ static Resources getRes() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ return sSceneManager.mRes;
+ }
+
+ public static SceneManager getInstance() {
+ if (sSceneManager == null) {
+ sSceneManager = new SceneManager();
+ }
+ return sSceneManager;
+ }
+
+ protected SceneManager() {
+ }
+
+ public void loadModel(String name, SceneLoadedCallback cb) {
+ ColladaScene scene = new ColladaScene(name, cb);
+ scene.init(mRS, mRes);
+ }
+
+ public Mesh getScreenAlignedQuad() {
+ if (mQuad != null) {
+ return mQuad;
+ }
+
+ Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+ 3, Mesh.TriangleMeshBuilder.TEXTURE_0);
+
+ tmb.setTexture(0.0f, 1.0f);
+ tmb.addVertex(-1.0f, 1.0f, 1.0f);
+
+ tmb.setTexture(0.0f, 0.0f);
+ tmb.addVertex(-1.0f, -1.0f, 1.0f);
+
+ tmb.setTexture(1.0f, 0.0f);
+ tmb.addVertex(1.0f, -1.0f, 1.0f);
+
+ tmb.setTexture(1.0f, 1.0f);
+ tmb.addVertex(1.0f, 1.0f, 1.0f);
+
+ tmb.addTriangle(0, 1, 2);
+ tmb.addTriangle(2, 3, 0);
+
+ mQuad = tmb.create(true);
+ return mQuad;
+ }
+
+ public Renderable getRenderableQuad(String name, RenderState state) {
+ Renderable quad = new Renderable();
+ quad.setTransform(new MatrixTransform());
+ quad.setMesh(getScreenAlignedQuad());
+ quad.setName(name);
+ quad.setRenderState(state);
+ quad.setCullType(1);
+ return quad;
+ }
+
+ public void initRS(RenderScriptGL rs, Resources res, int w, int h) {
+ mRS = rs;
+ mRes = res;
+ mAllocationMap = new HashMap<String, Allocation>();
+
+ mExportScript = new ScriptC_export(rs, res, R.raw.export);
+
+ mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
+ mTransformScript.set_gTransformScript(mTransformScript);
+
+ mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
+ mLightScript = new ScriptC_light(rs, res, R.raw.light);
+ mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params);
+ mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params);
+ mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params);
+ mCullScript = new ScriptC_cull(rs, res, R.raw.cull);
+
+ mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
+ mRenderLoop.set_gTransformScript(mTransformScript);
+ mRenderLoop.set_gCameraScript(mCameraScript);
+ mRenderLoop.set_gLightScript(mLightScript);
+ mRenderLoop.set_gObjectParamsScript(mObjectParamsScript);
+ mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript);
+ mRenderLoop.set_gVertexParamsScript(mVertexParamsScript);
+ mRenderLoop.set_gCullScript(mCullScript);
+
+ mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+ }
+
+ public ScriptC getRenderLoop() {
+ return mRenderLoop;
+ }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
new file mode 100644
index 0000000..4975114
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneGraphBase;
+import com.android.scenegraph.ShaderParam;
+
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Shader extends SceneGraphBase {
+ protected Type mPerObjConstants;
+ protected Type mPerShaderConstants;
+
+ protected HashMap<String, ShaderParam> mSourceParams;
+ protected ArrayList<String> mShaderTextureNames;
+ protected ArrayList<Program.TextureType > mShaderTextureTypes;
+ protected ArrayList<String> mTextureNames;
+ protected ArrayList<Program.TextureType > mTextureTypes;
+
+ protected Allocation mConstantBuffer;
+ protected ScriptField_ShaderParam_s mConstantBufferParams;
+
+ public Shader() {
+ mSourceParams = new HashMap<String, ShaderParam>();
+ mShaderTextureNames = new ArrayList<String>();
+ mShaderTextureTypes = new ArrayList<Program.TextureType>();
+ mTextureNames = new ArrayList<String>();
+ mTextureTypes = new ArrayList<Program.TextureType>();
+ }
+
+ public void appendSourceParams(ShaderParam p) {
+ mSourceParams.put(p.getParamName(), p);
+ }
+
+ public Type getObjectConstants() {
+ return mPerObjConstants;
+ }
+
+ public Type getShaderConstants() {
+ return mPerObjConstants;
+ }
+
+ void linkConstants(RenderScriptGL rs) {
+ if (mPerShaderConstants == null) {
+ return;
+ }
+
+ Element constElem = mPerShaderConstants.getElement();
+ mConstantBufferParams = ShaderParam.fillInParams(constElem, mSourceParams, null);
+
+ mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
new file mode 100644
index 0000000..8dea535
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.Transform;
+
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class ShaderParam extends SceneGraphBase {
+
+ static final String cameraPos = "cameraPos";
+ static final String cameraDir = "cameraDir";
+
+ static final String lightColor = "lightColor";
+ static final String lightPos = "lightPos";
+ static final String lightDir = "lightDir";
+
+ static final String view = "view";
+ static final String proj = "proj";
+ static final String viewProj = "viewProj";
+ static final String model = "model";
+ static final String modelView = "modelView";
+ static final String modelViewProj = "modelViewProj";
+
+ static final long sMaxTimeStamp = 0xffffffffL;
+
+ ScriptField_ShaderParamData_s.Item mData;
+ ScriptField_ShaderParamData_s mField;
+
+ String mParamName;
+ Camera mCamera;
+
+ static ScriptField_ShaderParam_s fillInParams(Element constantElem,
+ HashMap<String, ShaderParam> sourceParams,
+ Transform transform) {
+ RenderScriptGL rs = SceneManager.getRS();
+ ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+ paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+ int subElemCount = constantElem.getSubElementCount();
+ for (int i = 0; i < subElemCount; i ++) {
+ String inputName = constantElem.getSubElementName(i);
+ int offset = constantElem.getSubElementOffsetBytes(i);
+
+ ShaderParam matchingParam = sourceParams.get(inputName);
+ Element subElem = constantElem.getSubElement(i);
+ // Make one if it's not there
+ if (matchingParam == null) {
+ if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+ matchingParam = new Float4Param(inputName);
+ } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
+ TransformParam trParam = new TransformParam(inputName);
+ trParam.setTransform(transform);
+ matchingParam = trParam;
+ }
+ }
+ ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+ paramRS.bufferOffset = offset;
+ paramRS.transformTimestamp = 0;
+ paramRS.dataTimestamp = 0;
+ paramRS.data = matchingParam.getRSData().getAllocation();
+ if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+ paramRS.float_vecSize = subElem.getVectorSize();
+ }
+
+ paramList.add(paramRS);
+ }
+
+ ScriptField_ShaderParam_s rsParams = null;
+ int paramCount = paramList.size();
+ if (paramCount != 0) {
+ rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+ for (int i = 0; i < paramCount; i++) {
+ rsParams.set(paramList.get(i), i, false);
+ }
+ rsParams.copyAll();
+ }
+ return rsParams;
+ }
+
+ public ShaderParam(String name) {
+ mParamName = name;
+ mData = new ScriptField_ShaderParamData_s.Item();
+ }
+
+ public String getParamName() {
+ return mParamName;
+ }
+
+ public void setCamera(Camera c) {
+ mCamera = c;
+ if (mField != null) {
+ mData.camera = mCamera.getRSData().getAllocation();
+ mField.set_camera(0, mData.camera, true);
+ }
+ }
+
+ protected void incTimestamp() {
+ if (mField != null) {
+ mData.timestamp ++;
+ mData.timestamp %= sMaxTimeStamp;
+ mField.set_timestamp(0, mData.timestamp, true);
+ }
+ }
+
+ abstract void initLocalData();
+
+ public ScriptField_ShaderParamData_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ mField = new ScriptField_ShaderParamData_s(rs, 1);
+
+ if (mParamName != null) {
+ mData.paramName = SceneManager.getCachedAlloc(mParamName);
+ if (mData.paramName == null) {
+ mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName);
+ SceneManager.cacheAlloc(mParamName, mData.paramName);
+ }
+ }
+ initLocalData();
+ mData.timestamp = 1;
+
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
new file mode 100644
index 0000000..8fae9d9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
@@ -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.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Texture2D extends TextureBase {
+ String mFileName;
+ String mFileDir;
+
+ public Texture2D() {
+ super(ScriptC_export.const_TextureType_TEXTURE_2D);
+ }
+
+ public Texture2D(Allocation tex) {
+ super(ScriptC_export.const_TextureType_TEXTURE_2D);
+ setTexture(tex);
+ }
+
+ public void setFileDir(String dir) {
+ mFileDir = dir;
+ }
+
+ public void setFileName(String file) {
+ mFileName = file;
+ }
+
+ public String getFileName() {
+ return mFileName;
+ }
+
+ public void setTexture(Allocation tex) {
+ mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D();
+ if (mField != null) {
+ mField.set_texture(0, mData.texture, true);
+ }
+ }
+
+ void load() {
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+ setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res));
+ }
+
+ ScriptField_Texture_s getRsData(boolean loadNow) {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ mField = new ScriptField_Texture_s(rs, 1);
+
+ if (loadNow) {
+ load();
+ } else {
+ mData.texture = SceneManager.getDefaultTex2D();
+ new SingleImageLoaderTask().execute(this);
+ }
+
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
new file mode 100644
index 0000000..ba49d4e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import android.os.AsyncTask;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class TextureBase extends SceneGraphBase {
+
+ class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> {
+ protected Boolean doInBackground(TextureBase... objects) {
+ TextureBase tex = objects[0];
+ tex.load();
+ return new Boolean(true);
+ }
+ protected void onPostExecute(Boolean result) {
+ }
+ }
+
+ ScriptField_Texture_s.Item mData;
+ ScriptField_Texture_s mField;
+ TextureBase(int type) {
+ mData = new ScriptField_Texture_s.Item();
+ mData.type = type;
+ }
+
+ protected Allocation mRsTexture;
+ abstract ScriptField_Texture_s getRsData(boolean loadNow);
+ abstract void load();
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
new file mode 100644
index 0000000..12c81c2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureCube extends TextureBase {
+ String mFileName;
+ String mFileDir;
+
+ public TextureCube() {
+ super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+ }
+
+ public TextureCube(Allocation tex) {
+ super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+ setTexture(tex);
+ }
+
+ public TextureCube(String dir, String file) {
+ super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+ setFileDir(dir);
+ setFileName(file);
+ }
+
+ public void setFileDir(String dir) {
+ mFileDir = dir;
+ }
+
+ public void setFileName(String file) {
+ mFileName = file;
+ }
+
+ public String getFileName() {
+ return mFileName;
+ }
+
+ public void setTexture(Allocation tex) {
+ mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube();
+ if (mField != null) {
+ mField.set_texture(0, mData.texture, true);
+ }
+ }
+
+ void load() {
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+ setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res));
+ }
+
+ ScriptField_Texture_s getRsData(boolean loadNow) {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ mField = new ScriptField_Texture_s(rs, 1);
+
+ if (loadNow) {
+ load();
+ } else {
+ mData.texture = SceneManager.getDefaultTexCube();
+ new SingleImageLoaderTask().execute(this);
+ }
+
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
new file mode 100644
index 0000000..e656ed2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureParam extends ShaderParam {
+
+ TextureBase mTexture;
+
+ public TextureParam(String name) {
+ super(name);
+ }
+
+ public TextureParam(String name, TextureBase t) {
+ super(name);
+ setTexture(t);
+ }
+
+ public void setTexture(TextureBase t) {
+ mTexture = t;
+ }
+
+ public TextureBase getTexture() {
+ return mTexture;
+ }
+
+ void initLocalData() {
+ mData.type = ScriptC_export.const_ShaderParam_TEXTURE;
+ if (mTexture != null) {
+ mData.texture = mTexture.getRsData(false).getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
new file mode 100644
index 0000000..6aa29a5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureRenderTarget extends TextureBase {
+ public TextureRenderTarget() {
+ super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+ }
+
+ public TextureRenderTarget(Allocation tex) {
+ super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+ setTexture(tex);
+ }
+
+ public void setTexture(Allocation tex) {
+ mData.texture = tex;
+ if (mField != null) {
+ mField.set_texture(0, mData.texture, true);
+ }
+ }
+
+ void load() {
+ }
+
+ ScriptField_Texture_s getRsData(boolean loadNow) {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+
+ mField = new ScriptField_Texture_s(rs, 1);
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
new file mode 100644
index 0000000..8180bd0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Transform extends SceneGraphBase {
+ Transform mParent;
+ ArrayList<Transform> mChildren;
+
+ ScriptField_SgTransform mField;
+ ScriptField_SgTransform.Item mTransformData;
+
+ public Transform() {
+ mChildren = new ArrayList<Transform>();
+ mParent = null;
+ }
+
+ public void appendChild(Transform t) {
+ mChildren.add(t);
+ t.mParent = this;
+ updateRSChildData(true);
+ }
+
+ abstract void initLocalData();
+
+ void updateRSChildData(boolean copyData) {
+ if (mField == null) {
+ return;
+ }
+ RenderScriptGL rs = SceneManager.getRS();
+ if (mChildren.size() != 0) {
+ Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+ mChildren.size());
+ mTransformData.children = childRSData;
+
+ Allocation[] childrenAllocs = new Allocation[mChildren.size()];
+ for (int i = 0; i < mChildren.size(); i ++) {
+ Transform child = mChildren.get(i);
+ childrenAllocs[i] = child.getRSData().getAllocation();
+ }
+ childRSData.copyFrom(childrenAllocs);
+ }
+ if (copyData) {
+ mField.set(mTransformData, 0, true);
+ }
+ }
+
+ ScriptField_SgTransform getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+ mField = new ScriptField_SgTransform(rs, 1);
+
+ mTransformData = new ScriptField_SgTransform.Item();
+ mTransformData.name = getNameAlloc(rs);
+ mTransformData.isDirty = 1;
+ mTransformData.timestamp = 1;
+
+ initLocalData();
+ updateRSChildData(false);
+
+ mField.set(mTransformData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
new file mode 100644
index 0000000..d120d5d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TransformParam extends ShaderParam {
+
+ Transform mTransform;
+ LightBase mLight;
+
+ public TransformParam(String name) {
+ super(name);
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ if (mField != null && mTransform != null) {
+ mData.transform = mTransform.getRSData().getAllocation();
+ }
+ incTimestamp();
+ }
+
+ int getTypeFromName() {
+ int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA;
+ if (mParamName.equalsIgnoreCase(view)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW;
+ } else if(mParamName.equalsIgnoreCase(proj)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ;
+ } else if(mParamName.equalsIgnoreCase(viewProj)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ;
+ } else if(mParamName.equalsIgnoreCase(model)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL;
+ } else if(mParamName.equalsIgnoreCase(modelView)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW;
+ } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ;
+ }
+ return paramType;
+ }
+
+ void initLocalData() {
+ mData.type = getTypeFromName();
+ if (mTransform != null) {
+ mData.transform = mTransform.getRSData().getAllocation();
+ }
+ if (mCamera != null) {
+ mData.camera = mCamera.getRSData().getAllocation();
+ }
+ if (mLight != null) {
+ mData.light = mLight.getRSData().getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
new file mode 100644
index 0000000..f7d0e6d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class VertexShader extends Shader {
+ ProgramVertex mProgram;
+ ScriptField_VertexShader_s mField;
+
+ public static class Builder {
+ VertexShader mShader;
+ ProgramVertex.Builder mBuilder;
+
+ public Builder(RenderScriptGL rs) {
+ mShader = new VertexShader();
+ mBuilder = new ProgramVertex.Builder(rs);
+ }
+
+ public Builder setShader(Resources resources, int resourceID) {
+ mBuilder.setShader(resources, resourceID);
+ return this;
+ }
+
+ public Builder setObjectConst(Type type) {
+ mShader.mPerObjConstants = type;
+ return this;
+ }
+
+ public Builder setShaderConst(Type type) {
+ mShader.mPerShaderConstants = type;
+ return this;
+ }
+
+ public Builder addInput(Element e) {
+ mBuilder.addInput(e);
+ return this;
+ }
+
+ public VertexShader create() {
+ if (mShader.mPerShaderConstants != null) {
+ mBuilder.addConstant(mShader.mPerShaderConstants);
+ }
+ if (mShader.mPerObjConstants != null) {
+ mBuilder.addConstant(mShader.mPerObjConstants);
+ }
+ mShader.mProgram = mBuilder.create();
+ return mShader;
+ }
+ }
+
+ public ProgramVertex getProgram() {
+ return mProgram;
+ }
+
+ ScriptField_VertexShader_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item();
+ item.program = mProgram;
+
+ linkConstants(rs);
+ if (mPerShaderConstants != null) {
+ item.shaderConst = mConstantBuffer;
+ item.shaderConstParams = mConstantBufferParams.getAllocation();
+ mProgram.bindConstants(item.shaderConst, 0);
+ }
+
+ item.objectConstIndex = -1;
+ if (mPerObjConstants != null) {
+ item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+ }
+
+ mField = new ScriptField_VertexShader_s(rs, 1);
+ mField.set(item, 0, true);
+ return mField;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
new file mode 100644
index 0000000..dc0a885
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
@@ -0,0 +1,66 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_CAMERA
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) {
+
+ SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0);
+ float aspect = *usrData;
+ if (cam->aspect != aspect) {
+ cam->isDirty = 1;
+ cam->aspect = aspect;
+ }
+ if (cam->isDirty) {
+ rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far);
+ }
+
+ const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+ //rsDebug("Camera stamp", cam->transformTimestamp);
+ //rsDebug("Transform stamp", camTransform->timestamp);
+ if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) {
+ cam->isDirty = 1;
+ rs_matrix4x4 camPosMatrix;
+ rsMatrixLoad(&camPosMatrix, &camTransform->globalMat);
+ float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+ cam->position = rsMatrixMultiply(&camPosMatrix, zero);
+
+ rsMatrixInverse(&camPosMatrix);
+ rsMatrixLoad(&cam->view, &camPosMatrix);
+
+ rsMatrixLoad(&cam->viewProj, &cam->proj);
+ rsMatrixMultiply(&cam->viewProj, &cam->view);
+
+ rsExtractFrustumPlanes(&cam->viewProj,
+ &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+ &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+ &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+ }
+
+ if (cam->isDirty) {
+ cam->timestamp ++;
+ }
+
+ cam->isDirty = 0;
+ cam->transformTimestamp = camTransform->timestamp;
+
+#ifdef DEBUG_CAMERA
+ printCameraInfo(cam);
+#endif //DEBUG_CAMERA
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
new file mode 100644
index 0000000..024e026
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
@@ -0,0 +1,86 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+static void getTransformedSphere(SgRenderable *obj) {
+ obj->worldBoundingSphere = obj->boundingSphere;
+ obj->worldBoundingSphere.w = 1.0f;
+ const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+ obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
+
+ const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
+ float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
+ scaledVec.w = 0.0f;
+ obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
+}
+
+static bool frustumCulled(SgRenderable *obj, SgCamera *cam) {
+ if (!obj->bVolInitialized) {
+ float minX, minY, minZ, maxX, maxY, maxZ;
+ rsgMeshComputeBoundingBox(obj->mesh,
+ &minX, &minY, &minZ,
+ &maxX, &maxY, &maxZ);
+ //rsDebug("min", minX, minY, minZ);
+ //rsDebug("max", maxX, maxY, maxZ);
+ float4 sphere;
+ sphere.x = (maxX + minX) * 0.5f;
+ sphere.y = (maxY + minY) * 0.5f;
+ sphere.z = (maxZ + minZ) * 0.5f;
+ float3 radius;
+ radius.x = (maxX - sphere.x);
+ radius.y = (maxY - sphere.y);
+ radius.z = (maxZ - sphere.z);
+
+ sphere.w = length(radius);
+ obj->boundingSphere = sphere;
+ obj->bVolInitialized = 1;
+ //rsDebug("Sphere", sphere);
+ }
+
+ getTransformedSphere(obj);
+
+ return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
+ &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+ &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+ &cam->frustumPlanes[4], &cam->frustumPlanes[5]);
+}
+
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+ SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+ const SgCamera *camera = (const SgCamera*)usrData;
+
+ drawable->isVisible = 0;
+ // Not loaded yet
+ if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) {
+ return;
+ }
+
+ // check to see if we are culling this object and if it's
+ // outside the frustum
+ if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) {
+#ifdef DEBUG_RENDERABLES
+ rsDebug("Culled", drawable);
+ printName(drawable->name);
+#endif // DEBUG_RENDERABLES
+ return;
+ }
+ drawable->isVisible = 1;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
new file mode 100644
index 0000000..b438a43
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
@@ -0,0 +1,61 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+// The sole purpose of this script is to have various structs exposed
+// so that java reflected classes are generated
+#include "scenegraph_objects.rsh"
+
+// Export our native constants to java so that we don't have parallel definitions
+const int ShaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA;
+const int ShaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA;
+const int ShaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL;
+
+const int ShaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS;
+const int ShaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR;
+const int ShaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW;
+const int ShaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ;
+const int ShaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ;
+const int ShaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW;
+const int ShaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ;
+
+const int ShaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR;
+const int ShaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS;
+const int ShaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR;
+
+const int ShaderParam_TEXTURE = SHADER_PARAM_TEXTURE;
+
+const int Transform_TRANSLATE = TRANSFORM_TRANSLATE;
+const int Transform_ROTATE = TRANSFORM_ROTATE;
+const int Transform_SCALE = TRANSFORM_SCALE;
+
+const int TextureType_TEXTURE_2D = TEXTURE_2D;
+const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE;
+const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET;
+
+SgTransform *exportPtr;
+SgTransformComponent *componentPtr;
+SgRenderState *sExport;
+SgRenderable *drExport;
+SgRenderPass *pExport;
+SgCamera *exportPtrCam;
+SgLight *exportPtrLight;
+SgShaderParam *spExport;
+SgShaderParamData *spDataExport;
+SgVertexShader *pvExport;
+SgFragmentShader *pfExport;
+SgTexture *texExport;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
new file mode 100644
index 0000000..7202285
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
@@ -0,0 +1,30 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+ SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0);
+ const SgCamera *camera = (const SgCamera*)usrData;
+ processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+ processTextureParams(shader);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
new file mode 100644
index 0000000..e11979f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
@@ -0,0 +1,33 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_LIGHT
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out) {
+
+ SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0);
+ const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+
+ float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+ light->position = rsMatrixMultiply(&lTransform->globalMat, zero);
+
+#ifdef DEBUG_LIGHT
+ printLightInfo(light);
+#endif //DEBUG_LIGHT
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
new file mode 100644
index 0000000..0d524a6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
@@ -0,0 +1,36 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+ SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+ // Visibility flag was set earlier in the cull stage
+ if (!drawable->isVisible) {
+ return;
+ }
+
+ const SgCamera *camera = (const SgCamera*)usrData;
+ processAllParams(drawable->pf_const, drawable->pf_constParams, camera);
+ processAllParams(drawable->pv_const, drawable->pv_constParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
new file mode 100644
index 0000000..575794b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
@@ -0,0 +1,193 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+static void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
+ rsDebug("____________ Param ____________", p);
+ printName(pData->paramName);
+ rsDebug("bufferOffset", p->bufferOffset);
+ rsDebug("type ", pData->type);
+ rsDebug("data timestamp ", pData->timestamp);
+ rsDebug("param timestamp", p->dataTimestamp);
+
+ const SgTransform *pTransform = NULL;
+ if (rsIsObject(pData->transform)) {
+ pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+
+ rsDebug("transform", pTransform);
+ printName(pTransform->name);
+ rsDebug("timestamp", pTransform->timestamp);
+ rsDebug("param timestamp", p->transformTimestamp);
+ }
+
+ const SgLight *pLight = NULL;
+ if (rsIsObject(pData->light)) {
+ pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+ printLightInfo(pLight);
+ }
+}
+
+
+static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+#ifdef DEBUG_PARAMS
+ rsDebug("Writing value ", *input);
+ rsDebug("Writing vec size ", vecSize);
+#endif // DEBUG_PARAMS
+
+ switch (vecSize) {
+ case 1:
+ *ptr = input->x;
+ break;
+ case 2:
+ *((float2*)ptr) = (*input).xy;
+ break;
+ case 3:
+ *((float3*)ptr) = (*input).xyz;
+ break;
+ case 4:
+ *((float4*)ptr) = *input;
+ break;
+ }
+}
+
+static bool processParam(SgShaderParam *p, SgShaderParamData *pData,
+ uint8_t *constantBuffer,
+ const SgCamera *currentCam,
+ SgFragmentShader *shader) {
+ bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY);
+ const SgTransform *pTransform = NULL;
+ if (rsIsObject(pData->transform)) {
+ pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+ }
+
+ if (isDataOnly) {
+ // If we are a transform param and our transform is unchanged, nothing to do
+ if (pTransform) {
+ if (p->transformTimestamp == pTransform->timestamp) {
+ return false;
+ }
+ p->transformTimestamp = pTransform->timestamp;
+ } else {
+ if (p->dataTimestamp == pData->timestamp) {
+ return false;
+ }
+ p->dataTimestamp = pData->timestamp;
+ }
+ }
+
+ const SgLight *pLight = NULL;
+ if (rsIsObject(pData->light)) {
+ pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+ }
+
+ uint8_t *dataPtr = NULL;
+ const SgTexture *tex = NULL;
+ if (pData->type == SHADER_PARAM_TEXTURE) {
+ tex = rsGetElementAt(pData->texture, 0);
+ } else {
+ dataPtr = constantBuffer + p->bufferOffset;
+ }
+
+ switch (pData->type) {
+ case SHADER_PARAM_TEXTURE:
+ rsgBindTexture(shader->program, p->bufferOffset, tex->texture);
+ break;
+ case SHADER_PARAM_FLOAT4_DATA:
+ writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_CAMERA_POS:
+ writeFloatData((float*)dataPtr, ¤tCam->position, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
+ case SHADER_PARAM_FLOAT4_LIGHT_COLOR:
+ writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_LIGHT_POS:
+ writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
+
+ case SHADER_PARAM_TRANSFORM_DATA:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+ break;
+ case SHADER_PARAM_TRANSFORM_VIEW:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->view);
+ break;
+ case SHADER_PARAM_TRANSFORM_PROJ:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->proj);
+ break;
+ case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->viewProj);
+ break;
+ case SHADER_PARAM_TRANSFORM_MODEL:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+ break;
+ case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->view);
+ rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+ (rs_matrix4x4*)dataPtr,
+ &pTransform->globalMat);
+ break;
+ case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->viewProj);
+ rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+ (rs_matrix4x4*)dataPtr,
+ &pTransform->globalMat);
+ break;
+ }
+ return true;
+}
+
+static void processAllParams(rs_allocation shaderConst,
+ rs_allocation allParams,
+ const SgCamera *camera) {
+ if (rsIsObject(shaderConst)) {
+ uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0);
+
+ int numParams = 0;
+ if (rsIsObject(allParams)) {
+ numParams = rsAllocationGetDimX(allParams);
+ }
+ bool updated = false;
+ for (int i = 0; i < numParams; i ++) {
+ SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i);
+ SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+ debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+ updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated;
+ }
+ }
+}
+
+static void processTextureParams(SgFragmentShader *shader) {
+ int numParams = 0;
+ if (rsIsObject(shader->shaderTextureParams)) {
+ numParams = rsAllocationGetDimX(shader->shaderTextureParams);
+ }
+ for (int i = 0; i < numParams; i ++) {
+ SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i);
+ SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+ debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+ processParam(current, currentData, NULL, NULL, shader);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
new file mode 100644
index 0000000..d8d48b3
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
@@ -0,0 +1,240 @@
+// Copyright (C) 2011-2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "rs_graphics.rsh"
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+rs_script gCameraScript;
+rs_script gLightScript;
+rs_script gObjectParamsScript;
+rs_script gFragmentParamsScript;
+rs_script gVertexParamsScript;
+rs_script gCullScript;
+
+SgTransform *gRootNode;
+rs_allocation gCameras;
+rs_allocation gLights;
+rs_allocation gFragmentShaders;
+rs_allocation gVertexShaders;
+rs_allocation gRenderableObjects;
+
+rs_allocation gRenderPasses;
+
+// Temporary shaders
+rs_program_store gPFSBackground;
+
+uint32_t *gFrontToBack;
+static uint32_t gFrontToBackCount = 0;
+uint32_t *gBackToFront;
+static uint32_t gBackToFrontCount = 0;
+
+static SgCamera *gActiveCamera = NULL;
+
+static rs_allocation nullAlloc;
+
+// #define DEBUG_RENDERABLES
+static void draw(SgRenderable *obj) {
+#ifdef DEBUG_RENDERABLES
+ const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+ rsDebug("**** Drawing object with transform", obj);
+ printName(objTransform->name);
+ rsDebug("Model matrix: ", &objTransform->globalMat);
+ printName(obj->name);
+#endif //DEBUG_RENDERABLES
+
+ const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+ const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0);
+ const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0);
+
+ if (pv->objectConstIndex != -1) {
+ rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const);
+ }
+ if (pf->objectConstIndex != -1) {
+ rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const);
+ }
+
+ if (rsIsObject(renderState->ps)) {
+ rsgBindProgramStore(renderState->ps);
+ } else {
+ rsgBindProgramStore(gPFSBackground);
+ }
+
+ if (rsIsObject(renderState->pr)) {
+ rsgBindProgramRaster(renderState->pr);
+ } else {
+ rs_program_raster pr;
+ rsgBindProgramRaster(pr);
+ }
+
+ rsgBindProgramVertex(pv->program);
+ rsgBindProgramFragment(pf->program);
+
+ for (uint32_t i = 0; i < obj->pf_num_textures; i ++) {
+ const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0);
+ rsgBindTexture(pf->program, i, tex->texture);
+ }
+
+ rsgDrawMesh(obj->mesh, obj->meshIndex);
+}
+
+static void sortToBucket(SgRenderable *obj) {
+ const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+ if (rsIsObject(renderState->ps)) {
+ bool isOpaque = false;
+ if (isOpaque) {
+ gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+ } else {
+ gBackToFront[gBackToFrontCount++] = (uint32_t)obj;
+ }
+ } else {
+ gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+ }
+}
+
+static void updateActiveCamera(rs_allocation cam) {
+ gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0);
+}
+
+static void prepareCameras() {
+ // now compute all the camera matrices
+ if (rsIsObject(gCameras)) {
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect));
+ }
+}
+
+static void prepareLights() {
+ if (rsIsObject(gLights)) {
+ rsForEach(gLightScript, gLights, nullAlloc);
+ }
+}
+
+static void drawSorted() {
+ for (int i = 0; i < gFrontToBackCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+ draw(current);
+ }
+
+ for (int i = 0; i < gBackToFrontCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gBackToFront[i];
+ draw(current);
+ }
+}
+
+static void drawAllObjects(rs_allocation allObj) {
+ if (!rsIsObject(allObj)) {
+ return;
+ }
+
+ rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders,
+ gActiveCamera, sizeof(gActiveCamera));
+ rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders,
+ gActiveCamera, sizeof(gActiveCamera));
+
+ // Run the params and cull script
+ rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+ rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+
+ int numRenderables = rsAllocationGetDimX(allObj);
+ for (int i = 0; i < numRenderables; i ++) {
+ rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i);
+ SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0);
+ if (current->isVisible) {
+ sortToBucket(current);
+ }
+ }
+ drawSorted();
+}
+
+int root(void) {
+#ifdef DEBUG_RENDERABLES
+ rsDebug("=============================================================================", 0);
+#endif // DEBUG_RENDERABLES
+
+ // first step is to update the transform hierachy
+ if (gRootNode && rsIsObject(gRootNode->children)) {
+ rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0);
+ }
+
+ prepareCameras();
+ prepareLights();
+
+ if (rsIsObject(gRenderPasses)) {
+ rsgClearDepth(1.0f);
+ int numPasses = rsAllocationGetDimX(gRenderPasses);
+ for (uint i = 0; i < numPasses; i ++) {
+ gFrontToBackCount = 0;
+ gBackToFrontCount = 0;
+ SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i);
+ if (rsIsObject(pass->color_target)) {
+ rsgBindColorTarget(pass->color_target, 0);
+ }
+ if (rsIsObject(pass->depth_target)) {
+ rsgBindDepthTarget(pass->depth_target);
+ }
+ if (!rsIsObject(pass->color_target) &&
+ !rsIsObject(pass->depth_target)) {
+ rsgClearAllRenderTargets();
+ }
+ updateActiveCamera(pass->camera);
+ if (pass->should_clear_color) {
+ rsgClearColor(pass->clear_color.x, pass->clear_color.y,
+ pass->clear_color.z, pass->clear_color.w);
+ }
+ if (pass->should_clear_depth) {
+ rsgClearDepth(pass->clear_depth);
+ }
+ drawAllObjects(pass->objects);
+ }
+ } else {
+ gFrontToBackCount = 0;
+ gBackToFrontCount = 0;
+ rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgClearDepth(1.0f);
+
+ if (rsIsObject(gCameras)) {
+ rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0);
+ updateActiveCamera(*camAlloc);
+ }
+ drawAllObjects(gRenderableObjects);
+ }
+ return 10;
+}
+
+// Search through sorted and culled objects
+void pick(int screenX, int screenY) {
+ float3 pnt, vec;
+ getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec);
+
+ for (int i = 0; i < gFrontToBackCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+ bool isPicked = intersect(current, pnt, vec);
+ if (isPicked) {
+ current->cullType = CULL_ALWAYS;
+ }
+ }
+
+ for (int i = 0; i < gBackToFrontCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gBackToFront[i];
+ bool isPicked = intersect(current, pnt, vec);
+ if (isPicked) {
+ current->cullType = CULL_ALWAYS;
+ }
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
new file mode 100644
index 0000000..bdca3ab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
@@ -0,0 +1,323 @@
+// Copyright (C) 2011-2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#ifndef _TRANSFORM_DEF_
+#define _TRANSFORM_DEF_
+
+#include "rs_graphics.rsh"
+
+#define TRANSFORM_NONE 0
+#define TRANSFORM_TRANSLATE 1
+#define TRANSFORM_ROTATE 2
+#define TRANSFORM_SCALE 3
+
+#define CULL_FRUSTUM 0
+#define CULL_ALWAYS 2
+
+#define LIGHT_POINT 0
+#define LIGHT_DIRECTIONAL 1
+
+// Shader params that involve only data
+#define SHADER_PARAM_DATA_ONLY 10000
+#define SHADER_PARAM_FLOAT4_DATA 10001
+#define SHADER_PARAM_TRANSFORM_DATA 10002
+#define SHADER_PARAM_TRANSFORM_MODEL 10003
+
+// Shader params that involve camera
+#define SHADER_PARAM_CAMERA 1000
+#define SHADER_PARAM_FLOAT4_CAMERA_POS 1001
+#define SHADER_PARAM_FLOAT4_CAMERA_DIR 1002
+#define SHADER_PARAM_TRANSFORM_VIEW 1003
+#define SHADER_PARAM_TRANSFORM_PROJ 1004
+#define SHADER_PARAM_TRANSFORM_VIEW_PROJ 1005
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW 1006
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007
+
+// Shader Params that only involve lights
+#define SHADER_PARAM_LIGHT 100
+#define SHADER_PARAM_FLOAT4_LIGHT_COLOR 103
+#define SHADER_PARAM_FLOAT4_LIGHT_POS 104
+#define SHADER_PARAM_FLOAT4_LIGHT_DIR 105
+
+#define SHADER_PARAM_TEXTURE 10
+
+#define TEXTURE_NONE 0
+#define TEXTURE_2D 1
+#define TEXTURE_CUBE 2
+#define TEXTURE_RENDER_TARGET 3
+
+typedef struct TransformComponent_s {
+ float4 value;
+ int type;
+ rs_allocation name;
+} SgTransformComponent;
+
+typedef struct __attribute__((packed, aligned(4))) SgTransform {
+ rs_matrix4x4 globalMat;
+ rs_matrix4x4 localMat;
+
+ rs_allocation components;
+ int isDirty;
+
+ rs_allocation children;
+ rs_allocation name;
+
+ // Used to check whether transform params need to be updated
+ uint32_t timestamp;
+} SgTransform;
+
+typedef struct VertexShader_s {
+ rs_program_vertex program;
+ // Buffer with vertex constant data
+ rs_allocation shaderConst;
+ // ShaderParam's that populate data
+ rs_allocation shaderConstParams;
+ // location of the per object constants on the buffer
+ int objectConstIndex;
+} SgVertexShader;
+
+typedef struct FragmentShader_s {
+ rs_program_fragment program;
+ // Buffer with vertex constant data
+ rs_allocation shaderConst;
+ // ShaderParam's that populate data
+ rs_allocation shaderConstParams;
+ // ShaderParam's that set textures
+ rs_allocation shaderTextureParams;
+ // location of the per object constants on the buffer
+ int objectConstIndex;
+} SgFragmentShader;
+
+typedef struct RenderState_s {
+ rs_allocation pv; // VertexShader struct
+ rs_allocation pf; // FragmentShader struct
+ rs_program_store ps;
+ rs_program_raster pr;
+} SgRenderState;
+
+typedef struct Renderable_s {
+ rs_allocation render_state;
+ // Buffer with vertex constant data
+ rs_allocation pv_const;
+ // ShaderParam's that populate data
+ rs_allocation pv_constParams;
+ // Buffer with fragment constant data
+ rs_allocation pf_const;
+ // ShaderParam's that populate data
+ rs_allocation pf_constParams;
+ rs_allocation pf_textures[8];
+ int pf_num_textures;
+ rs_mesh mesh;
+ int meshIndex;
+ rs_allocation transformMatrix;
+ rs_allocation name;
+ float4 boundingSphere;
+ float4 worldBoundingSphere;
+ int bVolInitialized;
+ int cullType; // specifies whether to frustum cull
+ int isVisible;
+} SgRenderable;
+
+typedef struct RenderPass_s {
+ rs_allocation color_target;
+ rs_allocation depth_target;
+ rs_allocation camera;
+ rs_allocation objects;
+
+ float4 clear_color;
+ float clear_depth;
+ bool should_clear_color;
+ bool should_clear_depth;
+} SgRenderPass;
+
+typedef struct Camera_s {
+ rs_matrix4x4 proj;
+ rs_matrix4x4 view;
+ rs_matrix4x4 viewProj;
+ float4 position;
+ float near;
+ float far;
+ float horizontalFOV;
+ float aspect;
+ rs_allocation name;
+ rs_allocation transformMatrix;
+ float4 frustumPlanes[6];
+
+ int isDirty;
+ // Timestamp of the camera itself to signal params if anything changes
+ uint32_t timestamp;
+ // Timestamp of our transform
+ uint32_t transformTimestamp;
+} SgCamera;
+
+typedef struct Light_s {
+ float4 position;
+ float4 color;
+ float intensity;
+ int type;
+ rs_allocation name;
+ rs_allocation transformMatrix;
+} SgLight;
+
+// This represents the shader parameter data needed to set a float or transform data
+typedef struct ShaderParamData_s {
+ int type;
+ float4 float_value;
+ uint32_t timestamp;
+ rs_allocation paramName;
+ rs_allocation camera;
+ rs_allocation light;
+ rs_allocation transform;
+ rs_allocation texture;
+} SgShaderParamData;
+
+// This represents a shader parameter that knows how to update itself for a given
+// renderable or shader and contains a timestamp for the last time this buffer was updated
+typedef struct ShaderParam_s {
+ // Used to check whether transform params need to be updated
+ uint32_t transformTimestamp;
+ // Used to check whether data params need to be updated
+ // These are used when somebody set the matrix of float value directly in java
+ uint32_t dataTimestamp;
+ // Specifies where in the constant buffer data gets written to
+ int bufferOffset;
+ // An instance of SgShaderParamData that could be shared by multiple objects
+ rs_allocation data;
+ // How many components of the vector we need to write
+ int float_vecSize;
+} SgShaderParam;
+
+// This represents a texture object
+typedef struct Texture_s {
+ uint32_t type;
+ rs_allocation texture;
+} SgTexture;
+
+static void printName(rs_allocation name) {
+ if (!rsIsObject(name)) {
+ rsDebug("no name", 0);
+ return;
+ }
+
+ rsDebug((const char*)rsGetElementAt(name, 0), 0);
+}
+
+static void printCameraInfo(const SgCamera *cam) {
+ rsDebug("***** Camera information. ptr:", cam);
+ printName(cam->name);
+ const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+ rsDebug("Transform name:", camTransform);
+ printName(camTransform->name);
+
+ rsDebug("Aspect: ", cam->aspect);
+ rsDebug("Near: ", cam->near);
+ rsDebug("Far: ", cam->far);
+ rsDebug("Fov: ", cam->horizontalFOV);
+ rsDebug("Position: ", cam->position);
+ rsDebug("Proj: ", &cam->proj);
+ rsDebug("View: ", &cam->view);
+}
+
+static void printLightInfo(const SgLight *light) {
+ rsDebug("***** Light information. ptr:", light);
+ printName(light->name);
+ const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+ rsDebug("Transform name:", lTransform);
+ printName(lTransform->name);
+
+ rsDebug("Position: ", light->position);
+ rsDebug("Color : ", light->color);
+ rsDebug("Intensity: ", light->intensity);
+ rsDebug("Type: ", light->type);
+}
+
+static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
+ rsDebug("=================================", screenX);
+ rsDebug("Point X", screenX);
+ rsDebug("Point Y", screenY);
+
+ rs_matrix4x4 mvpInv;
+ rsMatrixLoad(&mvpInv, &cam->viewProj);
+ rsMatrixInverse(&mvpInv);
+
+ float width = (float)rsgGetWidth();
+ float height = (float)rsgGetHeight();
+
+ float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f};
+
+ pos.x /= width;
+ pos.y /= height;
+
+ rsDebug("Pre Norm X", pos.x);
+ rsDebug("Pre Norm Y", pos.y);
+
+ pos.xy = pos.xy * 2.0f - 1.0f;
+
+ rsDebug("Norm X", pos.x);
+ rsDebug("Norm Y", pos.y);
+
+ pos = rsMatrixMultiply(&mvpInv, pos);
+ float oneOverW = 1.0f / pos.w;
+ pos.xyz *= oneOverW;
+
+ rsDebug("World X", pos.x);
+ rsDebug("World Y", pos.y);
+ rsDebug("World Z", pos.z);
+
+ rsDebug("Cam X", cam->position.x);
+ rsDebug("Cam Y", cam->position.y);
+ rsDebug("Cam Z", cam->position.z);
+
+ *vec = normalize(pos.xyz - cam->position.xyz);
+ rsDebug("Vec X", vec->x);
+ rsDebug("Vec Y", vec->y);
+ rsDebug("Vec Z", vec->z);
+ *pnt = cam->position.xyz;
+}
+
+static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
+ // Solving for t^2 + Bt + C = 0
+ float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz;
+ float B = dot(originMinusCenter, vec) * 2.0f;
+ float C = dot(originMinusCenter, originMinusCenter) -
+ obj->worldBoundingSphere.w * obj->worldBoundingSphere.w;
+
+ float discriminant = B * B - 4.0f * C;
+ if (discriminant < 0.0f) {
+ return false;
+ }
+ discriminant = sqrt(discriminant);
+
+ float t0 = (-B - discriminant) * 0.5f;
+ float t1 = (-B + discriminant) * 0.5f;
+
+ if (t0 > t1) {
+ float temp = t0;
+ t0 = t1;
+ t1 = temp;
+ }
+
+ // The sphere is behind us
+ if (t1 < 0.0f) {
+ return false;
+ }
+ return true;
+}
+
+
+#endif // _TRANSFORM_DEF_
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
new file mode 100644
index 0000000..941b5a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
@@ -0,0 +1,127 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.modelviewer)
+
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+
+typedef struct {
+ int changed;
+ rs_matrix4x4 *mat;
+} ParentData;
+
+//#define DEBUG_TRANSFORMS
+static void debugTransform(SgTransform *data, const ParentData *parent) {
+ rsDebug("****** <Transform> ******", (int)data);
+ printName(data->name);
+ rsDebug("isDirty", data->isDirty);
+ rsDebug("parent", (int)parent);
+ rsDebug("child ", rsIsObject(data->children));
+
+ // Refresh matrices if dirty
+ if (data->isDirty && rsIsObject(data->components)) {
+ uint32_t numComponenets = rsAllocationGetDimX(data->components);
+ for (int i = 0; i < numComponenets; i ++) {
+ const SgTransformComponent *comp = NULL;
+ comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+
+ if (rsIsObject(comp->name)) {
+ rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
+ rsDebug("Type", comp->type);
+ } else {
+ rsDebug("no name", comp->value);
+ rsDebug("Type", comp->type);
+ }
+ }
+ }
+
+ rsDebug("timestamp", data->timestamp);
+ rsDebug("****** </Transform> ******", (int)data);
+}
+
+static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
+ rs_matrix4x4 temp;
+
+ switch (type) {
+ case TRANSFORM_TRANSLATE:
+ rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
+ break;
+ case TRANSFORM_ROTATE:
+ rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
+ break;
+ case TRANSFORM_SCALE:
+ rsMatrixLoadScale(&temp, data.x, data.y, data.z);
+ break;
+ }
+ rsMatrixMultiply(mat, &temp);
+}
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
+
+ SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
+ const ParentData *parent = (const ParentData *)usrData;
+
+#ifdef DEBUG_TRANSFORMS
+ debugTransform(data, parent);
+#endif //DEBUG_TRANSFORMS
+
+ rs_matrix4x4 *localMat = &data->localMat;
+ rs_matrix4x4 *globalMat = &data->globalMat;
+
+ // Refresh matrices if dirty
+ if (data->isDirty && rsIsObject(data->components)) {
+ bool resetLocal = false;
+ uint32_t numComponenets = rsAllocationGetDimX(data->components);
+ for (int i = 0; i < numComponenets; i ++) {
+ if (!resetLocal) {
+ // Reset our local matrix only for component transforms
+ rsMatrixLoadIdentity(localMat);
+ resetLocal = true;
+ }
+ const SgTransformComponent *comp = NULL;
+ comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+ appendTransformation(comp->type, comp->value, localMat);
+ }
+ }
+
+ if (parent) {
+ data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
+ if (data->isDirty) {
+ rsMatrixLoad(globalMat, parent->mat);
+ rsMatrixMultiply(globalMat, localMat);
+ }
+ } else if (data->isDirty) {
+ rsMatrixLoad(globalMat, localMat);
+ }
+
+ ParentData toChild;
+ toChild.changed = 0;
+ toChild.mat = globalMat;
+
+ if (data->isDirty) {
+ toChild.changed = 1;
+ data->timestamp ++;
+ }
+
+ if (rsIsObject(data->children)) {
+ rs_allocation nullAlloc;
+ rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
+ }
+
+ data->isDirty = 0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
new file mode 100644
index 0000000..88955a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
@@ -0,0 +1,29 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+ SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0);
+ const SgCamera *camera = (const SgCamera*)usrData;
+ processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
new file mode 100644
index 0000000..420e133
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * A list view where the last item the user clicked is placed in
+ * the "activated" state, causing its background to highlight.
+ */
+public class FileSelector extends ListActivity {
+
+ File[] mCurrentSubList;
+ File mCurrentFile;
+
+ class DAEFilter implements FileFilter {
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ return true;
+ }
+ return file.getName().endsWith(".dae");
+ }
+ }
+
+ private void populateList(File file) {
+
+ mCurrentFile = file;
+ setTitle(mCurrentFile.getAbsolutePath() + "/*.dae");
+ List<String> names = new ArrayList<String>();
+ names.add("..");
+
+ mCurrentSubList = mCurrentFile.listFiles(new DAEFilter());
+
+ if (mCurrentSubList != null) {
+ for (int i = 0; i < mCurrentSubList.length; i ++) {
+ String fileName = mCurrentSubList[i].getName();
+ if (mCurrentSubList[i].isDirectory()) {
+ fileName = "/" + fileName;
+ }
+ names.add(fileName);
+ }
+ }
+
+ // Use the built-in layout for showing a list item with a single
+ // line of text whose background is changes when activated.
+ setListAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_activated_1, names));
+ getListView().setTextFilterEnabled(true);
+
+ // Tell the list view to show one checked/activated item at a time.
+ getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ populateList(new File("/sdcard/"));
+ }
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ if (position == 0) {
+ File parent = mCurrentFile.getParentFile();
+ if (parent == null) {
+ return;
+ }
+ populateList(parent);
+ return;
+ }
+
+ // the first thing in list is parent directory
+ File selectedFile = mCurrentSubList[position - 1];
+ if (selectedFile.isDirectory()) {
+ populateList(selectedFile);
+ return;
+ }
+
+ Intent resultIntent = new Intent();
+ resultIntent.setData(Uri.fromFile(selectedFile));
+ setResult(RESULT_OK, resultIntent);
+ finish();
+ }
+
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
new file mode 100644
index 0000000..28f916c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+
+import com.android.scenegraph.*;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+class FullscreenBlur {
+
+ static TextureRenderTarget sRenderTargetBlur0Color;
+ static TextureRenderTarget sRenderTargetBlur0Depth;
+ static TextureRenderTarget sRenderTargetBlur1Color;
+ static TextureRenderTarget sRenderTargetBlur1Depth;
+ static TextureRenderTarget sRenderTargetBlur2Color;
+ static TextureRenderTarget sRenderTargetBlur2Depth;
+
+ static FragmentShader mPF_BlurH;
+ static FragmentShader mPF_BlurV;
+ static FragmentShader mPF_SelectColor;
+ static FragmentShader mPF_Texture;
+ static VertexShader mPV_Paint;
+ static VertexShader mPV_Blur;
+
+ static int targetWidth;
+ static int targetHeight;
+
+ // This is only used when full screen blur is enabled
+ // Basically, it's the offscreen render targets
+ static void createRenderTargets(RenderScriptGL rs, int w, int h) {
+ targetWidth = w/8;
+ targetHeight = h/8;
+ Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+ Type renderType = b.setX(targetWidth).setY(targetHeight).create();
+ int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;
+ sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+
+ b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,
+ Element.DataKind.PIXEL_DEPTH));
+ renderType = b.setX(targetWidth).setY(targetHeight).create();
+ usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;
+ sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ }
+
+ static void addOffsets(Renderable quad, float advance) {
+ quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));
+ }
+
+ static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {
+ RenderPass pass = new RenderPass();
+ pass.setColorTarget(color);
+ pass.setDepthTarget(depth);
+ pass.setShouldClearColor(false);
+ pass.setShouldClearDepth(false);
+ pass.setCamera(cam);
+ scene.appendRenderPass(pass);
+ return pass;
+ }
+
+ static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {
+ SceneManager sceneManager = SceneManager.getInstance();
+ ArrayList<RenderableBase> allDraw = scene.getRenderables();
+ int numDraw = allDraw.size();
+
+ ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);
+ ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);
+ ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);
+
+ RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);
+ RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);
+ RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);
+ RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);
+
+ // Renders the scene off screen
+ RenderPass blurSourcePass = addPass(scene, cam,
+ sRenderTargetBlur0Color,
+ sRenderTargetBlur0Depth);
+ blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+ blurSourcePass.setShouldClearColor(true);
+ blurSourcePass.setClearDepth(1.0f);
+ blurSourcePass.setShouldClearDepth(true);
+ for (int i = 0; i < numDraw; i ++) {
+ blurSourcePass.appendRenderable((Renderable)allDraw.get(i));
+ }
+
+ // Pass for selecting bright colors
+ RenderPass selectColorPass = addPass(scene, cam,
+ sRenderTargetBlur2Color,
+ sRenderTargetBlur2Depth);
+ Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));
+ selectColorPass.appendRenderable(quad);
+
+ // Horizontal blur
+ RenderPass horizontalBlurPass = addPass(scene, cam,
+ sRenderTargetBlur1Color,
+ sRenderTargetBlur1Depth);
+ quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
+ addOffsets(quad, 1.0f / (float)targetWidth);
+ horizontalBlurPass.appendRenderable(quad);
+
+ // Vertical Blur
+ RenderPass verticalBlurPass = addPass(scene, cam,
+ sRenderTargetBlur2Color,
+ sRenderTargetBlur2Depth);
+ quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));
+ addOffsets(quad, 1.0f / (float)targetHeight);
+ verticalBlurPass.appendRenderable(quad);
+ }
+
+ // Additively renders the blurred colors on top of the scene
+ static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {
+ SceneManager sceneManager = SceneManager.getInstance();
+ RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,
+ SceneManager.BLEND_ADD_DEPTH_NONE(rs),
+ ProgramRaster.CULL_NONE(rs));
+
+ RenderPass compositePass = addPass(scene, cam, null, null);
+ Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
+ compositePass.appendRenderable(quad);
+ }
+
+ static private FragmentShader getShader(Resources res, RenderScriptGL rs,
+ int resID, Type constants) {
+ FragmentShader.Builder fb = new FragmentShader.Builder(rs);
+ fb.setShader(res, resID);
+ fb.addTexture(TextureType.TEXTURE_2D, "color");
+ if (constants != null) {
+ fb.setObjectConst(constants);
+ }
+ FragmentShader prog = fb.create();
+ prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);
+ return prog;
+ }
+
+ static void initShaders(Resources res, RenderScriptGL rs) {
+ ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);
+ VertexShader.Builder vb = new VertexShader.Builder(rs);
+ vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));
+ vb.setShader(res, R.raw.blur_vertex);
+ mPV_Blur = vb.create();
+
+ mPF_Texture = getShader(res, rs, R.raw.texture, null);
+ mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);
+ mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());
+ mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());
+ mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);
+ }
+
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
new file mode 100644
index 0000000..385a7ab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+import android.view.MenuInflater;
+import android.view.Window;
+import android.net.Uri;
+
+import java.lang.Runtime;
+
+public class TestApp extends Activity {
+
+ private TestAppView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new TestAppView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.pause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.loader_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle item selection
+ switch (item.getItemId()) {
+ case R.id.load_model:
+ loadModel();
+ return true;
+ case R.id.use_blur:
+ mView.mRender.toggleBlur();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private static final int FIND_DAE_MODEL = 10;
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == RESULT_OK) {
+ if (requestCode == FIND_DAE_MODEL) {
+ Uri selectedImageUri = data.getData();
+ Log.e("Selected Path: ", selectedImageUri.getPath());
+ mView.mRender.loadModel(selectedImageUri.getPath());
+ }
+ }
+ }
+
+ public void loadModel() {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_PICK);
+ intent.setClassName("com.android.testapp",
+ "com.android.testapp.FileSelector");
+ startActivityForResult(intent, FIND_DAE_MODEL);
+ }
+
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
new file mode 100644
index 0000000..5bd8f0b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppLoadingScreen {
+
+ private static String TAG = "TestAppLoadingScreen";
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private ScriptC_test_app mScript;
+
+ public TestAppLoadingScreen(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+ // Shows the loading screen with some text
+ renderLoading();
+ // Adds a little 3D bugdroid model to the laoding screen asynchronously.
+ new LoadingScreenLoaderTask().execute();
+ }
+
+ public void showLoadingScreen(boolean show) {
+ if (show) {
+ mRS.bindRootScript(mScript);
+ } else {
+ mRS.bindRootScript(SceneManager.getInstance().getRenderLoop());
+ }
+ }
+
+ // The loading screen has some elements that shouldn't be loaded on the UI thread
+ private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> {
+ Allocation robotTex;
+ Mesh robotMesh;
+ protected Boolean doInBackground(String... names) {
+ long start = System.currentTimeMillis();
+ robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
+ MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+
+ FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
+ FileA3D.IndexEntry entry = model.getIndexEntry(0);
+ if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+ robotMesh = entry.getMesh();
+ }
+
+ mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+
+ ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
+ b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+ ProgramFragment pfDefault = b.create();
+ pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
+ mScript.set_gPFBackground(pfDefault);
+
+ ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+ ProgramVertexFixedFunction pvDefault = pvb.create();
+ ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS);
+ ((ProgramVertexFixedFunction)pvDefault).bindConstants(va);
+ mScript.set_gPVBackground(pvDefault);
+
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "Loading load time: " + (end - start));
+ return new Boolean(true);
+ }
+
+ protected void onPostExecute(Boolean result) {
+ mScript.set_gRobotTex(robotTex);
+ mScript.set_gRobotMesh(robotMesh);
+ }
+ }
+
+ // Creates a simple script to show a loding screen until everything is initialized
+ // Could also be used to do some custom renderscript work before handing things over
+ // to the scenegraph
+ void renderLoading() {
+ mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app);
+ mRS.bindRootScript(mScript);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
new file mode 100644
index 0000000..7bf7812
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011-2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.*;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Program.TextureType;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppRS {
+
+ private static String modelName = "orientation_test.dae";
+ private static String TAG = "TestAppRS";
+ private static String mFilePath = "";
+
+ int mWidth;
+ int mHeight;
+
+ boolean mUseBlur;
+
+ TestAppLoadingScreen mLoadingScreen;
+
+ // Used to asynchronously load scene elements like meshes and transform hierarchies
+ SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() {
+ public void run() {
+ prepareToRender(mLoadedScene);
+ }
+ };
+
+ // Top level class that initializes all the elements needed to use the scene graph
+ SceneManager mSceneManager;
+
+ // Used to move the camera around in the 3D world
+ TouchHandler mTouchHandler;
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+
+ // Shaders
+ private FragmentShader mPaintF;
+ private FragmentShader mLightsF;
+ private FragmentShader mAluminumF;
+ private FragmentShader mPlasticF;
+ private FragmentShader mDiffuseF;
+ private FragmentShader mTextureF;
+ private VertexShader mGenericV;
+
+ Scene mActiveScene;
+
+ // This is a part of the test app, it's used to tests multiple render passes and is toggled
+ // on and off in the menu, off by default
+ void toggleBlur() {
+ mUseBlur = !mUseBlur;
+
+ mActiveScene.clearRenderPasses();
+ initRenderPasses();
+ mActiveScene.initRenderPassRS(mRS, mSceneManager);
+
+ // This is just a hardcoded object in the scene that gets turned on and off for the demo
+ // to make things look a bit better. This could be deleted in the cleanup
+ Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+ if (plane != null) {
+ plane.setVisible(!mUseBlur);
+ }
+ }
+
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
+ mUseBlur = false;
+ mRS = rs;
+ mRes = res;
+ mWidth = width;
+ mHeight = height;
+
+ mTouchHandler = new TouchHandler();
+
+ mSceneManager = SceneManager.getInstance();
+ // Initializes all the RS specific scenegraph elements
+ mSceneManager.initRS(mRS, mRes, mWidth, mHeight);
+
+ mLoadingScreen = new TestAppLoadingScreen(mRS, mRes);
+
+ // Initi renderscript stuff specific to the app. This will need to be abstracted out later.
+ FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight);
+ initPaintShaders();
+
+ // Load a scene to render
+ mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback);
+ }
+
+ // When a new model file is selected from the UI, this function gets called to init everything
+ void loadModel(String path) {
+ mLoadingScreen.showLoadingScreen(true);
+ mActiveScene.destroyRS();
+ mSceneManager.loadModel(path, mLoadedCallback);
+ }
+
+ public void onActionDown(float x, float y) {
+ mTouchHandler.onActionDown(x, y);
+ }
+
+ public void onActionScale(float scale) {
+ mTouchHandler.onActionScale(scale);
+ }
+
+ public void onActionMove(float x, float y) {
+ mTouchHandler.onActionMove(x, y);
+ }
+
+ FragmentShader createFromResource(int id, boolean addCubemap, Type constType) {
+ FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+ fb.setShaderConst(constType);
+ fb.setShader(mRes, id);
+ fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
+ if (addCubemap) {
+ fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection");
+ }
+ FragmentShader pf = fb.create();
+ pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
+ if (addCubemap) {
+ pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1);
+ }
+ return pf;
+ }
+
+ private void initPaintShaders() {
+ ScriptField_ModelParams objConst = new ScriptField_ModelParams(mRS, 1);
+ ScriptField_ViewProjParams shaderConst = new ScriptField_ViewProjParams(mRS, 1);
+
+ VertexShader.Builder vb = new VertexShader.Builder(mRS);
+ vb.addInput(ScriptField_VertexShaderInputs.createElement(mRS));
+ vb.setShader(mRes, R.raw.shader2v);
+ vb.setObjectConst(objConst.getAllocation().getType());
+ vb.setShaderConst(shaderConst.getAllocation().getType());
+ mGenericV = vb.create();
+
+ ScriptField_CameraParams fsConst = new ScriptField_CameraParams(mRS, 1);
+ ScriptField_LightParams fsConst2 = new ScriptField_LightParams(mRS, 1);
+
+ mPaintF = createFromResource(R.raw.paintf, true, fsConst.getAllocation().getType());
+ // Assign a reflection map
+ TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
+ mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
+
+ mAluminumF = createFromResource(R.raw.metal, true, fsConst.getAllocation().getType());
+ TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
+ mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
+
+ mPlasticF = createFromResource(R.raw.plastic, false, fsConst.getAllocation().getType());
+ mDiffuseF = createFromResource(R.raw.diffuse, false, fsConst.getAllocation().getType());
+ mTextureF = createFromResource(R.raw.texture, false, fsConst.getAllocation().getType());
+
+ FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+ fb.setObjectConst(fsConst2.getAllocation().getType());
+ fb.setShader(mRes, R.raw.plastic_lights);
+ mLightsF = fb.create();
+
+ FullscreenBlur.initShaders(mRes, mRS);
+ }
+
+ void initRenderPasses() {
+ ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables();
+ int numDraw = allDraw.size();
+
+ if (mUseBlur) {
+ FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera());
+ }
+
+ RenderPass mainPass = new RenderPass();
+ mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+ mainPass.setShouldClearColor(true);
+ mainPass.setClearDepth(1.0f);
+ mainPass.setShouldClearDepth(true);
+ mainPass.setCamera(mTouchHandler.getCamera());
+ for (int i = 0; i < numDraw; i ++) {
+ mainPass.appendRenderable((Renderable)allDraw.get(i));
+ }
+ mActiveScene.appendRenderPass(mainPass);
+
+ if (mUseBlur) {
+ FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera());
+ }
+ }
+
+ private void addShadersToScene() {
+ mActiveScene.appendShader(mPaintF);
+ mActiveScene.appendShader(mLightsF);
+ mActiveScene.appendShader(mAluminumF);
+ mActiveScene.appendShader(mPlasticF);
+ mActiveScene.appendShader(mDiffuseF);
+ mActiveScene.appendShader(mTextureF);
+ mActiveScene.appendShader(mGenericV);
+ }
+
+ public void prepareToRender(Scene s) {
+ mSceneManager.setActiveScene(s);
+ mActiveScene = s;
+ mTouchHandler.init(mActiveScene);
+ addShadersToScene();
+ RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null);
+ RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null);
+ RenderState paint = new RenderState(mGenericV, mPaintF, null, null);
+ RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null);
+ RenderState lights = new RenderState(mGenericV, mLightsF, null, null);
+ RenderState glassTransp = new RenderState(mGenericV, mPaintF,
+ ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null);
+
+ initRenderPasses();
+
+ mActiveScene.assignRenderState(plastic);
+
+ mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$");
+
+ mActiveScene.assignRenderStateToMaterial(paint, "^Paint");
+ mActiveScene.assignRenderStateToMaterial(paint, "^Carbon");
+ mActiveScene.assignRenderStateToMaterial(paint, "^Glass");
+ mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass");
+
+ mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal");
+ mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake");
+
+ mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight");
+
+ mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn");
+
+ Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+ if (plane != null) {
+ RenderState texState = new RenderState(mGenericV, mTextureF, null, null);
+ plane.setRenderState(texState);
+ plane.setVisible(!mUseBlur);
+ }
+
+ long start = System.currentTimeMillis();
+ mActiveScene.initRS();
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "Scene init time: " + (end - start));
+
+ mLoadingScreen.showLoadingScreen(false);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
new file mode 100644
index 0000000..687f35b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+public class TestAppView extends RSSurfaceView {
+
+ public TestAppView(Context context) {
+ super(context);
+ mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+ }
+
+ private RenderScriptGL mRS;
+ TestAppRS mRender;
+
+ private ScaleGestureDetector mScaleDetector;
+ private static final int INVALID_POINTER_ID = -1;
+ private int mActivePointerId = INVALID_POINTER_ID;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScriptGL(sc);
+ mRS.setSurface(holder, w, h);
+ mRender = new TestAppRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (mRS != null) {
+ mRender = null;
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ mScaleDetector.onTouchEvent(ev);
+
+ boolean ret = false;
+ float x = ev.getX();
+ float y = ev.getY();
+
+ final int action = ev.getAction();
+
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN: {
+ mRender.onActionDown(x, y);
+ mActivePointerId = ev.getPointerId(0);
+ ret = true;
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ if (!mScaleDetector.isInProgress()) {
+ mRender.onActionMove(x, y);
+ }
+ mRender.onActionDown(x, y);
+ ret = true;
+ break;
+ }
+
+ case MotionEvent.ACTION_UP: {
+ mActivePointerId = INVALID_POINTER_ID;
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL: {
+ mActivePointerId = INVALID_POINTER_ID;
+ break;
+ }
+
+ case MotionEvent.ACTION_POINTER_UP: {
+ final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int pointerId = ev.getPointerId(pointerIndex);
+ if (pointerId == mActivePointerId) {
+ // This was our active pointer going up. Choose a new
+ // active pointer and adjust accordingly.
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ x = ev.getX(newPointerIndex);
+ y = ev.getY(newPointerIndex);
+ mRender.onActionDown(x, y);
+ mActivePointerId = ev.getPointerId(newPointerIndex);
+ }
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ mRender.onActionScale(detector.getScaleFactor());
+ return true;
+ }
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
new file mode 100644
index 0000000..d8e48e8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import android.util.Log;
+import android.renderscript.Float3;
+import com.android.scenegraph.*;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+
+public class TouchHandler {
+ private static String TAG = "TouchHandler";
+
+ float mLastX;
+ float mLastY;
+
+ float mRotateXValue;
+ float mRotateYValue;
+ Float3 mDistValue;
+ Float3 mPosValue;
+
+ CompoundTransform mCameraRig;
+ RotateComponent mRotateX;
+ RotateComponent mRotateY;
+ TranslateComponent mDist;
+ TranslateComponent mPosition;
+ Camera mCamera;
+
+ public void init(Scene scene) {
+ // Some initial values for camera position
+ mRotateXValue = -20;
+ mRotateYValue = 45;
+ mDistValue = new Float3(0, 0, 45);
+ mPosValue = new Float3(0, 4, 0);
+
+ mRotateX = new RotateComponent("RotateX", new Float3(1, 0, 0), mRotateXValue);
+ mRotateY = new RotateComponent("RotateY", new Float3(0, 1, 0), mRotateYValue);
+ mDist = new TranslateComponent("Distance", mDistValue);
+ mPosition = new TranslateComponent("Distance", mPosValue);
+
+ // Make a camera transform we can manipulate
+ mCameraRig = new CompoundTransform();
+ mCameraRig.setName("CameraRig");
+ mCameraRig.addComponent(mPosition);
+ mCameraRig.addComponent(mRotateY);
+ mCameraRig.addComponent(mRotateX);
+ mCameraRig.addComponent(mDist);
+ scene.appendTransform(mCameraRig);
+ mCamera = new Camera();
+ mCamera.setTransform(mCameraRig);
+ scene.appendCamera(mCamera);
+ }
+
+ public Camera getCamera() {
+ return mCamera;
+ }
+
+ public void onActionDown(float x, float y) {
+ mLastX = x;
+ mLastY = y;
+ }
+
+ public void onActionScale(float scale) {
+ if (mDist == null) {
+ return;
+ }
+ mDistValue.z *= 1.0f / scale;
+ mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f));
+ mDist.setValue(mDistValue);
+ }
+
+ public void onActionMove(float x, float y) {
+ if (mRotateX == null) {
+ return;
+ }
+
+ float dx = mLastX - x;
+ float dy = mLastY - y;
+
+ if (Math.abs(dy) <= 2.0f) {
+ dy = 0.0f;
+ }
+ if (Math.abs(dx) <= 2.0f) {
+ dx = 0.0f;
+ }
+
+ mRotateYValue += dx * 0.25f;
+ mRotateYValue %= 360.0f;
+
+ mRotateXValue += dy * 0.25f;
+ mRotateXValue = Math.max(mRotateXValue , -80.0f);
+ mRotateXValue = Math.min(mRotateXValue , 0.0f);
+
+ mRotateX.setAngle(mRotateXValue);
+ mRotateY.setAngle(mRotateYValue);
+
+ mLastX = x;
+ mLastY = y;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
new file mode 100644
index 0000000..997a1a7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
@@ -0,0 +1,86 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.testapp)
+
+#include "rs_graphics.rsh"
+#include "test_app.rsh"
+
+// Making sure these get reflected
+FBlurOffsets *blurExport;
+VShaderInputs *iExport;
+FShaderParams *fConst;
+FShaderLightParams *fConts2;
+VSParams *vConst2;
+VObjectParams *vConst3;
+
+rs_program_vertex gPVBackground;
+rs_program_fragment gPFBackground;
+
+rs_allocation gRobotTex;
+rs_mesh gRobotMesh;
+
+rs_program_store gPFSBackground;
+
+float gRotate;
+
+void init() {
+ gRotate = 0.0f;
+}
+
+static int pos = 50;
+static float gRotateY = 120.0f;
+static float3 gLookAt = 0;
+static float gZoom = 50.0f;
+static void displayLoading() {
+ if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) {
+ rsgBindProgramVertex(gPVBackground);
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+
+ rsgBindProgramFragment(gPFBackground);
+ rsgBindProgramStore(gPFSBackground);
+ rsgBindTexture(gPFBackground, 0, gRobotTex);
+
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ // Position our models on the screen
+ gRotateY += rsGetDt()*100;
+ rsMatrixTranslate(&matrix, 0, 0, -gZoom);
+ rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
+ rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+ rsgDrawMesh(gRobotMesh);
+ }
+
+ uint width = rsgGetWidth();
+ uint height = rsgGetHeight();
+ int left = 0, right = 0, top = 0, bottom = 0;
+ const char* text = "Initializing...";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ int centeredPos = width / 2 - (right - left) / 2;
+ rsgDrawText(text, centeredPos, height / 2 + height / 10);
+}
+
+int root(void) {
+ rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgClearDepth(1.0f);
+ displayLoading();
+ return 30;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
new file mode 100644
index 0000000..5fbcbb2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
@@ -0,0 +1,52 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.testapp)
+
+// Helpers
+typedef struct ViewProjParams {
+ rs_matrix4x4 viewProj;
+} VSParams;
+
+typedef struct ModelParams {
+ rs_matrix4x4 model;
+} VObjectParams;
+
+typedef struct CameraParams {
+ float4 cameraPos;
+} FShaderParams;
+
+typedef struct LightParams {
+ float4 lightPos_0;
+ float4 lightColor_0;
+ float4 lightPos_1;
+ float4 lightColor_1;
+ float4 cameraPos;
+ float4 diffuse;
+} FShaderLightParams;
+
+typedef struct BlurOffsets {
+ float blurOffset0;
+ float blurOffset1;
+ float blurOffset2;
+ float blurOffset3;
+} FBlurOffsets;
+
+typedef struct VertexShaderInputs {
+ float4 position;
+ float3 normal;
+ float2 texture0;
+} VShaderInputs;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 2293678..c7bd809 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,9 +64,15 @@
unitTests = new ArrayList<UnitTest>();
+ unitTests.add(new UT_mesh(this, mRes, mCtx));
+ unitTests.add(new UT_element(this, mRes, mCtx));
+ unitTests.add(new UT_sampler(this, mRes, mCtx));
+ unitTests.add(new UT_program_store(this, mRes, mCtx));
+ unitTests.add(new UT_program_raster(this, mRes, mCtx));
unitTests.add(new UT_primitives(this, mRes, mCtx));
unitTests.add(new UT_constant(this, mRes, mCtx));
unitTests.add(new UT_vector(this, mRes, mCtx));
+ unitTests.add(new UT_array_init(this, mRes, mCtx));
unitTests.add(new UT_rsdebug(this, mRes, mCtx));
unitTests.add(new UT_rstime(this, mRes, mCtx));
unitTests.add(new UT_rstypes(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
new file mode 100644
index 0000000..b98b753
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_array_init extends UnitTest {
+ private Resources mRes;
+
+ protected UT_array_init(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Array Init", ctx);
+ mRes = res;
+ }
+
+ private void checkInit(ScriptC_array_init s) {
+ float[] fa = s.get_fa();
+ _RS_ASSERT("fa[0] == 1.0", fa[0] == 1.0);
+ _RS_ASSERT("fa[1] == 9.9999f", fa[1] == 9.9999f);
+ _RS_ASSERT("fa[2] == 0", fa[2] == 0);
+ _RS_ASSERT("fa[3] == 0", fa[3] == 0);
+ _RS_ASSERT("fa.length == 4", fa.length == 4);
+
+ double[] da = s.get_da();
+ _RS_ASSERT("da[0] == 7.0", da[0] == 7.0);
+ _RS_ASSERT("da[1] == 8.88888", da[1] == 8.88888);
+ _RS_ASSERT("da.length == 2", da.length == 2);
+
+ byte[] ca = s.get_ca();
+ _RS_ASSERT("ca[0] == 'a'", ca[0] == 'a');
+ _RS_ASSERT("ca[1] == 7", ca[1] == 7);
+ _RS_ASSERT("ca[2] == 'b'", ca[2] == 'b');
+ _RS_ASSERT("ca[3] == 'c'", ca[3] == 'c');
+ _RS_ASSERT("ca.length == 4", ca.length == 4);
+
+ short[] sa = s.get_sa();
+ _RS_ASSERT("sa[0] == 1", sa[0] == 1);
+ _RS_ASSERT("sa[1] == 1", sa[1] == 1);
+ _RS_ASSERT("sa[2] == 2", sa[2] == 2);
+ _RS_ASSERT("sa[3] == 3", sa[3] == 3);
+ _RS_ASSERT("sa.length == 4", sa.length == 4);
+
+ int[] ia = s.get_ia();
+ _RS_ASSERT("ia[0] == 5", ia[0] == 5);
+ _RS_ASSERT("ia[1] == 8", ia[1] == 8);
+ _RS_ASSERT("ia[2] == 0", ia[2] == 0);
+ _RS_ASSERT("ia[3] == 0", ia[3] == 0);
+ _RS_ASSERT("ia.length == 4", ia.length == 4);
+
+ long[] la = s.get_la();
+ _RS_ASSERT("la[0] == 13", la[0] == 13);
+ _RS_ASSERT("la[1] == 21", la[1] == 21);
+ _RS_ASSERT("la.length == 4", la.length == 2);
+
+ long[] lla = s.get_lla();
+ _RS_ASSERT("lla[0] == 34", lla[0] == 34);
+ _RS_ASSERT("lla[1] == 0", lla[1] == 0);
+ _RS_ASSERT("lla[2] == 0", lla[2] == 0);
+ _RS_ASSERT("lla[3] == 0", lla[3] == 0);
+ _RS_ASSERT("lla.length == 4", lla.length == 4);
+
+ boolean[] ba = s.get_ba();
+ _RS_ASSERT("ba[0] == true", ba[0] == true);
+ _RS_ASSERT("ba[1] == false", ba[1] == false);
+ _RS_ASSERT("ba[2] == false", ba[2] == false);
+ _RS_ASSERT("ba.length == 3", ba.length == 3);
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_array_init s = new ScriptC_array_init(pRS, mRes, R.raw.array_init);
+ pRS.setMessageHandler(mRsMessage);
+ checkInit(s);
+ s.invoke_array_init_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ passTest();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
new file mode 100644
index 0000000..3e2a2ca
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Element.*;
+import android.renderscript.Element.DataKind.*;
+import android.renderscript.Element.DataType.*;
+
+public class UT_element extends UnitTest {
+ private Resources mRes;
+
+ Element simpleElem;
+ Element complexElem;
+
+ final String subElemNames[] = {
+ "subElem0",
+ "subElem1",
+ "subElem2",
+ "arrayElem0",
+ "arrayElem1",
+ "subElem3",
+ "subElem4",
+ "subElem5",
+ "subElem6",
+ "subElem_7",
+ };
+
+ final int subElemArraySizes[] = {
+ 1,
+ 1,
+ 1,
+ 2,
+ 5,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ };
+
+ final int subElemOffsets[] = {
+ 0,
+ 4,
+ 8,
+ 12,
+ 20,
+ 40,
+ 44,
+ 48,
+ 64,
+ 80,
+ };
+
+ protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Element", ctx);
+ mRes = res;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_element s) {
+ simpleElem = Element.F32_3(RS);
+ complexElem = ScriptField_ComplexStruct.createElement(RS);
+ s.set_simpleElem(simpleElem);
+ s.set_complexElem(complexElem);
+
+ ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
+ s.bind_complexStruct(data);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_element s = new ScriptC_element(pRS, mRes, R.raw.element);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_element_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+
+ int subElemCount = simpleElem.getSubElementCount();
+ _RS_ASSERT("subElemCount == 0", subElemCount == 0);
+ _RS_ASSERT("simpleElem.getDataKind() == USER",
+ simpleElem.getDataKind() == DataKind.USER);
+ _RS_ASSERT("simpleElem.getDataType() == FLOAT_32",
+ simpleElem.getDataType() == DataType.FLOAT_32);
+
+ subElemCount = complexElem.getSubElementCount();
+ _RS_ASSERT("subElemCount == 10", subElemCount == 10);
+ _RS_ASSERT("complexElem.getDataKind() == USER",
+ complexElem.getDataKind() == DataKind.USER);
+ _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE",
+ complexElem.getDataType() == DataType.NONE);
+ _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
+ complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof);
+
+ for (int i = 0; i < subElemCount; i ++) {
+ _RS_ASSERT("complexElem.getSubElement(i) != null",
+ complexElem.getSubElement(i) != null);
+ _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
+ complexElem.getSubElementName(i).equals(subElemNames[i]));
+ _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
+ complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
+ _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
+ complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
+ }
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
new file mode 100644
index 0000000..0c93702
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Mesh.*;
+
+public class UT_mesh extends UnitTest {
+ private Resources mRes;
+
+ Mesh mesh;
+
+ protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Mesh", ctx);
+ mRes = res;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_mesh s) {
+ Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10);
+ Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10);
+
+ Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10);
+ Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10);
+
+ Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS);
+ mBuilder.addVertexAllocation(vAlloc0);
+ mBuilder.addVertexAllocation(vAlloc1);
+
+ mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT);
+ mBuilder.addIndexSetType(Primitive.LINE);
+ mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE);
+
+ s.set_mesh(mBuilder.create());
+ s.set_vertexAlloc0(vAlloc0);
+ s.set_vertexAlloc1(vAlloc1);
+ s.set_indexAlloc0(iAlloc0);
+ s.set_indexAlloc2(iAlloc2);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_mesh s = new ScriptC_mesh(pRS, mRes, R.raw.mesh);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_mesh_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
new file mode 100644
index 0000000..1de4d71
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramRaster.CullMode;
+
+public class UT_program_raster extends UnitTest {
+ private Resources mRes;
+
+ ProgramRaster pointSpriteEnabled;
+ ProgramRaster cullMode;
+
+ protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "ProgramRaster", ctx);
+ mRes = res;
+ }
+
+ private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
+ ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
+ b.setCullMode(CullMode.BACK);
+ b.setPointSpriteEnabled(false);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
+ ProgramRaster.Builder b = getDefaultBuilder(RS);
+ pointSpriteEnabled = b.setPointSpriteEnabled(true).create();
+ b = getDefaultBuilder(RS);
+ cullMode = b.setCullMode(CullMode.FRONT).create();
+
+ s.set_pointSpriteEnabled(pointSpriteEnabled);
+ s.set_cullMode(cullMode);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_program_raster_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+ _RS_ASSERT("pointSpriteEnabled.getPointSpriteEnabled() == true",
+ pointSpriteEnabled.getPointSpriteEnabled() == true);
+ _RS_ASSERT("pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK",
+ pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK);
+
+ _RS_ASSERT("cullMode.getPointSpriteEnabled() == false",
+ cullMode.getPointSpriteEnabled() == false);
+ _RS_ASSERT("cullMode.getCullMode() == ProgramRaster.CullMode.FRONT",
+ cullMode.getCullMode() == ProgramRaster.CullMode.FRONT);
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
new file mode 100644
index 0000000..72a401d
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.Builder;
+import android.renderscript.ProgramStore.DepthFunc;
+
+public class UT_program_store extends UnitTest {
+ private Resources mRes;
+
+ ProgramStore ditherEnable;
+ ProgramStore colorRWriteEnable;
+ ProgramStore colorGWriteEnable;
+ ProgramStore colorBWriteEnable;
+ ProgramStore colorAWriteEnable;
+ ProgramStore blendSrc;
+ ProgramStore blendDst;
+ ProgramStore depthWriteEnable;
+ ProgramStore depthFunc;
+
+ protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "ProgramStore", ctx);
+ mRes = res;
+ }
+
+ private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
+ ProgramStore.Builder b = new ProgramStore.Builder(RS);
+ b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
+ b.setColorMaskEnabled(false, false, false, false);
+ b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ b.setDepthMaskEnabled(false);
+ b.setDitherEnabled(false);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
+ ProgramStore.Builder b = getDefaultBuilder(RS);
+ ditherEnable = b.setDitherEnabled(true).create();
+
+ b = getDefaultBuilder(RS);
+ colorRWriteEnable = b.setColorMaskEnabled(true, false, false, false).create();
+
+ b = getDefaultBuilder(RS);
+ colorGWriteEnable = b.setColorMaskEnabled(false, true, false, false).create();
+
+ b = getDefaultBuilder(RS);
+ colorBWriteEnable = b.setColorMaskEnabled(false, false, true, false).create();
+
+ b = getDefaultBuilder(RS);
+ colorAWriteEnable = b.setColorMaskEnabled(false, false, false, true).create();
+
+ b = getDefaultBuilder(RS);
+ blendSrc = b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
+ ProgramStore.BlendDstFunc.ZERO).create();
+
+ b = getDefaultBuilder(RS);
+ blendDst = b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
+ ProgramStore.BlendDstFunc.DST_ALPHA).create();
+
+ b = getDefaultBuilder(RS);
+ depthWriteEnable = b.setDepthMaskEnabled(true).create();
+
+ b = getDefaultBuilder(RS);
+ depthFunc = b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create();
+
+ s.set_ditherEnable(ditherEnable);
+ s.set_colorRWriteEnable(colorRWriteEnable);
+ s.set_colorGWriteEnable(colorGWriteEnable);
+ s.set_colorBWriteEnable(colorBWriteEnable);
+ s.set_colorAWriteEnable(colorAWriteEnable);
+ s.set_blendSrc(blendSrc);
+ s.set_blendDst(blendDst);
+ s.set_depthWriteEnable(depthWriteEnable);
+ s.set_depthFunc(depthFunc);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_program_store_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ void checkObject(ProgramStore ps,
+ boolean depthMask,
+ DepthFunc df,
+ BlendSrcFunc bsf,
+ BlendDstFunc bdf,
+ boolean R,
+ boolean G,
+ boolean B,
+ boolean A,
+ boolean dither) {
+ _RS_ASSERT("ps.getDepthMaskEnabled() == depthMask", ps.getDepthMaskEnabled() == depthMask);
+ _RS_ASSERT("ps.getDepthFunc() == df", ps.getDepthFunc() == df);
+ _RS_ASSERT("ps.getBlendSrcFunc() == bsf", ps.getBlendSrcFunc() == bsf);
+ _RS_ASSERT("ps.getBlendDstFunc() == bdf", ps.getBlendDstFunc() == bdf);
+ _RS_ASSERT("ps.getColorMaskREnabled() == R", ps.getColorMaskREnabled() == R);
+ _RS_ASSERT("ps.getColorMaskGEnabled() == G", ps.getColorMaskGEnabled() == G);
+ _RS_ASSERT("ps.getColorMaskBEnabled() == B", ps.getColorMaskBEnabled() == B);
+ _RS_ASSERT("ps.getColorMaskAEnabled() == A", ps.getColorMaskAEnabled() == A);
+ _RS_ASSERT("ps.getDitherEnabled() == dither", ps.getDitherEnabled() == dither);
+ }
+
+ void varyBuilderColorAndDither(ProgramStore.Builder pb,
+ boolean depthMask,
+ DepthFunc df,
+ BlendSrcFunc bsf,
+ BlendDstFunc bdf) {
+ for (int r = 0; r <= 1; r++) {
+ boolean isR = (r == 1);
+ for (int g = 0; g <= 1; g++) {
+ boolean isG = (g == 1);
+ for (int b = 0; b <= 1; b++) {
+ boolean isB = (b == 1);
+ for (int a = 0; a <= 1; a++) {
+ boolean isA = (a == 1);
+ for (int dither = 0; dither <= 1; dither++) {
+ boolean isDither = (dither == 1);
+ pb.setDitherEnabled(isDither);
+ pb.setColorMaskEnabled(isR, isG, isB, isA);
+ ProgramStore ps = pb.create();
+ checkObject(ps, depthMask, df, bsf, bdf, isR, isG, isB, isA, isDither);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void testJavaSide(RenderScript RS) {
+ for (int depth = 0; depth <= 1; depth++) {
+ boolean depthMask = (depth == 1);
+ for (DepthFunc df : DepthFunc.values()) {
+ for (BlendSrcFunc bsf : BlendSrcFunc.values()) {
+ for (BlendDstFunc bdf : BlendDstFunc.values()) {
+ ProgramStore.Builder b = new ProgramStore.Builder(RS);
+ b.setDepthFunc(df);
+ b.setDepthMaskEnabled(depthMask);
+ b.setBlendFunc(bsf, bdf);
+ varyBuilderColorAndDither(b, depthMask, df, bsf, bdf);
+ }
+ }
+ }
+ }
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testJavaSide(pRS);
+ testScriptSide(pRS);
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
new file mode 100644
index 0000000..c328cf6
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Sampler;
+import android.renderscript.Sampler.Value;
+
+public class UT_sampler extends UnitTest {
+ private Resources mRes;
+
+ Sampler minification;
+ Sampler magnification;
+ Sampler wrapS;
+ Sampler wrapT;
+ Sampler anisotropy;
+
+ protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Sampler", ctx);
+ mRes = res;
+ }
+
+ private Sampler.Builder getDefaultBuilder(RenderScript RS) {
+ Sampler.Builder b = new Sampler.Builder(RS);
+ b.setMinification(Value.NEAREST);
+ b.setMagnification(Value.NEAREST);
+ b.setWrapS(Value.CLAMP);
+ b.setWrapT(Value.CLAMP);
+ b.setAnisotropy(1.0f);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
+ Sampler.Builder b = getDefaultBuilder(RS);
+ b.setMinification(Value.LINEAR_MIP_LINEAR);
+ minification = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setMagnification(Value.LINEAR);
+ magnification = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setWrapS(Value.WRAP);
+ wrapS = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setWrapT(Value.WRAP);
+ wrapT = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setAnisotropy(8.0f);
+ anisotropy = b.create();
+
+ s.set_minification(minification);
+ s.set_magnification(magnification);
+ s.set_wrapS(wrapS);
+ s.set_wrapT(wrapT);
+ s.set_anisotropy(anisotropy);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_sampler_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+ _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST",
+ minification.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR",
+ minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR);
+ _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP",
+ minification.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP",
+ minification.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("minification.getAnisotropy() == 1.0f",
+ minification.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR",
+ magnification.getMagnification() == Sampler.Value.LINEAR);
+ _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST",
+ magnification.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP",
+ magnification.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP",
+ magnification.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("magnification.getAnisotropy() == 1.0f",
+ magnification.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST",
+ wrapS.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST",
+ wrapS.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP",
+ wrapS.getWrapS() == Sampler.Value.WRAP);
+ _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP",
+ wrapS.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("wrapS.getAnisotropy() == 1.0f",
+ wrapS.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST",
+ wrapT.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST",
+ wrapT.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP",
+ wrapT.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP",
+ wrapT.getWrapT() == Sampler.Value.WRAP);
+ _RS_ASSERT("wrapT.getAnisotropy() == 1.0f",
+ wrapT.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST",
+ anisotropy.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST",
+ anisotropy.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP",
+ anisotropy.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP",
+ anisotropy.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f",
+ anisotropy.getAnisotropy() == 8.0f);
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
index edff83f..fbac124 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
@@ -58,8 +58,8 @@
protected void _RS_ASSERT(String message, boolean b) {
if(b == false) {
- result = -1;
Log.e(name, message + " FAILED");
+ failTest();
}
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
new file mode 100644
index 0000000..842249a
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
@@ -0,0 +1,58 @@
+#include "shared.rsh"
+
+// Testing constant array initialization
+float fa[4] = {1.0, 9.9999f};
+double da[2] = {7.0, 8.88888};
+char ca[4] = {'a', 7, 'b', 'c'};
+short sa[4] = {1, 1, 2, 3};
+int ia[4] = {5, 8};
+long la[2] = {13, 21};
+long long lla[4] = {34};
+bool ba[3] = {true, false};
+
+void array_init_test() {
+ bool failed = false;
+
+ _RS_ASSERT(fa[0] == 1.0);
+ _RS_ASSERT(fa[1] == 9.9999f);
+ _RS_ASSERT(fa[2] == 0);
+ _RS_ASSERT(fa[3] == 0);
+
+ _RS_ASSERT(da[0] == 7.0);
+ _RS_ASSERT(da[1] == 8.88888);
+
+ _RS_ASSERT(ca[0] == 'a');
+ _RS_ASSERT(ca[1] == 7);
+ _RS_ASSERT(ca[2] == 'b');
+ _RS_ASSERT(ca[3] == 'c');
+
+ _RS_ASSERT(sa[0] == 1);
+ _RS_ASSERT(sa[1] == 1);
+ _RS_ASSERT(sa[2] == 2);
+ _RS_ASSERT(sa[3] == 3);
+
+ _RS_ASSERT(ia[0] == 5);
+ _RS_ASSERT(ia[1] == 8);
+ _RS_ASSERT(ia[2] == 0);
+ _RS_ASSERT(ia[3] == 0);
+
+ _RS_ASSERT(la[0] == 13);
+ _RS_ASSERT(la[1] == 21);
+
+ _RS_ASSERT(lla[0] == 34);
+ _RS_ASSERT(lla[1] == 0);
+ _RS_ASSERT(lla[2] == 0);
+ _RS_ASSERT(lla[3] == 0);
+
+ _RS_ASSERT(ba[0] == true);
+ _RS_ASSERT(ba[1] == false);
+ _RS_ASSERT(ba[2] == false);
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
new file mode 100644
index 0000000..0c42d84
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -0,0 +1,158 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_element simpleElem;
+rs_element complexElem;
+typedef struct ComplexStruct {
+ float subElem0;
+ float subElem1;
+ int subElem2;
+ float arrayElem0[2];
+ int arrayElem1[5];
+ char subElem3;
+ float subElem4;
+ float2 subElem5;
+ float3 subElem6;
+ float4 subElem_7;
+} ComplexStruct_t;
+
+ComplexStruct_t *complexStruct;
+
+static const char *subElemNames[] = {
+ "subElem0",
+ "subElem1",
+ "subElem2",
+ "arrayElem0",
+ "arrayElem1",
+ "subElem3",
+ "subElem4",
+ "subElem5",
+ "subElem6",
+ "subElem_7",
+};
+
+static uint32_t subElemNamesSizes[] = {
+ 8,
+ 8,
+ 8,
+ 10,
+ 10,
+ 8,
+ 8,
+ 8,
+ 8,
+ 9,
+};
+
+static uint32_t subElemArraySizes[] = {
+ 1,
+ 1,
+ 1,
+ 2,
+ 5,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+};
+
+static void resetStruct() {
+ uint8_t *bytePtr = (uint8_t*)complexStruct;
+ uint32_t sizeOfStruct = sizeof(*complexStruct);
+ for(uint32_t i = 0; i < sizeOfStruct; i ++) {
+ bytePtr[i] = 0;
+ }
+}
+
+static bool equals(const char *name0, const char * name1, uint32_t len) {
+ for (uint32_t i = 0; i < len; i ++) {
+ if (name0[i] != name1[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool test_element_getters() {
+ bool failed = false;
+
+ uint32_t subElemOffsets[10];
+ uint32_t index = 0;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7 - (uint32_t)complexStruct;
+
+ uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
+ _RS_ASSERT(subElemCount == 0);
+ _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER);
+ _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
+ _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3);
+
+ subElemCount = rsElementGetSubElementCount(complexElem);
+ _RS_ASSERT(subElemCount == 10);
+ _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
+ _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
+ _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
+ _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+
+ char buffer[64];
+ for (uint32_t i = 0; i < subElemCount; i ++) {
+ rs_element subElem = rsElementGetSubElement(complexElem, i);
+ _RS_ASSERT(rsIsObject(subElem));
+
+ _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
+
+ uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
+ _RS_ASSERT(written == subElemNamesSizes[i]);
+ _RS_ASSERT(equals(buffer, subElemNames[i], written));
+
+ _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
+ _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
+ }
+
+ // Tests error checking
+ rs_element subElem = rsElementGetSubElement(complexElem, subElemCount);
+ _RS_ASSERT(!rsIsObject(subElem));
+
+ _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0);
+
+ _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0);
+ _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0);
+ _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0);
+ uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5);
+ _RS_ASSERT(written == 4);
+ _RS_ASSERT(buffer[4] == '\0');
+
+ _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0);
+ _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0);
+
+ if (failed) {
+ rsDebug("test_element_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_element_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void element_test() {
+ bool failed = false;
+ failed |= test_element_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
new file mode 100644
index 0000000..627ab99
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
@@ -0,0 +1,64 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_mesh mesh;
+rs_allocation vertexAlloc0;
+rs_allocation vertexAlloc1;
+
+rs_allocation indexAlloc0;
+rs_allocation indexAlloc2;
+
+static bool test_mesh_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2);
+ _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3);
+
+ rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0);
+ rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1);
+ rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2);
+ _RS_ASSERT(meshV0.p == vertexAlloc0.p);
+ _RS_ASSERT(meshV1.p == vertexAlloc1.p);
+ _RS_ASSERT(!rsIsObject(meshV2));
+
+ rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0);
+ rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1);
+ rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2);
+ rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3);
+ _RS_ASSERT(meshI0.p == indexAlloc0.p);
+ _RS_ASSERT(!rsIsObject(meshI1));
+ _RS_ASSERT(meshI2.p == indexAlloc2.p);
+ _RS_ASSERT(!rsIsObject(meshI3));
+
+ rs_primitive p0 = rsMeshGetPrimitive(mesh, 0);
+ rs_primitive p1 = rsMeshGetPrimitive(mesh, 1);
+ rs_primitive p2 = rsMeshGetPrimitive(mesh, 2);
+ rs_primitive p3 = rsMeshGetPrimitive(mesh, 3);
+
+ _RS_ASSERT(p0 == RS_PRIMITIVE_POINT);
+ _RS_ASSERT(p1 == RS_PRIMITIVE_LINE);
+ _RS_ASSERT(p2 == RS_PRIMITIVE_TRIANGLE);
+ _RS_ASSERT(p3 == RS_PRIMITIVE_INVALID);
+
+ if (failed) {
+ rsDebug("test_mesh_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_mesh_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void mesh_test() {
+ bool failed = false;
+ failed |= test_mesh_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
new file mode 100644
index 0000000..11b8c30
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_raster pointSpriteEnabled;
+rs_program_raster cullMode;
+
+static bool test_program_raster_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+ _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+
+ _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+ _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+
+ if (failed) {
+ rsDebug("test_program_raster_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_program_raster_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void program_raster_test() {
+ bool failed = false;
+ failed |= test_program_raster_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
new file mode 100644
index 0000000..3cd8a20
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -0,0 +1,128 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_store ditherEnable;
+rs_program_store colorRWriteEnable;
+rs_program_store colorGWriteEnable;
+rs_program_store colorBWriteEnable;
+rs_program_store colorAWriteEnable;
+rs_program_store blendSrc;
+rs_program_store blendDst;
+rs_program_store depthWriteEnable;
+rs_program_store depthFunc;
+
+static bool test_program_store_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+
+ if (failed) {
+ rsDebug("test_program_store_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_program_store_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void program_store_test() {
+ bool failed = false;
+ failed |= test_program_store_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
new file mode 100644
index 0000000..ac9a549
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -0,0 +1,63 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+rs_sampler minification;
+rs_sampler magnification;
+rs_sampler wrapS;
+rs_sampler wrapT;
+rs_sampler anisotropy;
+
+static bool test_sampler_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+ _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+ _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+ _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+
+ if (failed) {
+ rsDebug("test_sampler_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_sampler_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void sampler_test() {
+ bool failed = false;
+ failed |= test_sampler_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/SerialChat/Android.mk b/tests/SerialChat/Android.mk
new file mode 100644
index 0000000..a534e1a
--- /dev/null
+++ b/tests/SerialChat/Android.mk
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SerialChat
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SerialChat/AndroidManifest.xml b/tests/SerialChat/AndroidManifest.xml
new file mode 100644
index 0000000..0efdb58
--- /dev/null
+++ b/tests/SerialChat/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.serialchat">
+
+ <uses-permission android:name="android.permission.SERIAL_PORT"/>
+
+ <application android:label="Serial Chat">
+ <activity android:name="SerialChat" android:label="Serial Chat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/SerialChat/res/layout/serial_chat.xml b/tests/SerialChat/res/layout/serial_chat.xml
new file mode 100644
index 0000000..596ecbf
--- /dev/null
+++ b/tests/SerialChat/res/layout/serial_chat.xml
@@ -0,0 +1,47 @@
+<?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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <ScrollView android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ >
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+ </ScrollView>
+
+ <EditText android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:capitalize="sentences"
+ android:autoText="true"
+ android:singleLine="true"
+ />
+
+</LinearLayout>
+
+
diff --git a/tests/SerialChat/src/com/android/serialchat/SerialChat.java b/tests/SerialChat/src/com/android/serialchat/SerialChat.java
new file mode 100644
index 0000000..faec312
--- /dev/null
+++ b/tests/SerialChat/src/com/android/serialchat/SerialChat.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.serialchat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.SerialManager;
+import android.hardware.SerialPort;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+public class SerialChat extends Activity implements Runnable, TextView.OnEditorActionListener {
+
+ private static final String TAG = "SerialChat";
+
+ private TextView mLog;
+ private EditText mEditText;
+ private ByteBuffer mInputBuffer;
+ private ByteBuffer mOutputBuffer;
+ private SerialManager mSerialManager;
+ private SerialPort mSerialPort;
+ private boolean mPermissionRequestPending;
+
+ private static final int MESSAGE_LOG = 1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mSerialManager = (SerialManager)getSystemService(Context.SERIAL_SERVICE);
+ setContentView(R.layout.serial_chat);
+ mLog = (TextView)findViewById(R.id.log);
+ mEditText = (EditText)findViewById(R.id.message);
+ mEditText.setOnEditorActionListener(this);
+
+ if (false) {
+ mInputBuffer = ByteBuffer.allocateDirect(1024);
+ mOutputBuffer = ByteBuffer.allocateDirect(1024);
+ } else {
+ mInputBuffer = ByteBuffer.allocate(1024);
+ mOutputBuffer = ByteBuffer.allocate(1024);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ String[] ports = mSerialManager.getSerialPorts();
+ if (ports != null && ports.length > 0) {
+ try {
+ mSerialPort = mSerialManager.openSerialPort(ports[0], 115200);
+ if (mSerialPort != null) {
+ new Thread(this).start();
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mSerialPort != null) {
+ try {
+ mSerialPort.close();
+ } catch (IOException e) {
+ }
+ mSerialPort = null;
+ }
+ super.onDestroy();
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (/* actionId == EditorInfo.IME_ACTION_DONE && */ mSerialPort != null) {
+ try {
+ String text = v.getText().toString();
+ Log.d(TAG, "write: " + text);
+ byte[] bytes = text.getBytes();
+ mOutputBuffer.clear();
+ mOutputBuffer.put(bytes);
+ mSerialPort.write(mOutputBuffer, bytes.length);
+ } catch (IOException e) {
+ Log.e(TAG, "write failed", e);
+ }
+ v.setText("");
+ return true;
+ }
+ Log.d(TAG, "onEditorAction " + actionId + " event: " + event);
+ return false;
+ }
+
+ public void run() {
+ Log.d(TAG, "run");
+ int ret = 0;
+ byte[] buffer = new byte[1024];
+ while (ret >= 0) {
+ try {
+ Log.d(TAG, "calling read");
+ mInputBuffer.clear();
+ ret = mSerialPort.read(mInputBuffer);
+ Log.d(TAG, "read returned " + ret);
+ mInputBuffer.get(buffer, 0, ret);
+ } catch (IOException e) {
+ Log.e(TAG, "read failed", e);
+ break;
+ }
+
+ if (ret > 0) {
+ Message m = Message.obtain(mHandler, MESSAGE_LOG);
+ String text = new String(buffer, 0, ret);
+ Log.d(TAG, "chat: " + text);
+ m.obj = text;
+ mHandler.sendMessage(m);
+ }
+ }
+ Log.d(TAG, "thread out");
+ }
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_LOG:
+ mLog.setText(mLog.getText() + (String)msg.obj);
+ break;
+ }
+ }
+ };
+}
+
+
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
index 5f53a9b..1a2dcb9 100644
--- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -19,12 +19,21 @@
import com.android.internal.os.RuntimeInit;
import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.test.AndroidTestCase;
import android.util.Log;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
/**
* This smoke test is designed to quickly sniff for any error conditions
@@ -32,53 +41,125 @@
*/
public class ProcessErrorsTest extends AndroidTestCase {
- private final String TAG = "ProcessErrorsTest";
+ private static final String TAG = "ProcessErrorsTest";
protected ActivityManager mActivityManager;
+ protected PackageManager mPackageManager;
@Override
public void setUp() throws Exception {
super.setUp();
- mActivityManager = (ActivityManager)
+ mActivityManager = (ActivityManager)
getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ mPackageManager = getContext().getPackageManager();
}
public void testSetUpConditions() throws Exception {
assertNotNull(mActivityManager);
+ assertNotNull(mPackageManager);
}
public void testNoProcessErrors() throws Exception {
- List<ActivityManager.ProcessErrorStateInfo> errList;
+ final String reportMsg = checkForProcessErrors();
+ if (reportMsg != null) {
+ Log.w(TAG, reportMsg);
+ }
+
+ // report a non-empty list back to the test framework
+ assertNull(reportMsg, reportMsg);
+ }
+
+ private String checkForProcessErrors() throws Exception {
+ List<ProcessErrorStateInfo> errList;
errList = mActivityManager.getProcessesInErrorState();
// note: this contains information about each process that is currently in an error
// condition. if the list is empty (null) then "we're good".
// if the list is non-empty, then it's useful to report the contents of the list
- // we'll put a copy in the log, and we'll report it back to the framework via the assert.
final String reportMsg = reportListContents(errList);
- if (reportMsg != null) {
- Log.w(TAG, reportMsg);
- }
-
- // report a non-empty list back to the test framework
- assertNull(reportMsg, errList);
+ return reportMsg;
}
-
+
+ /**
+ * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
+ * happened while doing so.
+ * <p />
+ * FIXME: Doesn't detect multiple crashing apps properly, since the crash dialog for the
+ * FIXME: first app doesn't go away.
+ */
+ public void testRunAllActivities() throws Exception {
+ final Intent home = new Intent(Intent.ACTION_MAIN);
+ home.addCategory(Intent.CATEGORY_HOME);
+ home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ final Intent launchable = new Intent(Intent.ACTION_MAIN);
+ launchable.addCategory(Intent.CATEGORY_LAUNCHER);
+ final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0);
+ final Set<ProcessError> errSet = new HashSet<ProcessError>();
+
+ for (ResolveInfo info : activities) {
+ Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
+ info.activityInfo.name));
+
+ // build an Intent to launch the app
+ final ComponentName component = new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(component);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // launch app, and wait 7 seconds for it to start/settle
+ getContext().startActivity(intent);
+ try {
+ Thread.sleep(7000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ // See if there are any errors
+ Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState();
+ if (procs != null) {
+ errSet.addAll(ProcessError.fromCollection(procs));
+ }
+
+ // Send the "home" intent and wait 2 seconds for us to get there
+ getContext().startActivity(home);
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ if (!errSet.isEmpty()) {
+ fail(String.format("Got %d errors: %s", errSet.size(),
+ reportWrappedListContents(errSet)));
+ }
+ }
+
+ private String reportWrappedListContents(Collection<ProcessError> errList) {
+ List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
+ for (ProcessError err : errList) {
+ newList.add(err.info);
+ }
+ return reportListContents(newList);
+ }
+
/**
* This helper function will dump the actual error reports.
*
* @param errList The error report containing one or more error records.
* @return Returns a string containing all of the errors.
*/
- private String reportListContents(List<ActivityManager.ProcessErrorStateInfo> errList) {
+ private String reportListContents(Collection<ProcessErrorStateInfo> errList) {
if (errList == null) return null;
StringBuilder builder = new StringBuilder();
- Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
+ Iterator<ProcessErrorStateInfo> iter = errList.iterator();
while (iter.hasNext()) {
- ActivityManager.ProcessErrorStateInfo entry = iter.next();
+ ProcessErrorStateInfo entry = iter.next();
String condition;
switch (entry.condition) {
@@ -96,8 +177,77 @@
builder.append("Process error ").append(condition).append(" ");
builder.append(" ").append(entry.shortMsg);
builder.append(" detected in ").append(entry.processName).append(" ").append(entry.tag);
+ builder.append("\n");
}
return builder.toString();
}
-
+
+ /**
+ * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
+ * crashes are considered equal).
+ */
+ private static class ProcessError {
+ public final ProcessErrorStateInfo info;
+
+ public ProcessError(ProcessErrorStateInfo newInfo) {
+ info = newInfo;
+ }
+
+ public static Collection<ProcessError> fromCollection(Collection<ProcessErrorStateInfo> in)
+ {
+ List<ProcessError> out = new ArrayList<ProcessError>(in.size());
+ for (ProcessErrorStateInfo info : in) {
+ out.add(new ProcessError(info));
+ }
+ return out;
+ }
+
+ private boolean strEquals(String a, String b) {
+ if ((a == null) && (b == null)) {
+ return true;
+ } else if ((a == null) || (b == null)) {
+ return false;
+ } else {
+ return a.equals(b);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) return false;
+ if (!(other instanceof ProcessError)) return false;
+ ProcessError peOther = (ProcessError) other;
+
+ return (info.condition == peOther.info.condition)
+ && strEquals(info.longMsg, peOther.info.longMsg)
+ && (info.pid == peOther.info.pid)
+ && strEquals(info.processName, peOther.info.processName)
+ && strEquals(info.shortMsg, peOther.info.shortMsg)
+ && strEquals(info.stackTrace, peOther.info.stackTrace)
+ && strEquals(info.tag, peOther.info.tag)
+ && (info.uid == peOther.info.uid);
+ }
+
+ private int hash(Object obj) {
+ if (obj == null) {
+ return 13;
+ } else {
+ return obj.hashCode();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int code = 17;
+ code += info.condition;
+ code *= hash(info.longMsg);
+ code += info.pid;
+ code *= hash(info.processName);
+ code *= hash(info.shortMsg);
+ code *= hash(info.stackTrace);
+ code *= hash(info.tag);
+ code += info.uid;
+ return code;
+ }
+ }
}
diff --git a/tests/SmokeTestApps/Android.mk b/tests/SmokeTestApps/Android.mk
new file mode 100644
index 0000000..3f5f011
--- /dev/null
+++ b/tests/SmokeTestApps/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SmokeTestTriggerApps
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/SmokeTestApps/AndroidManifest.xml b/tests/SmokeTestApps/AndroidManifest.xml
new file mode 100644
index 0000000..0f20107
--- /dev/null
+++ b/tests/SmokeTestApps/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.smoketest.triggers">
+
+ <application android:label="something">
+ <activity android:name=".CrashyApp"
+ android:label="Test Crashy App">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".CrashyApp2"
+ android:label="Test Crashy App2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".UnresponsiveApp"
+ android:label="Test Unresponsive App">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/SmokeTestApps/README b/tests/SmokeTestApps/README
new file mode 100644
index 0000000..04aa366
--- /dev/null
+++ b/tests/SmokeTestApps/README
@@ -0,0 +1,3 @@
+The apps in this folder are intentionally bad-behaving apps that are intended
+to trigger the smoke tests to fail. They are otherwise not useful.
+
diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java
new file mode 100644
index 0000000..c11b0f3
--- /dev/null
+++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest.triggers;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class CrashyApp extends Activity {
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ TextView tv = new TextView(this);
+ tv.setText("Hello, Crashy Android");
+ setContentView(tv);
+ }
+
+ @Override
+ public void onResume() {
+ ((String) null).length();
+ }
+}
diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java
new file mode 100644
index 0000000..3ef5b2b
--- /dev/null
+++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest.triggers;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class CrashyApp2 extends Activity {
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ TextView tv = new TextView(this);
+ tv.setText("Hello, Other Crashy Android");
+ setContentView(tv);
+ }
+
+
+ @Override
+ public void onResume() {
+ throw new RuntimeException("Two drums and a cymbal fall off a cliff...");
+ }
+}
diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java
new file mode 100644
index 0000000..1291897
--- /dev/null
+++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest.triggers;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class UnresponsiveApp extends Activity {
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ TextView tv = new TextView(this);
+ tv.setText("Hello, Unresponsive Android");
+ setContentView(tv);
+ }
+
+ @Override
+ public void onResume() {
+ // Attempt to provoke the ire of the ActivityManager
+ while (true) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp
index 04358ad..b5f6ff5 100644
--- a/tests/backup/backup_helper_test.cpp
+++ b/tests/backup/backup_helper_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
#include <stdio.h>
#include <string.h>
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 1c653e1..5924952 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -7,14 +7,14 @@
#define __AAPT_ASSETS_H
#include <stdlib.h>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/ResourceTypes.h>
+#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
+#include <utils/String8.h>
#include <utils/Vector.h>
-#include <utils/RefBase.h>
#include "ZipFile.h"
#include "Bundle.h"
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index ffbe875..6402e3c 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -8,7 +8,7 @@
#include "Images.h"
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/ByteOrder.h>
#include <png.h>
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 7a0499c..0c0b2ea 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -9,8 +9,8 @@
#include "XMLNode.h"
#include "ResourceFilter.h"
+#include <androidfw/ResourceTypes.h>
#include <utils/ByteOrder.h>
-#include <utils/ResourceTypes.h>
#include <stdarg.h>
#define NOISY(x) //x
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 255bdbf..86044ed 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -10,7 +10,7 @@
#include "Main.h"
#include "AaptAssets.h"
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/String16.h>
#include <utils/TextOutput.h>
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 0705be3..8057068 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -20,7 +20,7 @@
#define LOG_TAG "zip"
-#include <utils/ZipUtils.h>
+#include <androidfw/ZipUtils.h>
#include <utils/Log.h>
#include "ZipFile.h"
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 752ef7c..bfa6765 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -111,6 +111,21 @@
fprintf(to, "%s", this->value.c_str());
}
+StringLiteralExpression::StringLiteralExpression(const string& v)
+ :value(v)
+{
+}
+
+StringLiteralExpression::~StringLiteralExpression()
+{
+}
+
+void
+StringLiteralExpression::Write(FILE* to)
+{
+ fprintf(to, "\"%s\"", this->value.c_str());
+}
+
Variable::Variable()
:type(NULL),
name(),
@@ -277,6 +292,17 @@
{
}
+MethodCall::MethodCall(const string& n, int argc = 0, ...)
+ :obj(NULL),
+ clazz(NULL),
+ name(n)
+{
+ va_list args;
+ va_start(args, argc);
+ init(argc, args);
+ va_end(args);
+}
+
MethodCall::MethodCall(Expression* o, const string& n)
:obj(o),
clazz(NULL),
@@ -367,11 +393,29 @@
{
}
+NewExpression::NewExpression(Type* t, int argc = 0, ...)
+ :type(t)
+{
+ va_list args;
+ va_start(args, argc);
+ init(argc, args);
+ va_end(args);
+}
+
NewExpression::~NewExpression()
{
}
void
+NewExpression::init(int n, va_list args)
+{
+ for (int i=0; i<n; i++) {
+ Expression* expression = (Expression*)va_arg(args, void*);
+ this->arguments.push_back(expression);
+ }
+}
+
+void
NewExpression::Write(FILE* to)
{
fprintf(to, "new %s(", this->type->InstantiableName().c_str());
@@ -636,6 +680,20 @@
fprintf(to, "}\n");
}
+Break::Break()
+{
+}
+
+Break::~Break()
+{
+}
+
+void
+Break::Write(FILE* to)
+{
+ fprintf(to, "break;\n");
+}
+
Method::Method()
:ClassElement(),
modifiers(0),
@@ -678,7 +736,7 @@
fprintf(to, "%s\n", this->comment.c_str());
}
- WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
+ WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
if (this->returnType != NULL) {
string dim;
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 3156356..ead5e7a 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -54,6 +54,16 @@
virtual void Write(FILE* to);
};
+// TODO: also escape the contents. not needed for now
+struct StringLiteralExpression : public Expression
+{
+ string value;
+
+ StringLiteralExpression(const string& value);
+ virtual ~StringLiteralExpression();
+ virtual void Write(FILE* to);
+};
+
struct Variable : public Expression
{
Type* type;
@@ -104,7 +114,7 @@
virtual void Write(FILE* to) = 0;
};
-struct StatementBlock
+struct StatementBlock : public Statement
{
vector<Statement*> statements;
@@ -146,6 +156,7 @@
vector<string> exceptions;
MethodCall(const string& name);
+ MethodCall(const string& name, int argc, ...);
MethodCall(Expression* obj, const string& name);
MethodCall(Type* clazz, const string& name);
MethodCall(Expression* obj, const string& name, int argc, ...);
@@ -174,8 +185,12 @@
vector<Expression*> arguments;
NewExpression(Type* type);
+ NewExpression(Type* type, int argc, ...);
virtual ~NewExpression();
virtual void Write(FILE* to);
+
+private:
+ void init(int n, va_list args);
};
struct NewArrayExpression : public Expression
@@ -292,6 +307,13 @@
virtual void Write(FILE* to);
};
+struct Break : public Statement
+{
+ Break();
+ virtual ~Break();
+ virtual void Write(FILE* to);
+};
+
struct Method : public ClassElement
{
string comment;
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index 2ad0728..77d46ab 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -17,7 +17,9 @@
search_path.cpp \
AST.cpp \
Type.cpp \
- generate_java.cpp
+ generate_java.cpp \
+ generate_java_binder.cpp \
+ generate_java_rpc.cpp
LOCAL_CFLAGS := -g
LOCAL_MODULE := aidl
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 6b69864..d572af6 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -11,6 +11,7 @@
Type* FLOAT_TYPE;
Type* DOUBLE_TYPE;
Type* STRING_TYPE;
+Type* OBJECT_TYPE;
Type* CHAR_SEQUENCE_TYPE;
Type* TEXT_UTILS_TYPE;
Type* REMOTE_EXCEPTION_TYPE;
@@ -21,9 +22,13 @@
Type* BINDER_PROXY_TYPE;
Type* PARCEL_TYPE;
Type* PARCELABLE_INTERFACE_TYPE;
+Type* CONTEXT_TYPE;
Type* MAP_TYPE;
Type* LIST_TYPE;
Type* CLASSLOADER_TYPE;
+Type* RPC_DATA_TYPE;
+Type* RPC_ERROR_TYPE;
+Type* EVENT_FAKE_TYPE;
Expression* NULL_VALUE;
Expression* THIS_VALUE;
@@ -34,38 +39,48 @@
void
register_base_types()
{
- VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX");
+ VOID_TYPE = new BasicType("void",
+ "XXX", "XXX", "XXX", "XXX", "XXX",
+ "XXX", "XXX", "XXX", "XXX", "XXX");
NAMES.Add(VOID_TYPE);
BOOLEAN_TYPE = new BooleanType();
NAMES.Add(BOOLEAN_TYPE);
- BYTE_TYPE = new BasicType("byte", "writeByte", "readByte",
- "writeByteArray", "createByteArray", "readByteArray");
+ BYTE_TYPE = new BasicType("byte",
+ "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray",
+ "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
NAMES.Add(BYTE_TYPE);
CHAR_TYPE = new CharType();
NAMES.Add(CHAR_TYPE);
- INT_TYPE = new BasicType("int", "writeInt", "readInt",
- "writeIntArray", "createIntArray", "readIntArray");
+ INT_TYPE = new BasicType("int",
+ "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
+ "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
NAMES.Add(INT_TYPE);
- LONG_TYPE = new BasicType("long", "writeLong", "readLong",
- "writeLongArray", "createLongArray", "readLongArray");
+ LONG_TYPE = new BasicType("long",
+ "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
+ "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
NAMES.Add(LONG_TYPE);
- FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat",
- "writeFloatArray", "createFloatArray", "readFloatArray");
+ FLOAT_TYPE = new BasicType("float",
+ "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
+ "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
NAMES.Add(FLOAT_TYPE);
- DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble",
- "writeDoubleArray", "createDoubleArray", "readDoubleArray");
+ DOUBLE_TYPE = new BasicType("double",
+ "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
+ "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
NAMES.Add(DOUBLE_TYPE);
STRING_TYPE = new StringType();
NAMES.Add(STRING_TYPE);
+ OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+ NAMES.Add(OBJECT_TYPE);
+
CHAR_SEQUENCE_TYPE = new CharSequenceType();
NAMES.Add(CHAR_SEQUENCE_TYPE);
@@ -75,8 +90,7 @@
LIST_TYPE = new ListType();
NAMES.Add(LIST_TYPE);
- TEXT_UTILS_TYPE = new Type("android.text", "TextUtils",
- Type::BUILT_IN, false, false);
+ TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
NAMES.Add(TEXT_UTILS_TYPE);
REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -103,6 +117,19 @@
PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
NAMES.Add(PARCELABLE_INTERFACE_TYPE);
+ CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+ NAMES.Add(CONTEXT_TYPE);
+
+ RPC_DATA_TYPE = new RpcDataType();
+ NAMES.Add(RPC_DATA_TYPE);
+
+ RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError",
+ true, __FILE__, __LINE__);
+ NAMES.Add(RPC_ERROR_TYPE);
+
+ EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
+ NAMES.Add(EVENT_FAKE_TYPE);
+
CLASSLOADER_TYPE = new ClassLoaderType();
NAMES.Add(CLASSLOADER_TYPE);
@@ -129,27 +156,30 @@
// ================================================================
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
+ bool canBeOut)
:m_package(),
m_name(name),
m_declFile(""),
m_declLine(-1),
m_kind(kind),
m_canWriteToParcel(canWriteToParcel),
+ m_canWriteToRpcData(canWriteToRpcData),
m_canBeOut(canBeOut)
{
m_qualifiedName = name;
}
Type::Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
- const string& declFile, int declLine)
+ int kind, bool canWriteToParcel, bool canWriteToRpcData,
+ bool canBeOut, const string& declFile, int declLine)
:m_package(package),
m_name(name),
m_declFile(declFile),
m_declLine(declLine),
m_kind(kind),
m_canWriteToParcel(canWriteToParcel),
+ m_canWriteToRpcData(canWriteToRpcData),
m_canBeOut(canBeOut)
{
if (package.length() > 0) {
@@ -182,6 +212,12 @@
}
string
+Type::RpcCreatorName() const
+{
+ return "";
+}
+
+string
Type::InstantiableName() const
{
return QualifiedName();
@@ -244,6 +280,26 @@
}
void
+Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+ __FILE__, __LINE__, m_qualifiedName.c_str());
+ addTo->Add(new LiteralExpression("/* WriteToRpcData error "
+ + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+ __FILE__, __LINE__, m_qualifiedName.c_str());
+ addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
+ + m_qualifiedName + " */"));
+}
+
+void
Type::SetQualifiedName(const string& qualified)
{
m_qualifiedName = qualified;
@@ -264,29 +320,35 @@
// ================================================================
-BasicType::BasicType(const string& name, const string& marshallMethod,
- const string& unmarshallMethod,
- const string& writeArray, const string& createArray,
- const string& readArray)
- :Type(name, BUILT_IN, true, false),
- m_marshallMethod(marshallMethod),
- m_unmarshallMethod(unmarshallMethod),
- m_writeArrayMethod(writeArray),
- m_createArrayMethod(createArray),
- m_readArrayMethod(readArray)
+BasicType::BasicType(const string& name, const string& marshallParcel,
+ const string& unmarshallParcel, const string& writeArrayParcel,
+ const string& createArrayParcel, const string& readArrayParcel,
+ const string& marshallRpc, const string& unmarshallRpc,
+ const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
+ :Type(name, BUILT_IN, true, true, false),
+ m_marshallParcel(marshallParcel),
+ m_unmarshallParcel(unmarshallParcel),
+ m_writeArrayParcel(writeArrayParcel),
+ m_createArrayParcel(createArrayParcel),
+ m_readArrayParcel(readArrayParcel),
+ m_marshallRpc(marshallRpc),
+ m_unmarshallRpc(unmarshallRpc),
+ m_writeArrayRpc(writeArrayRpc),
+ m_createArrayRpc(createArrayRpc),
+ m_readArrayRpc(readArrayRpc)
{
}
void
BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
- addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
}
void
BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
+ addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
}
bool
@@ -298,27 +360,40 @@
void
BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
- addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
}
void
BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
+ addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
}
void
BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
- addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
}
+void
+BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
+}
+
+void
+BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
+}
// ================================================================
BooleanType::BooleanType()
- :Type("boolean", BUILT_IN, true, false)
+ :Type("boolean", BUILT_IN, true, true, false)
{
}
@@ -362,11 +437,24 @@
addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
}
+void
+BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
+}
+
+void
+BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
+}
// ================================================================
CharType::CharType()
- :Type("char", BUILT_IN, true, false)
+ :Type("char", BUILT_IN, true, true, false)
{
}
@@ -408,10 +496,24 @@
addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
}
+void
+CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putChar", 2, k, v));
+}
+
+void
+CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
+}
+
// ================================================================
StringType::StringType()
- :Type("java.lang", "String", BUILT_IN, true, false)
+ :Type("java.lang", "String", BUILT_IN, true, true, false)
{
}
@@ -458,10 +560,24 @@
addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
}
+void
+StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putString", 2, k, v));
+}
+
+void
+StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable**)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
+}
+
// ================================================================
CharSequenceType::CharSequenceType()
- :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+ :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
{
}
@@ -521,7 +637,7 @@
// ================================================================
RemoteExceptionType::RemoteExceptionType()
- :Type("android.os", "RemoteException", BUILT_IN, false, false)
+ :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
{
}
@@ -540,7 +656,7 @@
// ================================================================
RuntimeExceptionType::RuntimeExceptionType()
- :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+ :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
{
}
@@ -560,7 +676,7 @@
// ================================================================
IBinderType::IBinderType()
- :Type("android.os", "IBinder", BUILT_IN, true, false)
+ :Type("android.os", "IBinder", BUILT_IN, true, false, false)
{
}
@@ -599,7 +715,7 @@
// ================================================================
IInterfaceType::IInterfaceType()
- :Type("android.os", "IInterface", BUILT_IN, false, false)
+ :Type("android.os", "IInterface", BUILT_IN, false, false, false)
{
}
@@ -619,7 +735,7 @@
// ================================================================
BinderType::BinderType()
- :Type("android.os", "Binder", BUILT_IN, false, false)
+ :Type("android.os", "Binder", BUILT_IN, false, false, false)
{
}
@@ -640,7 +756,7 @@
// ================================================================
BinderProxyType::BinderProxyType()
- :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+ :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
{
}
@@ -661,7 +777,7 @@
// ================================================================
ParcelType::ParcelType()
- :Type("android.os", "Parcel", BUILT_IN, false, false)
+ :Type("android.os", "Parcel", BUILT_IN, false, false, false)
{
}
@@ -680,7 +796,7 @@
// ================================================================
ParcelableInterfaceType::ParcelableInterfaceType()
- :Type("android.os", "Parcelable", BUILT_IN, false, false)
+ :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
{
}
@@ -699,7 +815,7 @@
// ================================================================
MapType::MapType()
- :Type("java.util", "Map", BUILT_IN, true, true)
+ :Type("java.util", "Map", BUILT_IN, true, false, true)
{
}
@@ -729,8 +845,7 @@
}
void
-MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
{
EnsureClassLoader(addTo, cl);
addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
@@ -740,7 +855,7 @@
// ================================================================
ListType::ListType()
- :Type("java.util", "List", BUILT_IN, true, true)
+ :Type("java.util", "List", BUILT_IN, true, true, true)
{
}
@@ -771,24 +886,44 @@
addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
}
+void
+ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+}
+
+void
+ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
+}
// ================================================================
-ParcelableType::ParcelableType(const string& package, const string& name,
- bool builtIn, const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
- declFile, declLine)
+UserDataType::UserDataType(const string& package, const string& name,
+ bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+ const string& declFile, int declLine)
+ :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+ true, declFile, declLine)
{
}
string
-ParcelableType::CreatorName() const
+UserDataType::CreatorName() const
{
return QualifiedName() + ".CREATOR";
}
+string
+UserDataType::RpcCreatorName() const
+{
+ return QualifiedName() + ".RPC_CREATOR";
+}
+
void
-ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
// if (v != null) {
// parcel.writeInt(1);
@@ -811,7 +946,7 @@
}
void
-ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = CLASS.CREATOR.createFromParcel(parcel)
@@ -832,7 +967,7 @@
}
void
-ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
// TODO: really, we don't need to have this extra check, but we
@@ -848,20 +983,20 @@
}
bool
-ParcelableType::CanBeArray() const
+UserDataType::CanBeArray() const
{
return true;
}
void
-ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
BuildWriteToParcelFlags(flags)));
}
void
-ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
@@ -870,20 +1005,36 @@
}
void
-ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
v, new LiteralExpression(creator)));
}
+void
+UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ // data.putFlattenable(k, v);
+ addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
+}
+
+void
+UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl)
+{
+ // data.getFlattenable(k, CLASS.RPC_CREATOR);
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
+ new FieldVariable(v->type, "RPC_CREATOR"))));
+}
// ================================================================
InterfaceType::InterfaceType(const string& package, const string& name,
bool builtIn, bool oneway,
const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+ :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
declFile, declLine)
,m_oneway(oneway)
{
@@ -922,7 +1073,7 @@
GenericType::GenericType(const string& package, const string& name,
const vector<Type*>& args)
- :Type(package, name, BUILT_IN, true, true)
+ :Type(package, name, BUILT_IN, true, true, true)
{
m_args = args;
@@ -942,6 +1093,12 @@
SetQualifiedName(m_importName + gen);
}
+const vector<Type*>&
+GenericType::GenericArgumentTypes() const
+{
+ return m_args;
+}
+
string
GenericType::GenericArguments() const
{
@@ -1041,10 +1198,65 @@
}
}
+void
+GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
+ } else {
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+ }
+}
+
+void
+GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl)
+{
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k,
+ new LiteralExpression(generic->RpcCreatorName()))));
+ } else {
+ string classArg = GenericArgumentTypes()[0]->QualifiedName();
+ classArg += ".class";
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
+ new LiteralExpression(classArg))));
+ }
+}
+
+
+// ================================================================
+
+RpcDataType::RpcDataType()
+ :UserDataType("android.support.place.rpc", "RpcData", true, true, true)
+{
+}
+
+void
+RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
+}
+
+void
+RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
+}
+
+
// ================================================================
ClassLoaderType::ClassLoaderType()
- :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+ :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
{
}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 662e3a2..ae12720 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -13,7 +13,7 @@
// kinds
enum {
BUILT_IN,
- PARCELABLE,
+ USERDATA,
INTERFACE,
GENERATED
};
@@ -24,9 +24,9 @@
};
Type(const string& name, int kind, bool canWriteToParcel,
- bool canBeOut);
+ bool canWriteToRpcData, bool canBeOut);
Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
+ int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
const string& declFile = "", int declLine = -1);
virtual ~Type();
@@ -36,11 +36,13 @@
inline int Kind() const { return m_kind; }
inline string DeclFile() const { return m_declFile; }
inline int DeclLine() const { return m_declLine; }
- inline bool CanBeMarshalled() const { return m_canWriteToParcel; }
+ inline bool CanWriteToParcel() const { return m_canWriteToParcel; }
+ inline bool CanWriteToRpcData() const { return m_canWriteToRpcData; }
inline bool CanBeOutParameter() const { return m_canBeOut; }
virtual string ImportType() const;
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual string InstantiableName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -59,6 +61,11 @@
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
protected:
void SetQualifiedName(const string& qualified);
Expression* BuildWriteToParcelFlags(int flags);
@@ -74,17 +81,24 @@
int m_declLine;
int m_kind;
bool m_canWriteToParcel;
+ bool m_canWriteToRpcData;
bool m_canBeOut;
};
class BasicType : public Type
{
public:
- BasicType(const string& name, const string& marshallMethod,
- const string& unmarshallMethod,
- const string& writeArray,
- const string& createArray,
- const string& readArray);
+ BasicType(const string& name,
+ const string& marshallParcel,
+ const string& unmarshallParcel,
+ const string& writeArrayParcel,
+ const string& createArrayParcel,
+ const string& readArrayParcel,
+ const string& marshallRpc,
+ const string& unmarshallRpc,
+ const string& writeArrayRpc,
+ const string& createArrayRpc,
+ const string& readArrayRpc);
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
@@ -100,12 +114,22 @@
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
private:
- string m_marshallMethod;
- string m_unmarshallMethod;
- string m_writeArrayMethod;
- string m_createArrayMethod;
- string m_readArrayMethod;
+ string m_marshallParcel;
+ string m_unmarshallParcel;
+ string m_writeArrayParcel;
+ string m_createArrayParcel;
+ string m_readArrayParcel;
+ string m_marshallRpc;
+ string m_unmarshallRpc;
+ string m_writeArrayRpc;
+ string m_createArrayRpc;
+ string m_readArrayRpc;
};
class BooleanType : public Type
@@ -126,6 +150,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class CharType : public Type
@@ -146,6 +175,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
@@ -169,6 +203,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class CharSequenceType : public Type
@@ -305,15 +344,22 @@
Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
-class ParcelableType : public Type
+class UserDataType : public Type
{
public:
- ParcelableType(const string& package, const string& name,
- bool builtIn, const string& declFile, int declLine);
+ UserDataType(const string& package, const string& name,
+ bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+ const string& declFile = "", int declLine = -1);
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
@@ -330,6 +376,11 @@
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class InterfaceType : public Type
@@ -357,6 +408,7 @@
GenericType(const string& package, const string& name,
const vector<Type*>& args);
+ const vector<Type*>& GenericArgumentTypes() const;
string GenericArguments() const;
virtual string ImportType() const;
@@ -374,6 +426,22 @@
vector<Type*> m_args;
};
+class RpcDataType : public UserDataType
+{
+public:
+ RpcDataType();
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+};
+
+class ClassLoaderType : public Type
+{
+public:
+ ClassLoaderType();
+};
class GenericListType : public GenericType
{
@@ -391,16 +459,15 @@
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
private:
string m_creator;
};
-class ClassLoaderType : public Type
-{
-public:
- ClassLoaderType();
-};
-
class Namespace
{
public:
@@ -438,11 +505,13 @@
extern Type* VOID_TYPE;
extern Type* BOOLEAN_TYPE;
+extern Type* BYTE_TYPE;
extern Type* CHAR_TYPE;
extern Type* INT_TYPE;
extern Type* LONG_TYPE;
extern Type* FLOAT_TYPE;
extern Type* DOUBLE_TYPE;
+extern Type* OBJECT_TYPE;
extern Type* STRING_TYPE;
extern Type* CHAR_SEQUENCE_TYPE;
extern Type* TEXT_UTILS_TYPE;
@@ -455,6 +524,13 @@
extern Type* PARCEL_TYPE;
extern Type* PARCELABLE_INTERFACE_TYPE;
+extern Type* CONTEXT_TYPE;
+
+extern Type* RPC_DATA_TYPE;
+extern Type* RPC_ERROR_TYPE;
+extern Type* RPC_CONTEXT_TYPE;
+extern Type* EVENT_FAKE_TYPE;
+
extern Expression* NULL_VALUE;
extern Expression* THIS_VALUE;
extern Expression* SUPER_VALUE;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index fb4067a..8dbbf50 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -29,7 +29,7 @@
test_document(document_item_type* d)
{
while (d) {
- if (d->item_type == INTERFACE_TYPE) {
+ if (d->item_type == INTERFACE_TYPE_BINDER) {
interface_type* c = (interface_type*)d;
printf("interface %s %s {\n", c->package, c->name.data);
interface_item_type *q = (interface_item_type*)c->interface_items;
@@ -50,9 +50,14 @@
}
printf("}\n");
}
- else if (d->item_type == PARCELABLE_TYPE) {
- parcelable_type* b = (parcelable_type*)d;
- printf("parcelable %s %s;\n", b->package, b->name.data);
+ else if (d->item_type == USER_DATA_TYPE) {
+ user_data_type* b = (user_data_type*)d;
+ if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+ printf("parcelable %s %s;\n", b->package, b->name.data);
+ }
+ if ((b->flattening_methods & RPC_DATA) != 0) {
+ printf("flattenable %s %s;\n", b->package, b->name.data);
+ }
}
else {
printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
@@ -238,11 +243,12 @@
{
int err = 0;
while (items) {
- if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* p = (parcelable_type*)items;
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
err |= check_filename(filename, p->package, &p->name);
}
- else if (items->item_type == INTERFACE_TYPE) {
+ else if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* c = (interface_type*)items;
err |= check_filename(filename, c->package, &c->name);
}
@@ -264,8 +270,8 @@
{
case Type::INTERFACE:
return "an interface";
- case Type::PARCELABLE:
- return "a parcelable";
+ case Type::USERDATA:
+ return "a user data";
default:
return "ERROR";
}
@@ -290,12 +296,14 @@
int err = 0;
while (items) {
Type* type;
- if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* p = (parcelable_type*)items;
- type = new ParcelableType(p->package ? p->package : "",
- p->name.data, false, filename, p->name.lineno);
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
+ type = new UserDataType(p->package ? p->package : "", p->name.data,
+ false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
+ ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
}
- else if (items->item_type == INTERFACE_TYPE) {
+ else if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* c = (interface_type*)items;
type = new InterfaceType(c->package ? c->package : "",
c->name.data, false, c->oneway,
@@ -310,7 +318,7 @@
if (old == NULL) {
NAMES.Add(type);
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER) {
// for interfaces, also add the stub and proxy types, we don't
// bother checking these for duplicates, because the parser
// won't let us do it.
@@ -319,17 +327,30 @@
string name = c->name.data;
name += ".Stub";
Type* stub = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
+ name, Type::GENERATED, false, false, false,
filename, c->name.lineno);
NAMES.Add(stub);
name = c->name.data;
name += ".Stub.Proxy";
Type* proxy = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
+ name, Type::GENERATED, false, false, false,
filename, c->name.lineno);
NAMES.Add(proxy);
}
+ else if (items->item_type == INTERFACE_TYPE_RPC) {
+ // for interfaces, also add the service base type, we don't
+ // bother checking these for duplicates, because the parser
+ // won't let us do it.
+ interface_type* c = (interface_type*)items;
+
+ string name = c->name.data;
+ name += ".ServiceBase";
+ Type* base = new Type(c->package ? c->package : "",
+ name, Type::GENERATED, false, false, false,
+ filename, c->name.lineno);
+ NAMES.Add(base);
+ }
} else {
if (old->Kind() == Type::BUILT_IN) {
fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
@@ -381,7 +402,7 @@
}
static int
-check_method(const char* filename, method_type* m)
+check_method(const char* filename, int kind, method_type* m)
{
int err = 0;
@@ -394,10 +415,19 @@
return err;
}
- if (!returnType->CanBeMarshalled()) {
- fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
- m->type.type.lineno, m->type.type.data);
- err = 1;
+ if (returnType == EVENT_FAKE_TYPE) {
+ if (kind != INTERFACE_TYPE_RPC) {
+ fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
+ filename, m->type.type.lineno);
+ err = 1;
+ }
+ } else {
+ if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+ : returnType->CanWriteToRpcData())) {
+ fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+ m->type.type.lineno, m->type.type.data);
+ err = 1;
+ }
}
if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -429,14 +459,31 @@
err = 1;
goto next;
}
+
+ if (t == EVENT_FAKE_TYPE) {
+ fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
+ filename, m->type.type.lineno, arg->name.data, index,
+ arg->type.type.data);
+ err = 1;
+ goto next;
+ }
- if (!t->CanBeMarshalled()) {
+ if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
filename, m->type.type.lineno, index,
arg->type.type.data, arg->name.data);
err = 1;
}
+ if (returnType == EVENT_FAKE_TYPE
+ && convert_direction(arg->direction.data) != IN_PARAMETER) {
+ fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
+ filename, m->type.type.lineno, index,
+ arg->type.type.data, arg->name.data);
+ err = 1;
+ goto next;
+ }
+
if (arg->direction.data == NULL
&& (arg->type.dimension != 0 || t->CanBeOutParameter())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
@@ -479,7 +526,7 @@
// check that the name doesn't match a keyword
if (matches_keyword(arg->name.data)) {
fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
- " Java keyword\n",
+ " Java or aidl keyword\n",
filename, m->name.lineno, index, arg->name.data);
err = 1;
}
@@ -497,8 +544,9 @@
{
int err = 0;
while (items) {
- // (nothing to check for PARCELABLE_TYPE)
- if (items->item_type == INTERFACE_TYPE) {
+ // (nothing to check for USER_DATA_TYPE)
+ if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
map<string,method_type*> methodNames;
interface_type* c = (interface_type*)items;
@@ -507,7 +555,7 @@
if (member->item_type == METHOD_TYPE) {
method_type* m = (method_type*)member;
- err |= check_method(filename, m);
+ err |= check_method(filename, items->item_type, m);
// prevent duplicate methods
if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -544,26 +592,29 @@
const document_item_type* next = items->next;
if (items->next != NULL) {
int lineno = -1;
- if (next->item_type == INTERFACE_TYPE) {
+ if (next->item_type == INTERFACE_TYPE_BINDER) {
lineno = ((interface_type*)next)->interface_token.lineno;
}
- else if (next->item_type == PARCELABLE_TYPE) {
- lineno = ((parcelable_type*)next)->parcelable_token.lineno;
+ else if (next->item_type == INTERFACE_TYPE_RPC) {
+ lineno = ((interface_type*)next)->interface_token.lineno;
+ }
+ else if (next->item_type == USER_DATA_TYPE) {
+ lineno = ((user_data_type*)next)->keyword_token.lineno;
}
fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
filename, lineno);
return 1;
}
- if (items->item_type == PARCELABLE_TYPE) {
+ if (items->item_type == USER_DATA_TYPE) {
*onlyParcelable = true;
if (options.failOnParcelable) {
fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
- " parcelables,\n", filename,
- ((parcelable_type*)items)->parcelable_token.lineno);
- fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
- "don't need to go in the Makefile.\n", filename,
- ((parcelable_type*)items)->parcelable_token.lineno);
+ " parcelables or flattenables,\n", filename,
+ ((user_data_type*)items)->keyword_token.lineno);
+ fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+ "may not go in the Makefile.\n", filename,
+ ((user_data_type*)items)->keyword_token.lineno);
return 1;
}
} else {
@@ -598,7 +649,7 @@
slash = "";
}
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
fprintf(to, "%s: \\\n", options.outputFileName.c_str());
} else {
// parcelable: there's no output file.
@@ -658,12 +709,12 @@
generate_outputFileName(const Options& options, const document_item_type* items)
{
// items has already been checked to have only one interface.
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* type = (interface_type*)items;
return generate_outputFileName2(options, type->name, type->package);
- } else if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* type = (parcelable_type*)items;
+ } else if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* type = (user_data_type*)items;
return generate_outputFileName2(options, type->name, type->package);
}
@@ -734,24 +785,40 @@
document_item_type* doc;
if (0 == strcmp("parcelable", type)) {
- parcelable_type* parcl = (parcelable_type*)malloc(
- sizeof(parcelable_type));
- memset(parcl, 0, sizeof(parcelable_type));
- parcl->document_item.item_type = PARCELABLE_TYPE;
- parcl->parcelable_token.lineno = lineno;
- parcl->parcelable_token.data = strdup(type);
+ user_data_type* parcl = (user_data_type*)malloc(
+ sizeof(user_data_type));
+ memset(parcl, 0, sizeof(user_data_type));
+ parcl->document_item.item_type = USER_DATA_TYPE;
+ parcl->keyword_token.lineno = lineno;
+ parcl->keyword_token.data = strdup(type);
parcl->package = packagename ? strdup(packagename) : NULL;
parcl->name.lineno = lineno;
parcl->name.data = strdup(classname);
parcl->semicolon_token.lineno = lineno;
parcl->semicolon_token.data = strdup(";");
+ parcl->flattening_methods = PARCELABLE_DATA;
+ doc = (document_item_type*)parcl;
+ }
+ else if (0 == strcmp("flattenable", type)) {
+ user_data_type* parcl = (user_data_type*)malloc(
+ sizeof(user_data_type));
+ memset(parcl, 0, sizeof(user_data_type));
+ parcl->document_item.item_type = USER_DATA_TYPE;
+ parcl->keyword_token.lineno = lineno;
+ parcl->keyword_token.data = strdup(type);
+ parcl->package = packagename ? strdup(packagename) : NULL;
+ parcl->name.lineno = lineno;
+ parcl->name.data = strdup(classname);
+ parcl->semicolon_token.lineno = lineno;
+ parcl->semicolon_token.data = strdup(";");
+ parcl->flattening_methods = RPC_DATA;
doc = (document_item_type*)parcl;
}
else if (0 == strcmp("interface", type)) {
interface_type* iface = (interface_type*)malloc(
sizeof(interface_type));
memset(iface, 0, sizeof(interface_type));
- iface->document_item.item_type = INTERFACE_TYPE;
+ iface->document_item.item_type = INTERFACE_TYPE_BINDER;
iface->interface_token.lineno = lineno;
iface->interface_token.data = strdup(type);
iface->package = packagename ? strdup(packagename) : NULL;
@@ -923,9 +990,14 @@
}
document_item_type* doc = g_document;
string line;
- if (doc->item_type == PARCELABLE_TYPE) {
- line = "parcelable ";
- parcelable_type* parcelable = (parcelable_type*)doc;
+ if (doc->item_type == USER_DATA_TYPE) {
+ user_data_type* parcelable = (user_data_type*)doc;
+ if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+ line = "parcelable ";
+ }
+ if ((parcelable->flattening_methods & RPC_DATA) != 0) {
+ line = "flattenable ";
+ }
if (parcelable->package) {
line += parcelable->package;
line += '.';
@@ -995,5 +1067,3 @@
fprintf(stderr, "aidl: internal error\n");
return 1;
}
-
-
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index 9ca5deb..f203dbb0 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -63,8 +63,9 @@
} method_type;
enum {
- PARCELABLE_TYPE = 12,
- INTERFACE_TYPE
+ USER_DATA_TYPE = 12,
+ INTERFACE_TYPE_BINDER,
+ INTERFACE_TYPE_RPC
};
typedef struct document_item_type {
@@ -72,13 +73,21 @@
struct document_item_type* next;
} document_item_type;
-typedef struct parcelable_type {
+
+// for user_data_type.flattening_methods
+enum {
+ PARCELABLE_DATA = 0x1,
+ RPC_DATA = 0x2
+};
+
+typedef struct user_data_type {
document_item_type document_item;
- buffer_type parcelable_token;
+ buffer_type keyword_token; // only the first one
char* package;
buffer_type name;
buffer_type semicolon_token;
-} parcelable_type;
+ int flattening_methods;
+} user_data_type;
typedef struct interface_type {
document_item_type document_item;
@@ -100,7 +109,7 @@
method_type* method;
interface_item_type* interface_item;
interface_type* interface_obj;
- parcelable_type* parcelable;
+ user_data_type* user_data;
document_item_type* document_item;
} lexer_type;
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 567b1cf..7c5290c 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -81,6 +81,8 @@
/* keywords */
parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; }
interface { SET_BUFFER(INTERFACE); return INTERFACE; }
+flattenable { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
+rpc { SET_BUFFER(INTERFACE); return RPC; }
in { SET_BUFFER(IN); return IN; }
out { SET_BUFFER(OUT); return OUT; }
inout { SET_BUFFER(INOUT); return INOUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 3d65f17..cc04d15 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -19,6 +19,8 @@
%token ARRAY
%token PARCELABLE
%token INTERFACE
+%token FLATTENABLE
+%token RPC
%token IN
%token OUT
%token INOUT
@@ -72,36 +74,61 @@
;
declaration:
- parcelable_decl { $$.document_item = (document_item_type*)$1.parcelable; }
+ parcelable_decl { $$.document_item = (document_item_type*)$1.user_data; }
| interface_decl { $$.document_item = (document_item_type*)$1.interface_item; }
;
parcelable_decl:
- PARCELABLE IDENTIFIER ';' {
- parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
- b->document_item.item_type = PARCELABLE_TYPE;
+ PARCELABLE IDENTIFIER ';' {
+ user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+ b->document_item.item_type = USER_DATA_TYPE;
b->document_item.next = NULL;
- b->parcelable_token = $1.buffer;
+ b->keyword_token = $1.buffer;
b->name = $2.buffer;
b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
b->semicolon_token = $3.buffer;
- $$.parcelable = b;
+ b->flattening_methods = PARCELABLE_DATA;
+ $$.user_data = b;
}
| PARCELABLE ';' {
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
g_currentFilename, $1.buffer.lineno);
- $$.parcelable = NULL;
+ $$.user_data = NULL;
}
| PARCELABLE error ';' {
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
- $$.parcelable = NULL;
+ $$.user_data = NULL;
}
+ | FLATTENABLE IDENTIFIER ';' {
+ user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+ b->document_item.item_type = USER_DATA_TYPE;
+ b->document_item.next = NULL;
+ b->keyword_token = $1.buffer;
+ b->name = $2.buffer;
+ b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+ b->semicolon_token = $3.buffer;
+ b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
+ $$.user_data = b;
+ }
+ | FLATTENABLE ';' {
+ fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
+ g_currentFilename, $1.buffer.lineno);
+ $$.user_data = NULL;
+ }
+ | FLATTENABLE error ';' {
+ fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
+ g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+ $$.user_data = NULL;
+ }
+
;
interface_header:
INTERFACE {
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_BINDER;
+ c->document_item.next = NULL;
c->interface_token = $1.buffer;
c->oneway = false;
memset(&c->oneway_token, 0, sizeof(buffer_type));
@@ -110,19 +137,34 @@
}
| ONEWAY INTERFACE {
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_BINDER;
+ c->document_item.next = NULL;
c->interface_token = $2.buffer;
c->oneway = true;
c->oneway_token = $1.buffer;
c->comments_token = &c->oneway_token;
$$.interface_obj = c;
}
+ | RPC {
+ interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_RPC;
+ c->document_item.next = NULL;
+ c->interface_token = $1.buffer;
+ c->oneway = false;
+ memset(&c->oneway_token, 0, sizeof(buffer_type));
+ c->comments_token = &c->interface_token;
+ $$.interface_obj = c;
+ }
+ ;
+
+interface_keywords:
+ INTERFACE
+ | RPC
;
interface_decl:
interface_header IDENTIFIER '{' interface_items '}' {
interface_type* c = $1.interface_obj;
- c->document_item.item_type = INTERFACE_TYPE;
- c->document_item.next = NULL;
c->name = $2.buffer;
c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
c->open_brace_token = $3.buffer;
@@ -130,12 +172,12 @@
c->close_brace_token = $5.buffer;
$$.interface_obj = c;
}
- | INTERFACE error '{' interface_items '}' {
+ | interface_keywords error '{' interface_items '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
$$.document_item = NULL;
}
- | INTERFACE error '}' {
+ | interface_keywords error '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
$$.document_item = NULL;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 83e3bbc..9e57407 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,5 +1,4 @@
#include "generate_java.h"
-#include "AST.h"
#include "Type.h"
#include <string.h>
#include <stdio.h>
@@ -7,18 +6,6 @@
#include <string.h>
// =================================================
-class VariableFactory
-{
-public:
- VariableFactory(const string& base); // base must be short
- Variable* Get(Type* type);
- Variable* Get(int index);
-private:
- vector<Variable*> m_vars;
- string m_base;
- int m_index;
-};
-
VariableFactory::VariableFactory(const string& base)
:m_base(base),
m_index(0)
@@ -43,195 +30,7 @@
}
// =================================================
-class StubClass : public Class
-{
-public:
- StubClass(Type* type, Type* interfaceType);
- virtual ~StubClass();
-
- Variable* transact_code;
- Variable* transact_data;
- Variable* transact_reply;
- Variable* transact_flags;
- SwitchStatement* transact_switch;
-private:
- void make_as_interface(Type* interfaceType);
-};
-
-StubClass::StubClass(Type* type, Type* interfaceType)
- :Class()
-{
- this->comment = "/** Local-side IPC implementation stub class. */";
- this->modifiers = PUBLIC | ABSTRACT | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->extends = BINDER_NATIVE_TYPE;
- this->interfaces.push_back(interfaceType);
-
- // descriptor
- Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
- new Variable(STRING_TYPE, "DESCRIPTOR"));
- descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
- this->elements.push_back(descriptor);
-
- // ctor
- Method* ctor = new Method;
- ctor->modifiers = PUBLIC;
- ctor->comment = "/** Construct the stub at attach it to the "
- "interface. */";
- ctor->name = "Stub";
- ctor->statements = new StatementBlock;
- MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
- 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
- ctor->statements->Add(attach);
- this->elements.push_back(ctor);
-
- // asInterface
- make_as_interface(interfaceType);
-
- // asBinder
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
- this->elements.push_back(asBinder);
-
- // onTransact
- this->transact_code = new Variable(INT_TYPE, "code");
- this->transact_data = new Variable(PARCEL_TYPE, "data");
- this->transact_reply = new Variable(PARCEL_TYPE, "reply");
- this->transact_flags = new Variable(INT_TYPE, "flags");
- Method* onTransact = new Method;
- onTransact->modifiers = PUBLIC | OVERRIDE;
- onTransact->returnType = BOOLEAN_TYPE;
- onTransact->name = "onTransact";
- onTransact->parameters.push_back(this->transact_code);
- onTransact->parameters.push_back(this->transact_data);
- onTransact->parameters.push_back(this->transact_reply);
- onTransact->parameters.push_back(this->transact_flags);
- onTransact->statements = new StatementBlock;
- onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- this->elements.push_back(onTransact);
- this->transact_switch = new SwitchStatement(this->transact_code);
-
- onTransact->statements->Add(this->transact_switch);
- MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
- this->transact_code, this->transact_data,
- this->transact_reply, this->transact_flags);
- onTransact->statements->Add(new ReturnStatement(superCall));
-}
-
-StubClass::~StubClass()
-{
-}
-
-void
-StubClass::make_as_interface(Type *interfaceType)
-{
- Variable* obj = new Variable(IBINDER_TYPE, "obj");
-
- Method* m = new Method;
- m->comment = "/**\n * Cast an IBinder object into an ";
- m->comment += interfaceType->QualifiedName();
- m->comment += " interface,\n";
- m->comment += " * generating a proxy if needed.\n */";
- m->modifiers = PUBLIC | STATIC;
- m->returnType = interfaceType;
- m->name = "asInterface";
- m->parameters.push_back(obj);
- m->statements = new StatementBlock;
-
- IfStatement* ifstatement = new IfStatement();
- ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
- ifstatement->statements = new StatementBlock;
- ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
- m->statements->Add(ifstatement);
-
- // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
- MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
- queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
- IInterfaceType* iinType = new IInterfaceType();
- Variable *iin = new Variable(iinType, "iin");
- VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
- m->statements->Add(iinVd);
-
- // Ensure the instance type of the local object is as expected.
- // One scenario where this is needed is if another package (with a
- // different class loader) runs in the same process as the service.
-
- // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
- Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
- Comparison* instOfCheck = new Comparison(iin, " instanceof ",
- new LiteralExpression(interfaceType->QualifiedName()));
- IfStatement* instOfStatement = new IfStatement();
- instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
- instOfStatement->statements = new StatementBlock;
- instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
- m->statements->Add(instOfStatement);
-
- string proxyType = interfaceType->QualifiedName();
- proxyType += ".Stub.Proxy";
- NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
- ne->arguments.push_back(obj);
- m->statements->Add(new ReturnStatement(ne));
-
- this->elements.push_back(m);
-}
-
-
-
-// =================================================
-class ProxyClass : public Class
-{
-public:
- ProxyClass(Type* type, InterfaceType* interfaceType);
- virtual ~ProxyClass();
-
- Variable* mRemote;
- bool mOneWay;
-};
-
-ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
- :Class()
-{
- this->modifiers = PRIVATE | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->interfaces.push_back(interfaceType);
-
- mOneWay = interfaceType->OneWay();
-
- // IBinder mRemote
- mRemote = new Variable(IBINDER_TYPE, "mRemote");
- this->elements.push_back(new Field(PRIVATE, mRemote));
-
- // Proxy()
- Variable* remote = new Variable(IBINDER_TYPE, "remote");
- Method* ctor = new Method;
- ctor->name = "Proxy";
- ctor->statements = new StatementBlock;
- ctor->parameters.push_back(remote);
- ctor->statements->Add(new Assignment(mRemote, remote));
- this->elements.push_back(ctor);
-
- // IBinder asBinder()
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(mRemote));
- this->elements.push_back(asBinder);
-}
-
-ProxyClass::~ProxyClass()
-{
-}
-
-// =================================================
-static string
+string
gather_comments(extra_text_type* extra)
{
string s;
@@ -249,7 +48,7 @@
return s;
}
-static string
+string
append(const char* a, const char* b)
{
string s = a;
@@ -257,379 +56,25 @@
return s;
}
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
-{
- Variable* len = new Variable(INT_TYPE, v->name + "_length");
- addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
- IfStatement* lencheck = new IfStatement();
- lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
- lencheck->statements->Add(new Assignment(v, NULL_VALUE));
- lencheck->elseif = new IfStatement();
- lencheck->elseif->statements->Add(new Assignment(v,
- new NewArrayExpression(t, len)));
- addTo->Add(lencheck);
-}
-
-static void
-generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags)
-{
- if (v->dimension == 0) {
- t->WriteToParcel(addTo, v, parcel, flags);
- }
- if (v->dimension == 1) {
- t->WriteArrayToParcel(addTo, v, parcel, flags);
- }
-}
-
-static void
-generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->CreateFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->CreateArrayFromParcel(addTo, v, parcel, cl);
- }
-}
-
-static void
-generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->ReadFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->ReadArrayFromParcel(addTo, v, parcel, cl);
- }
-}
-
-
-static void
-generate_method(const method_type* method, Class* interface,
- StubClass* stubClass, ProxyClass* proxyClass, int index)
-{
- arg_type* arg;
- int i;
- bool hasOutParams = false;
-
- const bool oneway = proxyClass->mOneWay || method->oneway;
-
- // == the TRANSACT_ constant =============================================
- string transactCodeName = "TRANSACTION_";
- transactCodeName += method->name.data;
-
- char transactCodeValue[50];
- sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
-
- Field* transactCode = new Field(STATIC | FINAL,
- new Variable(INT_TYPE, transactCodeName));
- transactCode->value = transactCodeValue;
- stubClass->elements.push_back(transactCode);
-
- // == the declaration in the interface ===================================
- Method* decl = new Method;
- decl->comment = gather_comments(method->comments_token->extra);
- decl->modifiers = PUBLIC;
- decl->returnType = NAMES.Search(method->type.type.data);
- decl->returnTypeDimension = method->type.dimension;
- decl->name = method->name.data;
-
- arg = method->args;
- while (arg != NULL) {
- decl->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
-
- decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-
- interface->elements.push_back(decl);
-
- // == the stub method ====================================================
-
- Case* c = new Case(transactCodeName);
-
- MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-
- // interface token validation is the very first thing we do
- c->statements->Add(new MethodCall(stubClass->transact_data,
- "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
-
- // args
- Variable* cl = NULL;
- VariableFactory stubArgs("_arg");
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(t);
- v->dimension = arg->type.dimension;
-
- c->statements->Add(new VariableDeclaration(v));
-
- if (convert_direction(arg->direction.data) & IN_PARAMETER) {
- generate_create_from_parcel(t, c->statements, v,
- stubClass->transact_data, &cl);
- } else {
- if (arg->type.dimension == 0) {
- c->statements->Add(new Assignment(
- v, new NewExpression(v->type)));
- }
- else if (arg->type.dimension == 1) {
- generate_new_array(v->type, c->statements, v,
- stubClass->transact_data);
- }
- else {
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
- __LINE__);
- }
- }
-
- realCall->arguments.push_back(v);
-
- arg = arg->next;
- }
-
- // the real call
- Variable* _result = NULL;
- if (0 == strcmp(method->type.type.data, "void")) {
- c->statements->Add(realCall);
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
- } else {
- _result = new Variable(decl->returnType, "_result",
- decl->returnTypeDimension);
- c->statements->Add(new VariableDeclaration(_result, realCall));
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
-
- // marshall the return value
- generate_write_to_parcel(decl->returnType, c->statements, _result,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- }
-
- // out parameters
- i = 0;
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(i++);
-
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_write_to_parcel(t, c->statements, v,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- hasOutParams = true;
- }
-
- arg = arg->next;
- }
-
- // return true
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stubClass->transact_switch->cases.push_back(c);
-
- // == the proxy method ===================================================
- Method* proxy = new Method;
- proxy->comment = gather_comments(method->comments_token->extra);
- proxy->modifiers = PUBLIC;
- proxy->returnType = NAMES.Search(method->type.type.data);
- proxy->returnTypeDimension = method->type.dimension;
- proxy->name = method->name.data;
- proxy->statements = new StatementBlock;
- arg = method->args;
- while (arg != NULL) {
- proxy->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
- proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- proxyClass->elements.push_back(proxy);
-
- // the parcels
- Variable* _data = new Variable(PARCEL_TYPE, "_data");
- proxy->statements->Add(new VariableDeclaration(_data,
- new MethodCall(PARCEL_TYPE, "obtain")));
- Variable* _reply = NULL;
- if (!oneway) {
- _reply = new Variable(PARCEL_TYPE, "_reply");
- proxy->statements->Add(new VariableDeclaration(_reply,
- new MethodCall(PARCEL_TYPE, "obtain")));
- }
-
- // the return value
- _result = NULL;
- if (0 != strcmp(method->type.type.data, "void")) {
- _result = new Variable(proxy->returnType, "_result",
- method->type.dimension);
- proxy->statements->Add(new VariableDeclaration(_result));
- }
-
- // try and finally
- TryStatement* tryStatement = new TryStatement();
- proxy->statements->Add(tryStatement);
- FinallyStatement* finallyStatement = new FinallyStatement();
- proxy->statements->Add(finallyStatement);
-
- // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
- tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
- 1, new LiteralExpression("DESCRIPTOR")));
-
- // the parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- int dir = convert_direction(arg->direction.data);
- if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
- IfStatement* checklen = new IfStatement();
- checklen->expression = new Comparison(v, "==", NULL_VALUE);
- checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
- new LiteralExpression("-1")));
- checklen->elseif = new IfStatement();
- checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
- 1, new FieldVariable(v, "length")));
- tryStatement->statements->Add(checklen);
- }
- else if (dir & IN_PARAMETER) {
- generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
- }
- arg = arg->next;
- }
-
- // the transact call
- MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
- new LiteralExpression("Stub." + transactCodeName),
- _data, _reply ? _reply : NULL_VALUE,
- new LiteralExpression(
- oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
- tryStatement->statements->Add(call);
-
- // throw back exceptions.
- if (_reply) {
- MethodCall* ex = new MethodCall(_reply, "readException", 0);
- tryStatement->statements->Add(ex);
- }
-
- // returning and cleanup
- if (_reply != NULL) {
- if (_result != NULL) {
- generate_create_from_parcel(proxy->returnType,
- tryStatement->statements, _result, _reply, &cl);
- }
-
- // the out/inout parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_read_from_parcel(t, tryStatement->statements,
- v, _reply, &cl);
- }
- arg = arg->next;
- }
-
- finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
- }
- finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
-
- if (_result != NULL) {
- proxy->statements->Add(new ReturnStatement(_result));
- }
-}
-
-static void
-generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
-{
- // the interface descriptor transaction handler
- Case* c = new Case("INTERFACE_TRANSACTION");
- c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
- 1, new LiteralExpression("DESCRIPTOR")));
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stub->transact_switch->cases.push_back(c);
-
- // and the proxy-side method returning the descriptor directly
- Method* getDesc = new Method;
- getDesc->modifiers = PUBLIC;
- getDesc->returnType = STRING_TYPE;
- getDesc->returnTypeDimension = 0;
- getDesc->name = "getInterfaceDescriptor";
- getDesc->statements = new StatementBlock;
- getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
- proxy->elements.push_back(getDesc);
-}
-
-static Class*
-generate_interface_class(const interface_type* iface)
-{
- InterfaceType* interfaceType = static_cast<InterfaceType*>(
- NAMES.Find(iface->package, iface->name.data));
-
- // the interface class
- Class* interface = new Class;
- interface->comment = gather_comments(iface->comments_token->extra);
- interface->modifiers = PUBLIC;
- interface->what = Class::INTERFACE;
- interface->type = interfaceType;
- interface->interfaces.push_back(IINTERFACE_TYPE);
-
- // the stub inner class
- StubClass* stub = new StubClass(
- NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
- interfaceType);
- interface->elements.push_back(stub);
-
- // the proxy inner class
- ProxyClass* proxy = new ProxyClass(
- NAMES.Find(iface->package,
- append(iface->name.data, ".Stub.Proxy").c_str()),
- interfaceType);
- stub->elements.push_back(proxy);
-
- // stub and proxy support for getInterfaceDescriptor()
- generate_interface_descriptors(stub, proxy);
-
- // all the declared methods of the interface
- int index = 0;
- interface_item_type* item = iface->interface_items;
- while (item != NULL) {
- if (item->item_type == METHOD_TYPE) {
- generate_method((method_type*)item, interface, stub, proxy, index);
- }
- item = item->next;
- index++;
- }
-
- return interface;
-}
-
+// =================================================
int
generate_java(const string& filename, const string& originalSrc,
interface_type* iface)
{
+ Class* cl;
+
+ if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
+ cl = generate_binder_interface_class(iface);
+ }
+ else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
+ cl = generate_rpc_interface_class(iface);
+ }
+
Document* document = new Document;
document->comment = "";
if (iface->package) document->package = iface->package;
document->originalSrc = originalSrc;
- document->classes.push_back(generate_interface_class(iface));
+ document->classes.push_back(cl);
// printf("outputting... filename=%s\n", filename.c_str());
FILE* to;
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 203fe23..4bfcfeb 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -2,6 +2,7 @@
#define GENERATE_JAVA_H
#include "aidl_language.h"
+#include "AST.h"
#include <string>
@@ -10,5 +11,23 @@
int generate_java(const string& filename, const string& originalSrc,
interface_type* iface);
+Class* generate_binder_interface_class(const interface_type* iface);
+Class* generate_rpc_interface_class(const interface_type* iface);
+
+string gather_comments(extra_text_type* extra);
+string append(const char* a, const char* b);
+
+class VariableFactory
+{
+public:
+ VariableFactory(const string& base); // base must be short
+ Variable* Get(Type* type);
+ Variable* Get(int index);
+private:
+ vector<Variable*> m_vars;
+ string m_base;
+ int m_index;
+};
+
#endif // GENERATE_JAVA_H
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
new file mode 100644
index 0000000..2e459a8
--- /dev/null
+++ b/tools/aidl/generate_java_binder.cpp
@@ -0,0 +1,559 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+class StubClass : public Class
+{
+public:
+ StubClass(Type* type, Type* interfaceType);
+ virtual ~StubClass();
+
+ Variable* transact_code;
+ Variable* transact_data;
+ Variable* transact_reply;
+ Variable* transact_flags;
+ SwitchStatement* transact_switch;
+private:
+ void make_as_interface(Type* interfaceType);
+};
+
+StubClass::StubClass(Type* type, Type* interfaceType)
+ :Class()
+{
+ this->comment = "/** Local-side IPC implementation stub class. */";
+ this->modifiers = PUBLIC | ABSTRACT | STATIC;
+ this->what = Class::CLASS;
+ this->type = type;
+ this->extends = BINDER_NATIVE_TYPE;
+ this->interfaces.push_back(interfaceType);
+
+ // descriptor
+ Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
+ new Variable(STRING_TYPE, "DESCRIPTOR"));
+ descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
+ this->elements.push_back(descriptor);
+
+ // ctor
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->comment = "/** Construct the stub at attach it to the "
+ "interface. */";
+ ctor->name = "Stub";
+ ctor->statements = new StatementBlock;
+ MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
+ 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
+ ctor->statements->Add(attach);
+ this->elements.push_back(ctor);
+
+ // asInterface
+ make_as_interface(interfaceType);
+
+ // asBinder
+ Method* asBinder = new Method;
+ asBinder->modifiers = PUBLIC;
+ asBinder->returnType = IBINDER_TYPE;
+ asBinder->name = "asBinder";
+ asBinder->statements = new StatementBlock;
+ asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
+ this->elements.push_back(asBinder);
+
+ // onTransact
+ this->transact_code = new Variable(INT_TYPE, "code");
+ this->transact_data = new Variable(PARCEL_TYPE, "data");
+ this->transact_reply = new Variable(PARCEL_TYPE, "reply");
+ this->transact_flags = new Variable(INT_TYPE, "flags");
+ Method* onTransact = new Method;
+ onTransact->modifiers = PUBLIC | OVERRIDE;
+ onTransact->returnType = BOOLEAN_TYPE;
+ onTransact->name = "onTransact";
+ onTransact->parameters.push_back(this->transact_code);
+ onTransact->parameters.push_back(this->transact_data);
+ onTransact->parameters.push_back(this->transact_reply);
+ onTransact->parameters.push_back(this->transact_flags);
+ onTransact->statements = new StatementBlock;
+ onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+ this->elements.push_back(onTransact);
+ this->transact_switch = new SwitchStatement(this->transact_code);
+
+ onTransact->statements->Add(this->transact_switch);
+ MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
+ this->transact_code, this->transact_data,
+ this->transact_reply, this->transact_flags);
+ onTransact->statements->Add(new ReturnStatement(superCall));
+}
+
+StubClass::~StubClass()
+{
+}
+
+void
+StubClass::make_as_interface(Type *interfaceType)
+{
+ Variable* obj = new Variable(IBINDER_TYPE, "obj");
+
+ Method* m = new Method;
+ m->comment = "/**\n * Cast an IBinder object into an ";
+ m->comment += interfaceType->QualifiedName();
+ m->comment += " interface,\n";
+ m->comment += " * generating a proxy if needed.\n */";
+ m->modifiers = PUBLIC | STATIC;
+ m->returnType = interfaceType;
+ m->name = "asInterface";
+ m->parameters.push_back(obj);
+ m->statements = new StatementBlock;
+
+ IfStatement* ifstatement = new IfStatement();
+ ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
+ ifstatement->statements = new StatementBlock;
+ ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
+ m->statements->Add(ifstatement);
+
+ // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
+ MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
+ queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
+ IInterfaceType* iinType = new IInterfaceType();
+ Variable *iin = new Variable(iinType, "iin");
+ VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
+ m->statements->Add(iinVd);
+
+ // Ensure the instance type of the local object is as expected.
+ // One scenario where this is needed is if another package (with a
+ // different class loader) runs in the same process as the service.
+
+ // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
+ Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
+ Comparison* instOfCheck = new Comparison(iin, " instanceof ",
+ new LiteralExpression(interfaceType->QualifiedName()));
+ IfStatement* instOfStatement = new IfStatement();
+ instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
+ instOfStatement->statements = new StatementBlock;
+ instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
+ m->statements->Add(instOfStatement);
+
+ string proxyType = interfaceType->QualifiedName();
+ proxyType += ".Stub.Proxy";
+ NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
+ ne->arguments.push_back(obj);
+ m->statements->Add(new ReturnStatement(ne));
+
+ this->elements.push_back(m);
+}
+
+
+
+// =================================================
+class ProxyClass : public Class
+{
+public:
+ ProxyClass(Type* type, InterfaceType* interfaceType);
+ virtual ~ProxyClass();
+
+ Variable* mRemote;
+ bool mOneWay;
+};
+
+ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
+ :Class()
+{
+ this->modifiers = PRIVATE | STATIC;
+ this->what = Class::CLASS;
+ this->type = type;
+ this->interfaces.push_back(interfaceType);
+
+ mOneWay = interfaceType->OneWay();
+
+ // IBinder mRemote
+ mRemote = new Variable(IBINDER_TYPE, "mRemote");
+ this->elements.push_back(new Field(PRIVATE, mRemote));
+
+ // Proxy()
+ Variable* remote = new Variable(IBINDER_TYPE, "remote");
+ Method* ctor = new Method;
+ ctor->name = "Proxy";
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(remote);
+ ctor->statements->Add(new Assignment(mRemote, remote));
+ this->elements.push_back(ctor);
+
+ // IBinder asBinder()
+ Method* asBinder = new Method;
+ asBinder->modifiers = PUBLIC;
+ asBinder->returnType = IBINDER_TYPE;
+ asBinder->name = "asBinder";
+ asBinder->statements = new StatementBlock;
+ asBinder->statements->Add(new ReturnStatement(mRemote));
+ this->elements.push_back(asBinder);
+}
+
+ProxyClass::~ProxyClass()
+{
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel)
+{
+ Variable* len = new Variable(INT_TYPE, v->name + "_length");
+ addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
+ IfStatement* lencheck = new IfStatement();
+ lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
+ lencheck->statements->Add(new Assignment(v, NULL_VALUE));
+ lencheck->elseif = new IfStatement();
+ lencheck->elseif->statements->Add(new Assignment(v,
+ new NewArrayExpression(t, len)));
+ addTo->Add(lencheck);
+}
+
+static void
+generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, int flags)
+{
+ if (v->dimension == 0) {
+ t->WriteToParcel(addTo, v, parcel, flags);
+ }
+ if (v->dimension == 1) {
+ t->WriteArrayToParcel(addTo, v, parcel, flags);
+ }
+}
+
+static void
+generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, Variable** cl)
+{
+ if (v->dimension == 0) {
+ t->CreateFromParcel(addTo, v, parcel, cl);
+ }
+ if (v->dimension == 1) {
+ t->CreateArrayFromParcel(addTo, v, parcel, cl);
+ }
+}
+
+static void
+generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, Variable** cl)
+{
+ if (v->dimension == 0) {
+ t->ReadFromParcel(addTo, v, parcel, cl);
+ }
+ if (v->dimension == 1) {
+ t->ReadArrayFromParcel(addTo, v, parcel, cl);
+ }
+}
+
+
+static void
+generate_method(const method_type* method, Class* interface,
+ StubClass* stubClass, ProxyClass* proxyClass, int index)
+{
+ arg_type* arg;
+ int i;
+ bool hasOutParams = false;
+
+ const bool oneway = proxyClass->mOneWay || method->oneway;
+
+ // == the TRANSACT_ constant =============================================
+ string transactCodeName = "TRANSACTION_";
+ transactCodeName += method->name.data;
+
+ char transactCodeValue[50];
+ sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+
+ Field* transactCode = new Field(STATIC | FINAL,
+ new Variable(INT_TYPE, transactCodeName));
+ transactCode->value = transactCodeValue;
+ stubClass->elements.push_back(transactCode);
+
+ // == the declaration in the interface ===================================
+ Method* decl = new Method;
+ decl->comment = gather_comments(method->comments_token->extra);
+ decl->modifiers = PUBLIC;
+ decl->returnType = NAMES.Search(method->type.type.data);
+ decl->returnTypeDimension = method->type.dimension;
+ decl->name = method->name.data;
+
+ arg = method->args;
+ while (arg != NULL) {
+ decl->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+
+ interface->elements.push_back(decl);
+
+ // == the stub method ====================================================
+
+ Case* c = new Case(transactCodeName);
+
+ MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
+
+ // interface token validation is the very first thing we do
+ c->statements->Add(new MethodCall(stubClass->transact_data,
+ "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
+
+ // args
+ Variable* cl = NULL;
+ VariableFactory stubArgs("_arg");
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ v->dimension = arg->type.dimension;
+
+ c->statements->Add(new VariableDeclaration(v));
+
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ generate_create_from_parcel(t, c->statements, v,
+ stubClass->transact_data, &cl);
+ } else {
+ if (arg->type.dimension == 0) {
+ c->statements->Add(new Assignment(v, new NewExpression(v->type)));
+ }
+ else if (arg->type.dimension == 1) {
+ generate_new_array(v->type, c->statements, v,
+ stubClass->transact_data);
+ }
+ else {
+ fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+ __LINE__);
+ }
+ }
+
+ realCall->arguments.push_back(v);
+
+ arg = arg->next;
+ }
+
+ // the real call
+ Variable* _result = NULL;
+ if (0 == strcmp(method->type.type.data, "void")) {
+ c->statements->Add(realCall);
+
+ if (!oneway) {
+ // report that there were no exceptions
+ MethodCall* ex = new MethodCall(stubClass->transact_reply,
+ "writeNoException", 0);
+ c->statements->Add(ex);
+ }
+ } else {
+ _result = new Variable(decl->returnType, "_result",
+ decl->returnTypeDimension);
+ c->statements->Add(new VariableDeclaration(_result, realCall));
+
+ if (!oneway) {
+ // report that there were no exceptions
+ MethodCall* ex = new MethodCall(stubClass->transact_reply,
+ "writeNoException", 0);
+ c->statements->Add(ex);
+ }
+
+ // marshall the return value
+ generate_write_to_parcel(decl->returnType, c->statements, _result,
+ stubClass->transact_reply,
+ Type::PARCELABLE_WRITE_RETURN_VALUE);
+ }
+
+ // out parameters
+ i = 0;
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(i++);
+
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ generate_write_to_parcel(t, c->statements, v,
+ stubClass->transact_reply,
+ Type::PARCELABLE_WRITE_RETURN_VALUE);
+ hasOutParams = true;
+ }
+
+ arg = arg->next;
+ }
+
+ // return true
+ c->statements->Add(new ReturnStatement(TRUE_VALUE));
+ stubClass->transact_switch->cases.push_back(c);
+
+ // == the proxy method ===================================================
+ Method* proxy = new Method;
+ proxy->comment = gather_comments(method->comments_token->extra);
+ proxy->modifiers = PUBLIC;
+ proxy->returnType = NAMES.Search(method->type.type.data);
+ proxy->returnTypeDimension = method->type.dimension;
+ proxy->name = method->name.data;
+ proxy->statements = new StatementBlock;
+ arg = method->args;
+ while (arg != NULL) {
+ proxy->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+ proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+ proxyClass->elements.push_back(proxy);
+
+ // the parcels
+ Variable* _data = new Variable(PARCEL_TYPE, "_data");
+ proxy->statements->Add(new VariableDeclaration(_data,
+ new MethodCall(PARCEL_TYPE, "obtain")));
+ Variable* _reply = NULL;
+ if (!oneway) {
+ _reply = new Variable(PARCEL_TYPE, "_reply");
+ proxy->statements->Add(new VariableDeclaration(_reply,
+ new MethodCall(PARCEL_TYPE, "obtain")));
+ }
+
+ // the return value
+ _result = NULL;
+ if (0 != strcmp(method->type.type.data, "void")) {
+ _result = new Variable(proxy->returnType, "_result",
+ method->type.dimension);
+ proxy->statements->Add(new VariableDeclaration(_result));
+ }
+
+ // try and finally
+ TryStatement* tryStatement = new TryStatement();
+ proxy->statements->Add(tryStatement);
+ FinallyStatement* finallyStatement = new FinallyStatement();
+ proxy->statements->Add(finallyStatement);
+
+ // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
+ tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
+ 1, new LiteralExpression("DESCRIPTOR")));
+
+ // the parameters
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ int dir = convert_direction(arg->direction.data);
+ if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
+ IfStatement* checklen = new IfStatement();
+ checklen->expression = new Comparison(v, "==", NULL_VALUE);
+ checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
+ new LiteralExpression("-1")));
+ checklen->elseif = new IfStatement();
+ checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
+ 1, new FieldVariable(v, "length")));
+ tryStatement->statements->Add(checklen);
+ }
+ else if (dir & IN_PARAMETER) {
+ generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
+ }
+ arg = arg->next;
+ }
+
+ // the transact call
+ MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
+ new LiteralExpression("Stub." + transactCodeName),
+ _data, _reply ? _reply : NULL_VALUE,
+ new LiteralExpression(
+ oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
+ tryStatement->statements->Add(call);
+
+ // throw back exceptions.
+ if (_reply) {
+ MethodCall* ex = new MethodCall(_reply, "readException", 0);
+ tryStatement->statements->Add(ex);
+ }
+
+ // returning and cleanup
+ if (_reply != NULL) {
+ if (_result != NULL) {
+ generate_create_from_parcel(proxy->returnType,
+ tryStatement->statements, _result, _reply, &cl);
+ }
+
+ // the out/inout parameters
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ generate_read_from_parcel(t, tryStatement->statements,
+ v, _reply, &cl);
+ }
+ arg = arg->next;
+ }
+
+ finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
+ }
+ finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
+
+ if (_result != NULL) {
+ proxy->statements->Add(new ReturnStatement(_result));
+ }
+}
+
+static void
+generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
+{
+ // the interface descriptor transaction handler
+ Case* c = new Case("INTERFACE_TRANSACTION");
+ c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
+ 1, new LiteralExpression("DESCRIPTOR")));
+ c->statements->Add(new ReturnStatement(TRUE_VALUE));
+ stub->transact_switch->cases.push_back(c);
+
+ // and the proxy-side method returning the descriptor directly
+ Method* getDesc = new Method;
+ getDesc->modifiers = PUBLIC;
+ getDesc->returnType = STRING_TYPE;
+ getDesc->returnTypeDimension = 0;
+ getDesc->name = "getInterfaceDescriptor";
+ getDesc->statements = new StatementBlock;
+ getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
+ proxy->elements.push_back(getDesc);
+}
+
+Class*
+generate_binder_interface_class(const interface_type* iface)
+{
+ InterfaceType* interfaceType = static_cast<InterfaceType*>(
+ NAMES.Find(iface->package, iface->name.data));
+
+ // the interface class
+ Class* interface = new Class;
+ interface->comment = gather_comments(iface->comments_token->extra);
+ interface->modifiers = PUBLIC;
+ interface->what = Class::INTERFACE;
+ interface->type = interfaceType;
+ interface->interfaces.push_back(IINTERFACE_TYPE);
+
+ // the stub inner class
+ StubClass* stub = new StubClass(
+ NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
+ interfaceType);
+ interface->elements.push_back(stub);
+
+ // the proxy inner class
+ ProxyClass* proxy = new ProxyClass(
+ NAMES.Find(iface->package,
+ append(iface->name.data, ".Stub.Proxy").c_str()),
+ interfaceType);
+ stub->elements.push_back(proxy);
+
+ // stub and proxy support for getInterfaceDescriptor()
+ generate_interface_descriptors(stub, proxy);
+
+ // all the declared methods of the interface
+ int index = 0;
+ interface_item_type* item = iface->interface_items;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ generate_method((method_type*)item, interface, stub, proxy, index);
+ }
+ item = item->next;
+ index++;
+ }
+
+ return interface;
+}
+
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
new file mode 100644
index 0000000..e5fa076
--- /dev/null
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -0,0 +1,998 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
+ "Context", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector",
+ "EventListener", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector",
+ "EventListener.Listener", Type::BUILT_IN, false, false, false);
+Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
+ Type::BUILT_IN, false, false, false);
+Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
+ Type::BUILT_IN, false, false, false);
+// TODO: Just use Endpoint, so this works for all endpoints.
+Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc",
+ "EndpointInfo", true, __FILE__, __LINE__);
+Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler",
+ true, __FILE__, __LINE__);
+Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true,
+ __FILE__, __LINE__);
+
+static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
+ Variable* v, Variable* data, Variable** cl);
+static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
+static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data);
+
+static string
+format_int(int n)
+{
+ char str[20];
+ sprintf(str, "%d", n);
+ return string(str);
+}
+
+static string
+class_name_leaf(const string& str)
+{
+ string::size_type pos = str.rfind('.');
+ if (pos == string::npos) {
+ return str;
+ } else {
+ return string(str, pos+1);
+ }
+}
+
+static string
+results_class_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "On");
+ return str;
+}
+
+static string
+results_method_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "on");
+ return str;
+}
+
+static string
+push_method_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "push");
+ return str;
+}
+
+// =================================================
+class DispatcherClass : public Class
+{
+public:
+ DispatcherClass(const interface_type* iface, Expression* target);
+ virtual ~DispatcherClass();
+
+ void AddMethod(const method_type* method);
+ void DoneWithMethods();
+
+ Method* processMethod;
+ Variable* actionParam;
+ Variable* requestParam;
+ Variable* rpcContextParam;
+ Variable* errorParam;
+ Variable* requestData;
+ Variable* resultData;
+ IfStatement* dispatchIfStatement;
+ Expression* targetExpression;
+
+private:
+ void generate_process();
+};
+
+DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
+ :Class(),
+ dispatchIfStatement(NULL),
+ targetExpression(target)
+{
+ generate_process();
+}
+
+DispatcherClass::~DispatcherClass()
+{
+}
+
+void
+DispatcherClass::generate_process()
+{
+ // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
+ this->processMethod = new Method;
+ this->processMethod->modifiers = PUBLIC;
+ this->processMethod->returnType = BYTE_TYPE;
+ this->processMethod->returnTypeDimension = 1;
+ this->processMethod->name = "process";
+ this->processMethod->statements = new StatementBlock;
+
+ this->actionParam = new Variable(STRING_TYPE, "action");
+ this->processMethod->parameters.push_back(this->actionParam);
+
+ this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
+ this->processMethod->parameters.push_back(this->requestParam);
+
+ this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
+ this->processMethod->parameters.push_back(this->rpcContextParam);
+
+ this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
+ this->processMethod->parameters.push_back(this->errorParam);
+
+ this->requestData = new Variable(RPC_DATA_TYPE, "request");
+ this->processMethod->statements->Add(new VariableDeclaration(requestData,
+ new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
+
+ this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
+ this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
+ NULL_VALUE));
+}
+
+void
+DispatcherClass::AddMethod(const method_type* method)
+{
+ arg_type* arg;
+
+ // The if/switch statement
+ IfStatement* ifs = new IfStatement();
+ ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
+ 1, this->actionParam);
+ StatementBlock* block = ifs->statements = new StatementBlock;
+ if (this->dispatchIfStatement == NULL) {
+ this->dispatchIfStatement = ifs;
+ this->processMethod->statements->Add(dispatchIfStatement);
+ } else {
+ this->dispatchIfStatement->elseif = ifs;
+ this->dispatchIfStatement = ifs;
+ }
+
+ // The call to decl (from above)
+ MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
+
+ // args
+ Variable* classLoader = NULL;
+ VariableFactory stubArgs("_arg");
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ v->dimension = arg->type.dimension;
+
+ // Unmarshall the parameter
+ block->Add(new VariableDeclaration(v));
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ generate_create_from_data(t, block, arg->name.data, v,
+ this->requestData, &classLoader);
+ } else {
+ if (arg->type.dimension == 0) {
+ block->Add(new Assignment(v, new NewExpression(v->type)));
+ }
+ else if (arg->type.dimension == 1) {
+ generate_new_array(v->type, block, v, this->requestData);
+ }
+ else {
+ fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+ __LINE__);
+ }
+ }
+
+ // Add that parameter to the method call
+ realCall->arguments.push_back(v);
+
+ arg = arg->next;
+ }
+
+ // Add a final parameter: RpcContext. Contains data about
+ // incoming request (e.g., certificate)
+ realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+ Type* returnType = NAMES.Search(method->type.type.data);
+ if (returnType == EVENT_FAKE_TYPE) {
+ returnType = VOID_TYPE;
+ }
+
+ // the real call
+ bool first = true;
+ Variable* _result = NULL;
+ if (returnType == VOID_TYPE) {
+ block->Add(realCall);
+ } else {
+ _result = new Variable(returnType, "_result",
+ method->type.dimension);
+ block->Add(new VariableDeclaration(_result, realCall));
+
+ // need the result RpcData
+ if (first) {
+ block->Add(new Assignment(this->resultData,
+ new NewExpression(RPC_DATA_TYPE)));
+ first = false;
+ }
+
+ // marshall the return value
+ generate_write_to_data(returnType, block,
+ new StringLiteralExpression("_result"), _result, this->resultData);
+ }
+
+ // out parameters
+ int i = 0;
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(i++);
+
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ // need the result RpcData
+ if (first) {
+ block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
+ first = false;
+ }
+
+ generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
+ v, this->resultData);
+ }
+
+ arg = arg->next;
+ }
+}
+
+void
+DispatcherClass::DoneWithMethods()
+{
+ if (this->dispatchIfStatement == NULL) {
+ return;
+ }
+
+ this->elements.push_back(this->processMethod);
+
+ IfStatement* fallthrough = new IfStatement();
+ fallthrough->statements = new StatementBlock;
+ fallthrough->statements->Add(new ReturnStatement(
+ new MethodCall(SUPER_VALUE, "process", 4,
+ this->actionParam, this->requestParam,
+ this->rpcContextParam,
+ this->errorParam)));
+ this->dispatchIfStatement->elseif = fallthrough;
+ IfStatement* s = new IfStatement;
+ s->statements = new StatementBlock;
+ this->processMethod->statements->Add(s);
+ s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
+ s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
+ s->elseif = new IfStatement;
+ s = s->elseif;
+ s->statements->Add(new ReturnStatement(NULL_VALUE));
+}
+
+// =================================================
+class RpcProxyClass : public Class
+{
+public:
+ RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
+ virtual ~RpcProxyClass();
+
+ Variable* endpoint;
+ Variable* broker;
+
+private:
+ void generate_ctor();
+ void generate_get_endpoint_info();
+};
+
+RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
+ :Class()
+{
+ this->comment = gather_comments(iface->comments_token->extra);
+ this->modifiers = PUBLIC;
+ this->what = Class::CLASS;
+ this->type = interfaceType;
+
+ // broker
+ this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
+ this->elements.push_back(new Field(PRIVATE, this->broker));
+ // endpoint
+ this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
+ this->elements.push_back(new Field(PRIVATE, this->endpoint));
+
+ // methods
+ generate_ctor();
+ generate_get_endpoint_info();
+}
+
+RpcProxyClass::~RpcProxyClass()
+{
+}
+
+void
+RpcProxyClass::generate_ctor()
+{
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(endpoint);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new Assignment(this->broker, broker));
+ ctor->statements->Add(new Assignment(this->endpoint, endpoint));
+}
+
+void
+RpcProxyClass::generate_get_endpoint_info()
+{
+ Method* get = new Method;
+ get->modifiers = PUBLIC;
+ get->returnType = RPC_ENDPOINT_INFO_TYPE;
+ get->name = "getEndpointInfo";
+ get->statements = new StatementBlock;
+ this->elements.push_back(get);
+
+ get->statements->Add(new ReturnStatement(this->endpoint));
+}
+
+// =================================================
+class EventListenerClass : public DispatcherClass
+{
+public:
+ EventListenerClass(const interface_type* iface, Type* listenerType);
+ virtual ~EventListenerClass();
+
+ Variable* _listener;
+
+private:
+ void generate_ctor();
+};
+
+Expression*
+generate_get_listener_expression(Type* cast)
+{
+ return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
+}
+
+EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
+ :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
+{
+ this->modifiers = PRIVATE;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".Presenter"),
+ Type::GENERATED, false, false, false);
+ this->extends = PRESENTER_BASE_TYPE;
+
+ this->_listener = new Variable(listenerType, "_listener");
+ this->elements.push_back(new Field(PRIVATE, this->_listener));
+
+ // methods
+ generate_ctor();
+}
+
+EventListenerClass::~EventListenerClass()
+{
+}
+
+void
+EventListenerClass::generate_ctor()
+{
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* listener = new Variable(this->_listener->type, "listener");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(listener);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new MethodCall("super", 2, broker, listener));
+ ctor->statements->Add(new Assignment(this->_listener, listener));
+}
+
+// =================================================
+class ListenerClass : public Class
+{
+public:
+ ListenerClass(const interface_type* iface);
+ virtual ~ListenerClass();
+
+ bool needed;
+
+private:
+ void generate_ctor();
+};
+
+ListenerClass::ListenerClass(const interface_type* iface)
+ :Class(),
+ needed(false)
+{
+ this->comment = "/** Extend this to listen to the events from this class. */";
+ this->modifiers = STATIC | PUBLIC ;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".Listener"),
+ Type::GENERATED, false, false, false);
+ this->extends = PRESENTER_LISTENER_BASE_TYPE;
+}
+
+ListenerClass::~ListenerClass()
+{
+}
+
+// =================================================
+class EndpointBaseClass : public DispatcherClass
+{
+public:
+ EndpointBaseClass(const interface_type* iface);
+ virtual ~EndpointBaseClass();
+
+ bool needed;
+
+private:
+ void generate_ctor();
+};
+
+EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
+ :DispatcherClass(iface, THIS_VALUE),
+ needed(false)
+{
+ this->comment = "/** Extend this to implement a link service. */";
+ this->modifiers = STATIC | PUBLIC | ABSTRACT;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".EndpointBase"),
+ Type::GENERATED, false, false, false);
+ this->extends = RPC_CONNECTOR_TYPE;
+
+ // methods
+ generate_ctor();
+}
+
+EndpointBaseClass::~EndpointBaseClass()
+{
+}
+
+void
+EndpointBaseClass::generate_ctor()
+{
+ Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(container);
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(place);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
+}
+
+// =================================================
+class ResultDispatcherClass : public Class
+{
+public:
+ ResultDispatcherClass();
+ virtual ~ResultDispatcherClass();
+
+ void AddMethod(int index, const string& name, Method** method, Variable** param);
+
+ bool needed;
+ Variable* methodId;
+ Variable* callback;
+ Method* onResultMethod;
+ Variable* resultParam;
+ SwitchStatement* methodSwitch;
+
+private:
+ void generate_ctor();
+ void generate_onResult();
+};
+
+ResultDispatcherClass::ResultDispatcherClass()
+ :Class(),
+ needed(false)
+{
+ this->modifiers = PRIVATE | FINAL;
+ this->what = Class::CLASS;
+ this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
+ this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
+
+ // methodId
+ this->methodId = new Variable(INT_TYPE, "methodId");
+ this->elements.push_back(new Field(PRIVATE, this->methodId));
+ this->callback = new Variable(OBJECT_TYPE, "callback");
+ this->elements.push_back(new Field(PRIVATE, this->callback));
+
+ // methods
+ generate_ctor();
+ generate_onResult();
+}
+
+ResultDispatcherClass::~ResultDispatcherClass()
+{
+}
+
+void
+ResultDispatcherClass::generate_ctor()
+{
+ Variable* methodIdParam = new Variable(INT_TYPE, "methId");
+ Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(methodIdParam);
+ ctor->parameters.push_back(callbackParam);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
+ ctor->statements->Add(new Assignment(this->callback, callbackParam));
+}
+
+void
+ResultDispatcherClass::generate_onResult()
+{
+ this->onResultMethod = new Method;
+ this->onResultMethod->modifiers = PUBLIC;
+ this->onResultMethod->returnType = VOID_TYPE;
+ this->onResultMethod->returnTypeDimension = 0;
+ this->onResultMethod->name = "onResult";
+ this->onResultMethod->statements = new StatementBlock;
+ this->elements.push_back(this->onResultMethod);
+
+ this->resultParam = new Variable(BYTE_TYPE, "result", 1);
+ this->onResultMethod->parameters.push_back(this->resultParam);
+
+ this->methodSwitch = new SwitchStatement(this->methodId);
+ this->onResultMethod->statements->Add(this->methodSwitch);
+}
+
+void
+ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
+{
+ Method* m = new Method;
+ m->modifiers = PUBLIC;
+ m->returnType = VOID_TYPE;
+ m->returnTypeDimension = 0;
+ m->name = name;
+ m->statements = new StatementBlock;
+ *param = new Variable(BYTE_TYPE, "result", 1);
+ m->parameters.push_back(*param);
+ this->elements.push_back(m);
+ *method = m;
+
+ Case* c = new Case(format_int(index));
+ c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
+ c->statements->Add(new Break());
+
+ this->methodSwitch->cases.push_back(c);
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
+{
+ fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
+ exit(1);
+}
+
+static void
+generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
+ Variable* data, Variable** cl)
+{
+ Expression* k = new StringLiteralExpression(key);
+ if (v->dimension == 0) {
+ t->CreateFromRpcData(addTo, k, v, data, cl);
+ }
+ if (v->dimension == 1) {
+ //t->ReadArrayFromRpcData(addTo, v, data, cl);
+ fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
+ __FILE__, __LINE__);
+ }
+}
+
+static void
+generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
+{
+ if (v->dimension == 0) {
+ t->WriteToRpcData(addTo, k, v, data, 0);
+ }
+ if (v->dimension == 1) {
+ //t->WriteArrayToParcel(addTo, v, data);
+ fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
+ __FILE__, __LINE__);
+ }
+}
+
+// =================================================
+static Type*
+generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
+{
+ arg_type* arg;
+
+ string resultsMethodName = results_method_name(method->name.data);
+ Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
+ Type::GENERATED, false, false, false);
+
+ if (!method->oneway) {
+ Class* resultsClass = new Class;
+ resultsClass->modifiers = STATIC | PUBLIC;
+ resultsClass->what = Class::INTERFACE;
+ resultsClass->type = resultsInterfaceType;
+
+ Method* resultMethod = new Method;
+ resultMethod->comment = gather_comments(method->comments_token->extra);
+ resultMethod->modifiers = PUBLIC;
+ resultMethod->returnType = VOID_TYPE;
+ resultMethod->returnTypeDimension = 0;
+ resultMethod->name = resultsMethodName;
+ if (0 != strcmp("void", method->type.type.data)) {
+ resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
+ "_result", method->type.dimension));
+ }
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ resultMethod->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ }
+ arg = arg->next;
+ }
+ resultsClass->elements.push_back(resultMethod);
+
+ if (resultMethod->parameters.size() > 0) {
+ proxyClass->elements.push_back(resultsClass);
+ return resultsInterfaceType;
+ }
+ }
+ //delete resultsInterfaceType;
+ return NULL;
+}
+
+static void
+generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
+ ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+ arg_type* arg;
+ Method* proxyMethod = new Method;
+ proxyMethod->comment = gather_comments(method->comments_token->extra);
+ proxyMethod->modifiers = PUBLIC;
+ proxyMethod->returnType = VOID_TYPE;
+ proxyMethod->returnTypeDimension = 0;
+ proxyMethod->name = method->name.data;
+ proxyMethod->statements = new StatementBlock;
+ proxyClass->elements.push_back(proxyMethod);
+
+ // The local variables
+ Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+ proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+ // Add the arguments
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ // Function signature
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ proxyMethod->parameters.push_back(v);
+
+ // Input parameter marshalling
+ generate_write_to_data(t, proxyMethod->statements,
+ new StringLiteralExpression(arg->name.data), v, _data);
+ }
+ arg = arg->next;
+ }
+
+ // If there is a results interface for this class
+ Expression* resultParameter;
+ if (resultsInterfaceType != NULL) {
+ // Result interface parameter
+ Variable* resultListener = new Variable(resultsInterfaceType, "_result");
+ proxyMethod->parameters.push_back(resultListener);
+
+ // Add the results dispatcher callback
+ resultsDispatcherClass->needed = true;
+ resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
+ new LiteralExpression(format_int(index)), resultListener);
+ } else {
+ resultParameter = NULL_VALUE;
+ }
+
+ // All proxy methods take an error parameter
+ Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
+ proxyMethod->parameters.push_back(errorListener);
+
+ // Call the broker
+ proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
+ "sendRpc", 5,
+ proxyClass->endpoint,
+ new StringLiteralExpression(method->name.data),
+ new MethodCall(_data, "serialize"),
+ resultParameter,
+ errorListener));
+}
+
+static void
+generate_result_dispatcher_method(const method_type* method,
+ ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+ arg_type* arg;
+ Method* dispatchMethod;
+ Variable* dispatchParam;
+ resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
+
+ Variable* classLoader = NULL;
+ Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
+ dispatchMethod->statements->Add(new VariableDeclaration(resultData,
+ new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
+
+ // The callback method itself
+ MethodCall* realCall = new MethodCall(
+ new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
+ results_method_name(method->name.data));
+
+ // The return value
+ {
+ Type* t = NAMES.Search(method->type.type.data);
+ if (t != VOID_TYPE) {
+ Variable* rv = new Variable(t, "rv");
+ dispatchMethod->statements->Add(new VariableDeclaration(rv));
+ generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
+ resultData, &classLoader);
+ realCall->arguments.push_back(rv);
+ }
+ }
+
+ VariableFactory stubArgs("arg");
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ // Unmarshall the results
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ dispatchMethod->statements->Add(new VariableDeclaration(v));
+
+ generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
+ resultData, &classLoader);
+
+ // Add the argument to the callback
+ realCall->arguments.push_back(v);
+ }
+ arg = arg->next;
+ }
+
+ // Call the callback method
+ dispatchMethod->statements->Add(realCall);
+}
+
+static void
+generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
+ EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
+ int index)
+{
+ arg_type* arg;
+
+ // == the callback interface for results ================================
+ // the service base class
+ Type* resultsInterfaceType = generate_results_method(method, proxyClass);
+
+ // == the method in the proxy class =====================================
+ generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
+
+ // == the method in the result dispatcher class =========================
+ if (resultsInterfaceType != NULL) {
+ generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
+ index);
+ }
+
+ // == The abstract method that the service developers implement ==========
+ Method* decl = new Method;
+ decl->comment = gather_comments(method->comments_token->extra);
+ decl->modifiers = PUBLIC | ABSTRACT;
+ decl->returnType = NAMES.Search(method->type.type.data);
+ decl->returnTypeDimension = method->type.dimension;
+ decl->name = method->name.data;
+ arg = method->args;
+ while (arg != NULL) {
+ decl->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ // Add the default RpcContext param to all methods
+ decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+ serviceBaseClass->elements.push_back(decl);
+
+
+ // == the dispatch method in the service base class ======================
+ serviceBaseClass->AddMethod(method);
+}
+
+static void
+generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
+ EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
+ EventListenerClass* presenterClass, int index)
+{
+ arg_type* arg;
+ listenerClass->needed = true;
+
+ // == the push method in the service base class =========================
+ Method* push = new Method;
+ push->modifiers = PUBLIC;
+ push->name = push_method_name(method->name.data);
+ push->statements = new StatementBlock;
+ push->returnType = VOID_TYPE;
+ serviceBaseClass->elements.push_back(push);
+
+ // The local variables
+ Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+ push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+ // Add the arguments
+ arg = method->args;
+ while (arg != NULL) {
+ // Function signature
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ push->parameters.push_back(v);
+
+ // Input parameter marshalling
+ generate_write_to_data(t, push->statements,
+ new StringLiteralExpression(arg->name.data), v, _data);
+
+ arg = arg->next;
+ }
+
+ // Send the notifications
+ push->statements->Add(new MethodCall("pushEvent", 2,
+ new StringLiteralExpression(method->name.data),
+ new MethodCall(_data, "serialize")));
+
+ // == the event callback dispatcher method ====================================
+ presenterClass->AddMethod(method);
+
+ // == the event method in the listener base class =====================
+ Method* event = new Method;
+ event->modifiers = PUBLIC;
+ event->name = method->name.data;
+ event->statements = new StatementBlock;
+ event->returnType = VOID_TYPE;
+ listenerClass->elements.push_back(event);
+ arg = method->args;
+ while (arg != NULL) {
+ event->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ // Add a final parameter: RpcContext. Contains data about
+ // incoming request (e.g., certificate)
+ event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+}
+
+static void
+generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
+{
+ // AndroidAtHomePresenter _presenter;
+ // void startListening(Listener listener) {
+ // stopListening();
+ // _presenter = new Presenter(_broker, listener);
+ // _presenter.startListening(_endpoint);
+ // }
+ // void stopListening() {
+ // if (_presenter != null) {
+ // _presenter.stopListening();
+ // }
+ // }
+
+ Variable* _presenter = new Variable(presenterType, "_presenter");
+ proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
+
+ Variable* listener = new Variable(listenerType, "listener");
+
+ Method* startListeningMethod = new Method;
+ startListeningMethod->modifiers = PUBLIC;
+ startListeningMethod->returnType = VOID_TYPE;
+ startListeningMethod->name = "startListening";
+ startListeningMethod->statements = new StatementBlock;
+ startListeningMethod->parameters.push_back(listener);
+ proxyClass->elements.push_back(startListeningMethod);
+
+ startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
+ startListeningMethod->statements->Add(new Assignment(_presenter,
+ new NewExpression(presenterType, 2, proxyClass->broker, listener)));
+ startListeningMethod->statements->Add(new MethodCall(_presenter,
+ "startListening", 1, proxyClass->endpoint));
+
+ Method* stopListeningMethod = new Method;
+ stopListeningMethod->modifiers = PUBLIC;
+ stopListeningMethod->returnType = VOID_TYPE;
+ stopListeningMethod->name = "stopListening";
+ stopListeningMethod->statements = new StatementBlock;
+ proxyClass->elements.push_back(stopListeningMethod);
+
+ IfStatement* ifst = new IfStatement;
+ ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
+ stopListeningMethod->statements->Add(ifst);
+
+ ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
+ ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
+}
+
+Class*
+generate_rpc_interface_class(const interface_type* iface)
+{
+ // the proxy class
+ InterfaceType* interfaceType = static_cast<InterfaceType*>(
+ NAMES.Find(iface->package, iface->name.data));
+ RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
+
+ // the listener class
+ ListenerClass* listener = new ListenerClass(iface);
+
+ // the presenter class
+ EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
+
+ // the service base class
+ EndpointBaseClass* base = new EndpointBaseClass(iface);
+ proxy->elements.push_back(base);
+
+ // the result dispatcher
+ ResultDispatcherClass* results = new ResultDispatcherClass();
+
+ // all the declared methods of the proxy
+ int index = 0;
+ interface_item_type* item = iface->interface_items;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
+ generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
+ } else {
+ generate_regular_method((method_type*)item, proxy, base, results, index);
+ }
+ }
+ item = item->next;
+ index++;
+ }
+ presenter->DoneWithMethods();
+ base->DoneWithMethods();
+
+ // only add this if there are methods with results / out parameters
+ if (results->needed) {
+ proxy->elements.push_back(results);
+ }
+ if (listener->needed) {
+ proxy->elements.push_back(listener);
+ proxy->elements.push_back(presenter);
+ generate_listener_methods(proxy, presenter->type, listener->type);
+ }
+
+ return proxy;
+}
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 96de51c..97d9969 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -29,7 +29,7 @@
public static void setAttachInfo(View view) {
AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
- new Handler(), null);
+ new ViewRootImpl(view.getContext()), new Handler(), null);
info.mHasWindowFocus = true;
info.mWindowVisibility = View.VISIBLE;
info.mInTouchMode = false; // this is so that we can display selections.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index db0694c..6afdfbe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -197,6 +197,12 @@
}
@Override
+ public boolean switchToNextInputMethod(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub
diff --git a/tools/makekeycodes/makekeycodes.cpp b/tools/makekeycodes/makekeycodes.cpp
index 16df774..6ffbfb8 100644
--- a/tools/makekeycodes/makekeycodes.cpp
+++ b/tools/makekeycodes/makekeycodes.cpp
@@ -1,5 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <stdio.h>
-#include <ui/KeycodeLabels.h>
+#include <androidfw/KeycodeLabels.h>
int
main(int argc, char** argv)
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
index 932dbec..b2152e8 100644
--- a/tools/obbtool/Main.cpp
+++ b/tools/obbtool/Main.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <utils/ObbFile.h>
+#include <androidfw/ObbFile.h>
#include <utils/String8.h>
#include <getopt.h>
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 8ab9b6a..3cc2467 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <ui/KeyCharacterMap.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/VirtualKeyMap.h>
#include <utils/PropertyMap.h>
#include <utils/String8.h>
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index bbb74d1..d05e0b8 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -366,17 +366,6 @@
handleDriverEvent(eventData);
} else if (event == TERMINATING) {
/**
- * If monitor socket is closed, we have already
- * stopped the supplicant, simply exit the monitor thread
- */
- if (eventData.startsWith(MONITOR_SOCKET_CLOSED_STR)) {
- if (false) {
- Log.d(TAG, "Monitor socket is closed, exiting thread");
- }
- break;
- }
-
- /**
* Close the supplicant connection if we see
* too many recv errors
*/
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 48a785c..e3dd3a6 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -39,6 +39,8 @@
*/
public class WifiNative {
+ private static final boolean DBG = false;
+ private final String mTAG;
private static final int DEFAULT_GROUP_OWNER_INTENT = 7;
static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0;
@@ -53,9 +55,7 @@
public native static boolean unloadDriver();
- public native static boolean startSupplicant();
-
- public native static boolean startP2pSupplicant();
+ public native static boolean startSupplicant(boolean p2pSupported);
/* Sends a kill signal to supplicant. To be used when we have lost connection
or when the supplicant is hung */
@@ -79,6 +79,7 @@
public WifiNative(String iface) {
mInterface = iface;
+ mTAG = "WifiNative-" + iface;
}
public boolean connectToSupplicant() {
@@ -94,14 +95,17 @@
}
private boolean doBooleanCommand(String command) {
+ if (DBG) Log.d(mTAG, "doBoolean: " + command);
return doBooleanCommand(mInterface, command);
}
private int doIntCommand(String command) {
+ if (DBG) Log.d(mTAG, "doInt: " + command);
return doIntCommand(mInterface, command);
}
private String doStringCommand(String command) {
+ if (DBG) Log.d(mTAG, "doString: " + command);
return doStringCommand(mInterface, command);
}
@@ -437,6 +441,10 @@
return doBooleanCommand("P2P_FIND " + timeout);
}
+ public boolean p2pStopFind() {
+ return doBooleanCommand("P2P_STOP_FIND");
+ }
+
public boolean p2pListen() {
return doBooleanCommand("P2P_LISTEN");
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index b8b7c0e..1b64f3e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -45,6 +45,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.DhcpInfoInternal;
@@ -118,6 +119,8 @@
private INetworkManagementService mNwService;
private ConnectivityManager mCm;
+ private final boolean mP2pSupported;
+
/* Scan results handling */
private List<ScanResult> mScanResults;
private static final Pattern scanResultPattern = Pattern.compile("\t+");
@@ -361,9 +364,9 @@
/* Reset the WPS state machine */
static final int CMD_RESET_WPS_STATE = BASE + 122;
- /* Interaction with WifiP2pService */
- public static final int WIFI_ENABLE_PENDING = BASE + 131;
- public static final int P2P_ENABLE_PROCEED = BASE + 132;
+ /* P2p commands */
+ public static final int CMD_ENABLE_P2P = BASE + 131;
+ public static final int CMD_DISABLE_P2P = BASE + 132;
private static final int CONNECT_MODE = 1;
private static final int SCAN_ONLY_MODE = 2;
@@ -482,9 +485,6 @@
/* Waiting for untether confirmation to stop soft Ap */
private State mSoftApStoppingState = new SoftApStoppingState();
- /* Wait till p2p is disabled */
- private State mWaitForP2pDisableState = new WaitForP2pDisableState();
-
private class TetherStateChange {
ArrayList<String> available;
ArrayList<String> active;
@@ -556,6 +556,9 @@
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNwService = INetworkManagementService.Stub.asInterface(b);
+ mP2pSupported = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_DIRECT);
+
mWifiNative = new WifiNative(mInterfaceName);
mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
mWifiMonitor = new WifiMonitor(this, mWifiNative);
@@ -639,7 +642,6 @@
addState(mTetheringState, mSoftApStartedState);
addState(mTetheredState, mSoftApStartedState);
addState(mSoftApStoppingState, mDefaultState);
- addState(mWaitForP2pDisableState, mDefaultState);
setInitialState(mInitialState);
@@ -1625,14 +1627,14 @@
private void handleNetworkDisconnect() {
if (DBG) log("Stopping DHCP and clearing IP");
- /* In case we were in middle of DHCP operation
- restore back powermode */
- handlePostDhcpSetup();
-
/*
* stop DHCP
*/
if (mDhcpStateMachine != null) {
+ /* In case we were in middle of DHCP operation
+ restore back powermode */
+ handlePostDhcpSetup();
+
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
mDhcpStateMachine.quit();
mDhcpStateMachine = null;
@@ -1752,7 +1754,9 @@
* If we've exceeded the maximum number of retries for DHCP
* to a given network, disable the network
*/
- if (++mReconnectCount > getMaxDhcpRetries()) {
+ int maxRetries = getMaxDhcpRetries();
+ // maxRetries == 0 means keep trying forever
+ if (maxRetries > 0 && ++mReconnectCount > maxRetries) {
loge("Failed " +
mReconnectCount + " times, Disabling " + mLastNetworkId);
mWifiConfigStore.disableNetwork(mLastNetworkId,
@@ -1896,11 +1900,6 @@
mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED,
new WpsResult(Status.FAILURE));
break;
- case WifiP2pService.P2P_ENABLE_PENDING:
- // turn off wifi and defer to be handled in DriverUnloadedState
- setWifiEnabled(false);
- deferMessage(message);
- break;
default:
loge("Error! unhandled message" + message);
break;
@@ -2060,7 +2059,7 @@
loge("Unable to change interface settings: " + ie);
}
- if(mWifiNative.startSupplicant()) {
+ if(mWifiNative.startSupplicant(mP2pSupported)) {
if (DBG) log("Supplicant start successful");
mWifiMonitor.startMonitoring();
transitionTo(mSupplicantStartingState);
@@ -2172,11 +2171,7 @@
if (DBG) log(getName() + message.toString() + "\n");
switch (message.what) {
case CMD_LOAD_DRIVER:
- mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);
- transitionTo(mWaitForP2pDisableState);
- break;
- case WifiP2pService.P2P_ENABLE_PENDING:
- mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED);
+ transitionTo(mDriverLoadingState);
break;
default:
return NOT_HANDLED;
@@ -2395,6 +2390,10 @@
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ /* Send any reset commands to supplicant before shutting it down */
+ handleNetworkDisconnect();
+
if (DBG) log("stopping supplicant");
if (!mWifiNative.stopSupplicant()) {
loge("Failed to stop supplicant");
@@ -2405,7 +2404,6 @@
++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
mNetworkInfo.setIsAvailable(false);
- handleNetworkDisconnect();
setWifiState(WIFI_STATE_DISABLING);
sendSupplicantConnectionChangedBroadcast(false);
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
@@ -2553,13 +2551,15 @@
mWifiNative.status();
transitionTo(mDisconnectedState);
}
+
+ if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
}
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
boolean eventLoggingEnabled = true;
switch(message.what) {
- case CMD_SET_SCAN_TYPE:
+ case CMD_SET_SCAN_TYPE:
mSetScanActive = (message.arg1 == SCAN_ACTIVE);
mWifiNative.setScanMode(mSetScanActive);
break;
@@ -2672,6 +2672,8 @@
mIsRunning = false;
updateBatteryWorkSource(null);
mScanResults = null;
+
+ if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
}
}
@@ -3345,7 +3347,6 @@
case CMD_START_PACKET_FILTERING:
case CMD_STOP_PACKET_FILTERING:
case CMD_TETHER_STATE_CHANGE:
- case WifiP2pService.P2P_ENABLE_PENDING:
deferMessage(message);
break;
case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
@@ -3409,55 +3410,6 @@
transitionTo(mTetheringState);
}
break;
- case WifiP2pService.P2P_ENABLE_PENDING:
- // turn of soft Ap and defer to be handled in DriverUnloadedState
- setWifiApEnabled(null, false);
- deferMessage(message);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class WaitForP2pDisableState extends State {
- private int mSavedArg;
- @Override
- public void enter() {
- if (DBG) log(getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- //Preserve the argument arg1 that has information used in DriverLoadingState
- mSavedArg = getCurrentMessage().arg1;
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
- switch(message.what) {
- case WifiP2pService.WIFI_ENABLE_PROCEED:
- //restore argument from original message (CMD_LOAD_DRIVER)
- message.arg1 = mSavedArg;
- transitionTo(mDriverLoadingState);
- break;
- case CMD_LOAD_DRIVER:
- case CMD_UNLOAD_DRIVER:
- case CMD_START_SUPPLICANT:
- case CMD_STOP_SUPPLICANT:
- case CMD_START_AP:
- case CMD_STOP_AP:
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case CMD_SET_SCAN_MODE:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_HIGH_PERF_MODE:
- case CMD_SET_COUNTRY_CODE:
- case CMD_SET_FREQUENCY_BAND:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
default:
return NOT_HANDLED;
}
@@ -3507,7 +3459,6 @@
case CMD_SET_FREQUENCY_BAND:
case CMD_START_PACKET_FILTERING:
case CMD_STOP_PACKET_FILTERING:
- case WifiP2pService.P2P_ENABLE_PENDING:
deferMessage(message);
break;
default:
@@ -3603,7 +3554,6 @@
case CMD_SET_FREQUENCY_BAND:
case CMD_START_PACKET_FILTERING:
case CMD_STOP_PACKET_FILTERING:
- case WifiP2pService.P2P_ENABLE_PENDING:
deferMessage(message);
break;
default:
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 7471a2d..b0cde64 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -301,7 +301,8 @@
private String trimQuotes(String str) {
str = str.trim();
if (str.startsWith("'") && str.endsWith("'")) {
- return str.substring(1, str.length()-1);
+ if (str.length() <= 2) return "";
+ else return str.substring(1, str.length()-1);
}
return str;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 9205300..4fd0a57 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -199,68 +199,61 @@
private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
/** @hide */
- public static final int ENABLE_P2P = BASE + 1;
+ public static final int DISCOVER_PEERS = BASE + 1;
/** @hide */
- public static final int ENABLE_P2P_FAILED = BASE + 2;
+ public static final int DISCOVER_PEERS_FAILED = BASE + 2;
/** @hide */
- public static final int ENABLE_P2P_SUCCEEDED = BASE + 3;
+ public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 3;
/** @hide */
- public static final int DISABLE_P2P = BASE + 4;
+ public static final int STOP_DISCOVERY = BASE + 4;
/** @hide */
- public static final int DISABLE_P2P_FAILED = BASE + 5;
+ public static final int STOP_DISCOVERY_FAILED = BASE + 5;
/** @hide */
- public static final int DISABLE_P2P_SUCCEEDED = BASE + 6;
+ public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 6;
/** @hide */
- public static final int DISCOVER_PEERS = BASE + 7;
+ public static final int CONNECT = BASE + 7;
/** @hide */
- public static final int DISCOVER_PEERS_FAILED = BASE + 8;
+ public static final int CONNECT_FAILED = BASE + 8;
/** @hide */
- public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 9;
+ public static final int CONNECT_SUCCEEDED = BASE + 9;
/** @hide */
- public static final int CONNECT = BASE + 10;
+ public static final int CANCEL_CONNECT = BASE + 10;
/** @hide */
- public static final int CONNECT_FAILED = BASE + 11;
+ public static final int CANCEL_CONNECT_FAILED = BASE + 11;
/** @hide */
- public static final int CONNECT_SUCCEEDED = BASE + 12;
+ public static final int CANCEL_CONNECT_SUCCEEDED = BASE + 12;
/** @hide */
- public static final int CANCEL_CONNECT = BASE + 13;
+ public static final int CREATE_GROUP = BASE + 13;
/** @hide */
- public static final int CANCEL_CONNECT_FAILED = BASE + 14;
+ public static final int CREATE_GROUP_FAILED = BASE + 14;
/** @hide */
- public static final int CANCEL_CONNECT_SUCCEEDED = BASE + 15;
+ public static final int CREATE_GROUP_SUCCEEDED = BASE + 15;
/** @hide */
- public static final int CREATE_GROUP = BASE + 16;
+ public static final int REMOVE_GROUP = BASE + 16;
/** @hide */
- public static final int CREATE_GROUP_FAILED = BASE + 17;
+ public static final int REMOVE_GROUP_FAILED = BASE + 17;
/** @hide */
- public static final int CREATE_GROUP_SUCCEEDED = BASE + 18;
+ public static final int REMOVE_GROUP_SUCCEEDED = BASE + 18;
/** @hide */
- public static final int REMOVE_GROUP = BASE + 19;
+ public static final int REQUEST_PEERS = BASE + 19;
/** @hide */
- public static final int REMOVE_GROUP_FAILED = BASE + 20;
- /** @hide */
- public static final int REMOVE_GROUP_SUCCEEDED = BASE + 21;
+ public static final int RESPONSE_PEERS = BASE + 20;
/** @hide */
- public static final int REQUEST_PEERS = BASE + 22;
+ public static final int REQUEST_CONNECTION_INFO = BASE + 21;
/** @hide */
- public static final int RESPONSE_PEERS = BASE + 23;
+ public static final int RESPONSE_CONNECTION_INFO = BASE + 22;
/** @hide */
- public static final int REQUEST_CONNECTION_INFO = BASE + 24;
+ public static final int REQUEST_GROUP_INFO = BASE + 23;
/** @hide */
- public static final int RESPONSE_CONNECTION_INFO = BASE + 25;
-
- /** @hide */
- public static final int REQUEST_GROUP_INFO = BASE + 26;
- /** @hide */
- public static final int RESPONSE_GROUP_INFO = BASE + 27;
+ public static final int RESPONSE_GROUP_INFO = BASE + 24;
/**
* Create a new WifiP2pManager instance. Applications use
@@ -376,6 +369,7 @@
break;
/* ActionListeners grouped together */
case WifiP2pManager.DISCOVER_PEERS_FAILED:
+ case WifiP2pManager.STOP_DISCOVERY_FAILED:
case WifiP2pManager.CONNECT_FAILED:
case WifiP2pManager.CANCEL_CONNECT_FAILED:
case WifiP2pManager.CREATE_GROUP_FAILED:
@@ -386,6 +380,7 @@
break;
/* ActionListeners grouped together */
case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED:
+ case WifiP2pManager.STOP_DISCOVERY_SUCCEEDED:
case WifiP2pManager.CONNECT_SUCCEEDED:
case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED:
case WifiP2pManager.CREATE_GROUP_SUCCEEDED:
@@ -459,26 +454,6 @@
}
/**
- * Sends in a request to the system to enable p2p. This will pop up a dialog
- * to the user and upon authorization will enable p2p.
- * @hide
- */
- public void enableP2p(Channel c) {
- if (c == null) return;
- c.mAsyncChannel.sendMessage(ENABLE_P2P);
- }
-
- /**
- * Sends in a request to the system to disable p2p. This will pop up a dialog
- * to the user and upon authorization will enable p2p.
- * @hide
- */
- public void disableP2p(Channel c) {
- if (c == null) return;
- c.mAsyncChannel.sendMessage(DISABLE_P2P);
- }
-
- /**
* Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
* for the purpose of establishing a connection.
*
@@ -503,6 +478,16 @@
}
/**
+ * TODO: Add more documentation before opening up
+ * Cancel peer discovery
+ * @hide
+ */
+ public void stopPeerDiscovery(Channel c, ActionListener listener) {
+ if (c == null) return;
+ c.mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, c.putListener(listener));
+ }
+
+ /**
* Start a p2p connection to a device with the specified configuration.
*
* <p> The function call immediately returns after sending a connection request
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 69cbb5c..5b0e424 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -49,6 +49,7 @@
import android.os.HandlerThread;
import android.os.Message;
import android.os.Messenger;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -84,7 +85,7 @@
*/
public class WifiP2pService extends IWifiP2pManager.Stub {
private static final String TAG = "WifiP2pService";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final String NETWORKTYPE = "WIFI_P2P";
private Context mContext;
@@ -94,11 +95,6 @@
INetworkManagementService mNwService;
private DhcpStateMachine mDhcpStateMachine;
- //Tracked to notify the user about wifi client/hotspot being shut down
- //during p2p bring up
- private int mWifiState = WifiManager.WIFI_STATE_DISABLED;
- private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED;
-
private P2pStateMachine mP2pStateMachine;
private AsyncChannel mReplyChannel = new AsyncChannel();
private AsyncChannel mWifiChannel;
@@ -110,6 +106,9 @@
private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
private static int mGroupCreatingTimeoutIndex = 0;
+ /* Set a two minute discover timeout to avoid STA scans from being blocked */
+ private static final int DISCOVER_TIMEOUT_S = 120;
+
/**
* Delay between restarts upon failure to setup connection with supplicant
*/
@@ -124,28 +123,13 @@
private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
- /* Message sent to WifiStateMachine to indicate p2p enable is pending */
- public static final int P2P_ENABLE_PENDING = BASE + 1;
- /* Message sent to WifiStateMachine to indicate Wi-Fi client/hotspot operation can proceed */
- public static final int WIFI_ENABLE_PROCEED = BASE + 2;
-
/* Delayed message to timeout group creation */
- public static final int GROUP_CREATING_TIMED_OUT = BASE + 3;
-
- /* User accepted to disable Wi-Fi in order to enable p2p */
- private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 4;
- /* User rejected to disable Wi-Fi in order to enable p2p */
- private static final int WIFI_DISABLE_USER_REJECT = BASE + 5;
+ public static final int GROUP_CREATING_TIMED_OUT = BASE + 1;
/* User accepted a peer request */
- private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 6;
+ private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2;
/* User rejected a peer request */
- private static final int PEER_CONNECTION_USER_REJECT = BASE + 7;
-
- /* Airplane mode changed */
- private static final int AIRPLANE_MODE_CHANGED = BASE + 8;
- /* Emergency callback mode */
- private static final int EMERGENCY_CALLBACK_MODE = BASE + 9;
+ private static final int PEER_CONNECTION_USER_REJECT = BASE + 3;
private final boolean mP2pSupported;
@@ -166,7 +150,7 @@
public WifiP2pService(Context context) {
mContext = context;
- //STOPSHIP: fix this
+ //STOPSHIP: get this from native side
mInterface = "p2p0";
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
@@ -179,15 +163,6 @@
mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
mP2pStateMachine.start();
-
- // broadcasts
- IntentFilter filter = new IntentFilter();
- filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
- filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- mContext.registerReceiver(new WifiStateReceiver(), filter);
-
}
public void connectivityServiceReady() {
@@ -195,26 +170,6 @@
mNwService = INetworkManagementService.Stub.asInterface(b);
}
- private class WifiStateReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_DISABLED);
- } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
- mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
- WifiManager.WIFI_AP_STATE_DISABLED);
- } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- mP2pStateMachine.sendMessage(AIRPLANE_MODE_CHANGED);
- } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
- if (intent.getBooleanExtra("phoneinECMState", false) == true) {
- mP2pStateMachine.sendMessage(EMERGENCY_CALLBACK_MODE);
- }
- }
- }
- }
-
private void enforceAccessPermission() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
"WifiP2pService");
@@ -264,8 +219,6 @@
private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState();
private P2pDisablingState mP2pDisablingState = new P2pDisablingState();
private P2pDisabledState mP2pDisabledState = new P2pDisabledState();
- private WaitForUserActionState mWaitForUserActionState = new WaitForUserActionState();
- private WaitForWifiDisableState mWaitForWifiDisableState = new WaitForWifiDisableState();
private P2pEnablingState mP2pEnablingState = new P2pEnablingState();
private P2pEnabledState mP2pEnabledState = new P2pEnabledState();
// Inactive is when p2p is enabled with no connectivity
@@ -299,8 +252,6 @@
addState(mP2pNotSupportedState, mDefaultState);
addState(mP2pDisablingState, mDefaultState);
addState(mP2pDisabledState, mDefaultState);
- addState(mWaitForUserActionState, mP2pDisabledState);
- addState(mWaitForWifiDisableState, mP2pDisabledState);
addState(mP2pEnablingState, mDefaultState);
addState(mP2pEnabledState, mDefaultState);
addState(mInactiveState, mP2pEnabledState);
@@ -346,23 +297,14 @@
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, getHandler(), message.replyTo);
break;
- case WifiStateMachine.WIFI_ENABLE_PENDING:
- // Disable p2p operation before we can respond
- sendMessage(WifiP2pManager.DISABLE_P2P);
- deferMessage(message);
- break;
- case WifiP2pManager.ENABLE_P2P:
- replyToMessage(message, WifiP2pManager.ENABLE_P2P_FAILED,
- WifiP2pManager.BUSY);
- break;
- case WifiP2pManager.DISABLE_P2P:
- replyToMessage(message, WifiP2pManager.DISABLE_P2P_FAILED,
- WifiP2pManager.BUSY);
- break;
case WifiP2pManager.DISCOVER_PEERS:
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.BUSY);
break;
+ case WifiP2pManager.STOP_DISCOVERY:
+ replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
+ WifiP2pManager.BUSY);
+ break;
case WifiP2pManager.CONNECT:
replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
WifiP2pManager.BUSY);
@@ -388,16 +330,14 @@
case WifiP2pManager.REQUEST_GROUP_INFO:
replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
break;
- case AIRPLANE_MODE_CHANGED:
- if (isAirplaneModeOn()) sendMessage(WifiP2pManager.DISABLE_P2P);
- break;
- case EMERGENCY_CALLBACK_MODE:
- sendMessage(WifiP2pManager.DISABLE_P2P);
- break;
// Ignore
case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
- case WIFI_DISABLE_USER_ACCEPT:
- case WIFI_DISABLE_USER_REJECT:
+ case WifiMonitor.SCAN_RESULTS_EVENT:
+ case WifiMonitor.SUP_CONNECTION_EVENT:
+ case WifiMonitor.SUP_DISCONNECTION_EVENT:
+ case WifiMonitor.NETWORK_CONNECTION_EVENT:
+ case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
+ case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
case PEER_CONNECTION_USER_ACCEPT:
case PEER_CONNECTION_USER_REJECT:
case GROUP_CREATING_TIMED_OUT:
@@ -414,22 +354,14 @@
@Override
public boolean processMessage(Message message) {
switch (message.what) {
- // Allow Wi-Fi to proceed
- case WifiStateMachine.WIFI_ENABLE_PENDING:
- replyToMessage(message, WIFI_ENABLE_PROCEED);
- break;
- case WifiP2pManager.ENABLE_P2P:
- replyToMessage(message, WifiP2pManager.ENABLE_P2P_FAILED,
- WifiP2pManager.P2P_UNSUPPORTED);
- break;
- case WifiP2pManager.DISABLE_P2P:
- replyToMessage(message, WifiP2pManager.DISABLE_P2P_FAILED,
- WifiP2pManager.P2P_UNSUPPORTED);
- break;
- case WifiP2pManager.DISCOVER_PEERS:
+ case WifiP2pManager.DISCOVER_PEERS:
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
+ case WifiP2pManager.STOP_DISCOVERY:
+ replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
+ WifiP2pManager.P2P_UNSUPPORTED);
+ break;
case WifiP2pManager.CONNECT:
replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
@@ -438,7 +370,7 @@
replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
- case WifiP2pManager.CREATE_GROUP:
+ case WifiP2pManager.CREATE_GROUP:
replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
@@ -455,26 +387,15 @@
class P2pDisablingState extends State {
@Override
- public void enter() {
- if (DBG) logd(getName());
- logd("stopping supplicant");
- if (!mWifiNative.stopSupplicant()) {
- loge("Failed to stop supplicant, issue kill");
- mWifiNative.killSupplicant();
- }
- }
-
- @Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiMonitor.SUP_DISCONNECTION_EVENT:
- logd("Supplicant connection lost");
- mWifiNative.closeSupplicantConnection();
+ if (DBG) logd("p2p socket connection lost");
transitionTo(mP2pDisabledState);
break;
- case WifiP2pManager.ENABLE_P2P:
- case WifiP2pManager.DISABLE_P2P:
+ case WifiStateMachine.CMD_ENABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P:
deferMessage(message);
break;
default:
@@ -484,7 +405,6 @@
}
}
-
class P2pDisabledState extends State {
@Override
public void enter() {
@@ -495,118 +415,19 @@
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
- case WifiP2pManager.ENABLE_P2P:
- OnClickListener listener = new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- sendMessage(WIFI_DISABLE_USER_ACCEPT);
- } else {
- sendMessage(WIFI_DISABLE_USER_REJECT);
- }
- }
- };
-
- // Show a user request dialog if we know Wi-Fi client/hotspot is in operation
- if (mWifiState != WifiManager.WIFI_STATE_DISABLED ||
- mWifiApState != WifiManager.WIFI_AP_STATE_DISABLED) {
- Resources r = Resources.getSystem();
- AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
- .setMessage(r.getString(R.string.wifi_p2p_turnon_message))
- .setPositiveButton(r.getString(R.string.ok), listener)
- .setNegativeButton(r.getString(R.string.cancel), listener)
- .create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- dialog.show();
- transitionTo(mWaitForUserActionState);
- } else {
- mWifiChannel.sendMessage(P2P_ENABLE_PENDING);
- transitionTo(mWaitForWifiDisableState);
- }
- replyToMessage(message, WifiP2pManager.ENABLE_P2P_SUCCEEDED);
- break;
- case WifiP2pManager.DISABLE_P2P:
- replyToMessage(message, WifiP2pManager.DISABLE_P2P_SUCCEEDED);
- break;
- case WifiStateMachine.WIFI_ENABLE_PENDING:
- replyToMessage(message, WIFI_ENABLE_PROCEED);
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- class WaitForUserActionState extends State {
- @Override
- public void enter() {
- if (DBG) logd(getName());
- }
-
- @Override
- public boolean processMessage(Message message) {
- if (DBG) logd(getName() + message.toString());
- switch (message.what) {
- case WIFI_DISABLE_USER_ACCEPT:
- mWifiChannel.sendMessage(P2P_ENABLE_PENDING);
- transitionTo(mWaitForWifiDisableState);
- break;
- case WIFI_DISABLE_USER_REJECT:
- logd("User rejected enabling p2p");
- sendP2pStateChangedBroadcast(false);
- transitionTo(mP2pDisabledState);
- break;
- case WifiP2pManager.ENABLE_P2P:
- case WifiP2pManager.DISABLE_P2P:
- deferMessage(message);
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- class WaitForWifiDisableState extends State {
- @Override
- public void enter() {
- if (DBG) logd(getName());
- }
-
- @Override
- public boolean processMessage(Message message) {
- if (DBG) logd(getName() + message.toString());
- switch (message.what) {
- case WifiStateMachine.P2P_ENABLE_PROCEED:
+ case WifiStateMachine.CMD_ENABLE_P2P:
try {
- mNwService.wifiFirmwareReload(mInterface, "P2P");
- } catch (Exception e) {
- loge("Failed to reload p2p firmware " + e);
- // continue
+ mNwService.setInterfaceUp(mInterface);
+ } catch (RemoteException re) {
+ loge("Unable to change interface settings: " + re);
+ } catch (IllegalStateException ie) {
+ loge("Unable to change interface settings: " + ie);
}
-
- //A runtime crash can leave the interface up and
- //this affects p2p when supplicant starts up.
- //Ensure interface is down before a supplicant start.
- try {
- mNwService.setInterfaceDown(mInterface);
- } catch (Exception e) {
- if (DBG) Slog.w(TAG, "Unable to bring down wlan interface: " + e);
- }
-
- if (mWifiNative.startP2pSupplicant()) {
- mWifiMonitor.startMonitoring();
- transitionTo(mP2pEnablingState);
- } else {
- notifyP2pEnableFailure();
- transitionTo(mP2pDisabledState);
- }
+ mWifiMonitor.startMonitoring();
+ transitionTo(mP2pEnablingState);
break;
- case WifiP2pManager.ENABLE_P2P:
- case WifiP2pManager.DISABLE_P2P:
- deferMessage(message);
+ case WifiStateMachine.CMD_DISABLE_P2P:
+ //Nothing to do
break;
default:
return NOT_HANDLED;
@@ -626,22 +447,15 @@
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiMonitor.SUP_CONNECTION_EVENT:
- logd("P2p start successful");
+ if (DBG) logd("P2p socket connection successful");
transitionTo(mInactiveState);
break;
case WifiMonitor.SUP_DISCONNECTION_EVENT:
- if (++mP2pRestartCount <= P2P_RESTART_TRIES) {
- loge("Failed to start p2p, retry");
- mWifiNative.killSupplicant();
- sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS);
- } else {
- loge("Failed " + mP2pRestartCount + " times to start p2p, quit ");
- mP2pRestartCount = 0;
- }
+ loge("P2p socket connection failed");
transitionTo(mP2pDisabledState);
break;
- case WifiP2pManager.ENABLE_P2P:
- case WifiP2pManager.DISABLE_P2P:
+ case WifiStateMachine.CMD_ENABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P:
deferMessage(message);
break;
default:
@@ -658,30 +472,36 @@
sendP2pStateChangedBroadcast(true);
mNetworkInfo.setIsAvailable(true);
initializeP2pSettings();
- showNotification();
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
- case WifiP2pManager.ENABLE_P2P:
- replyToMessage(message, WifiP2pManager.ENABLE_P2P_SUCCEEDED);
+ case WifiStateMachine.CMD_ENABLE_P2P:
+ //Nothing to do
break;
- case WifiP2pManager.DISABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P:
if (mPeers.clear()) sendP2pPeersChangedBroadcast();
- replyToMessage(message, WifiP2pManager.DISABLE_P2P_SUCCEEDED);
+ mWifiNative.closeSupplicantConnection();
transitionTo(mP2pDisablingState);
break;
case WifiP2pManager.DISCOVER_PEERS:
- int timeout = message.arg1;
- if (mWifiNative.p2pFind(timeout)) {
+ if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.ERROR);
}
break;
+ case WifiP2pManager.STOP_DISCOVERY:
+ if (mWifiNative.p2pStopFind()) {
+ replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
+ } else {
+ replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
+ WifiP2pManager.ERROR);
+ }
+ break;
case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
WifiP2pDevice device = (WifiP2pDevice) message.obj;
if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
@@ -692,15 +512,7 @@
device = (WifiP2pDevice) message.obj;
if (mPeers.remove(device)) sendP2pPeersChangedBroadcast();
break;
- case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant died */
- loge("Connection lost, restart p2p");
- mWifiNative.killSupplicant();
- mWifiNative.closeSupplicantConnection();
- if (mPeers.clear()) sendP2pPeersChangedBroadcast();
- transitionTo(mP2pDisabledState);
- sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS);
- break;
- default:
+ default:
return NOT_HANDLED;
}
return HANDLED;
@@ -710,7 +522,6 @@
public void exit() {
sendP2pStateChangedBroadcast(false);
mNetworkInfo.setIsAvailable(false);
- clearNotification();
}
}
@@ -719,7 +530,8 @@
public void enter() {
if (DBG) logd(getName());
//Start listening every time we get inactive
- mWifiNative.p2pListen();
+ //TODO: Fix listen after driver behavior is fixed
+ //mWifiNative.p2pListen();
}
@Override
@@ -737,6 +549,8 @@
//TODO: if failure, remove config and do a regular p2pConnect()
mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress);
} else {
+ //Stop discovery before issuing connect
+ mWifiNative.p2pStopFind();
//If peer is a GO, we do not need to send provisional discovery,
//the supplicant takes care of it.
if (isGroupOwner(mSavedPeerConfig.deviceAddress)) {
@@ -1114,7 +928,7 @@
}
// Do the regular device lost handling
return NOT_HANDLED;
- case WifiP2pManager.DISABLE_P2P:
+ case WifiStateMachine.CMD_DISABLE_P2P:
sendMessage(WifiP2pManager.REMOVE_GROUP);
deferMessage(message);
break;
@@ -1494,54 +1308,5 @@
Slog.e(TAG, s);
}
- private void showNotification() {
- NotificationManager notificationManager =
- (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager == null || mNotification != null) {
- return;
- }
-
- Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-
- PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-
- Resources r = Resources.getSystem();
- CharSequence title = r.getText(R.string.wifi_p2p_enabled_notification_title);
- CharSequence message = r.getText(R.string.wifi_p2p_enabled_notification_message);
-
- mNotification = new Notification();
- mNotification.when = 0;
- //TODO: might change to be a seperate icon
- mNotification.icon = R.drawable.stat_sys_tether_wifi;
- mNotification.defaults &= ~Notification.DEFAULT_SOUND;
- mNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mNotification.tickerText = title;
- mNotification.setLatestEventInfo(mContext, title, message, pi);
-
- notificationManager.notify(mNotification.icon, mNotification);
- }
-
- private void clearNotification() {
- NotificationManager notificationManager =
- (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager != null && mNotification != null) {
- notificationManager.cancel(mNotification.icon);
- mNotification = null;
- }
- }
-
- private boolean isAirplaneSensitive() {
- String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_RADIOS);
- return airplaneModeRadios == null
- || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
- }
-
- private boolean isAirplaneModeOn() {
- return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON, 0) == 1;
- }
-
}
}