Merge "bugreport: Add ping wlan gateway, dns1 and dns2 servers"
diff --git a/Android.mk b/Android.mk
index de0112c..aae10dc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -315,7 +315,6 @@
fwbase_dirs_to_document += core/config/sdk
# include definition of libcore_to_document
-# These are relative to libcore
include $(LOCAL_PATH)/../../libcore/Docs.mk
non_base_dirs := \
@@ -324,8 +323,7 @@
# These are relative to frameworks/base
dirs_to_document := \
$(fwbase_dirs_to_document) \
- $(non_base_dirs) \
- $(addprefix ../../libcore/, $(libcore_to_document))
+ $(non_base_dirs)
html_dirs := \
$(FRAMEWORKS_BASE_SUBDIRS) \
@@ -334,7 +332,8 @@
# These are relative to frameworks/base
framework_docs_LOCAL_SRC_FILES := \
$(call find-other-java-files, $(dirs_to_document)) \
- $(call find-other-html-files, $(html_dirs))
+ $(call find-other-html-files, $(html_dirs)) \
+ $(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore))
# This is used by ide.mk as the list of source files that are
# always included.
diff --git a/api/current.xml b/api/current.xml
index 3305a32..555f804 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -9068,6 +9068,17 @@
visibility="public"
>
</field>
+<field name="state_hovered"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843620"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="state_last"
type="int"
transient="false"
@@ -31494,6 +31505,25 @@
<parameter name="exit" type="int">
</parameter>
</method>
+<method name="setCustomAnimations"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enter" type="int">
+</parameter>
+<parameter name="exit" type="int">
+</parameter>
+<parameter name="popEnter" type="int">
+</parameter>
+<parameter name="popExit" type="int">
+</parameter>
+</method>
<method name="setTransition"
return="android.app.FragmentTransaction"
abstract="true"
@@ -86730,6 +86760,17 @@
<parameter name="texName" type="int">
</parameter>
</constructor>
+<method name="getTimestamp"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getTransformMatrix"
return="void"
abstract="false"
@@ -93386,6 +93427,17 @@
visibility="public"
>
</field>
+<field name="TYPE_AMBIENT_TEMPERATURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TYPE_GRAVITY"
type="int"
transient="false"
@@ -93492,7 +93544,7 @@
value="7"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -202087,7 +202139,7 @@
>
<parameter name="context" type="android.content.Context">
</parameter>
-<parameter name="suggests" type="java.util.List<java.lang.CharSequence>">
+<parameter name="suggestions" type="java.lang.String[]">
</parameter>
<parameter name="flags" type="int">
</parameter>
@@ -202101,7 +202153,7 @@
>
<parameter name="locale" type="java.util.Locale">
</parameter>
-<parameter name="suggests" type="java.util.List<java.lang.CharSequence>">
+<parameter name="suggestions" type="java.lang.String[]">
</parameter>
<parameter name="flags" type="int">
</parameter>
@@ -202117,7 +202169,7 @@
</parameter>
<parameter name="locale" type="java.util.Locale">
</parameter>
-<parameter name="suggests" type="java.util.List<java.lang.CharSequence>">
+<parameter name="suggestions" type="java.lang.String[]">
</parameter>
<parameter name="flags" type="int">
</parameter>
@@ -202189,8 +202241,8 @@
visibility="public"
>
</method>
-<method name="getSuggests"
- return="java.util.List<java.lang.CharSequence>"
+<method name="getSuggestions"
+ return="java.lang.String[]"
abstract="false"
native="false"
synchronized="false"
@@ -202225,17 +202277,6 @@
visibility="public"
>
</field>
-<field name="FLAG_DEFAULT"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="FLAG_VERBATIM"
type="int"
transient="false"
@@ -218638,6 +218679,28 @@
visibility="public"
>
</field>
+<field name="ACTION_HOVER_ENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_HOVER_EXIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_HOVER_MOVE"
type="int"
transient="false"
@@ -223461,6 +223524,17 @@
visibility="public"
>
</method>
+<method name="isHovered"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isInEditMode"
return="boolean"
abstract="false"
@@ -223936,6 +224010,19 @@
<parameter name="event" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="onHoverEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -224976,6 +225063,19 @@
<parameter name="horizontalScrollBarEnabled" type="boolean">
</parameter>
</method>
+<method name="setHovered"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="hovered" type="boolean">
+</parameter>
+</method>
<method name="setId"
return="void"
abstract="false"
@@ -236982,27 +237082,6 @@
<parameter name="newCursorPosition" type="int">
</parameter>
</method>
-<method name="setCorrectionSpan"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="token" type="android.os.IBinder">
-</parameter>
-<parameter name="correctionSpan" type="android.text.style.CorrectionSpan">
-</parameter>
-<parameter name="start" type="int">
-</parameter>
-<parameter name="end" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
<method name="setSelection"
return="boolean"
abstract="false"
@@ -238273,27 +238352,6 @@
<parameter name="newCursorPosition" type="int">
</parameter>
</method>
-<method name="setCorrectionSpan"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="token" type="android.os.IBinder">
-</parameter>
-<parameter name="correctionSpan" type="android.text.style.CorrectionSpan">
-</parameter>
-<parameter name="start" type="int">
-</parameter>
-<parameter name="end" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
<method name="setSelection"
return="boolean"
abstract="true"
@@ -238624,27 +238682,6 @@
<parameter name="newCursorPosition" type="int">
</parameter>
</method>
-<method name="setCorrectionSpan"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="token" type="android.os.IBinder">
-</parameter>
-<parameter name="correctionSpan" type="android.text.style.CorrectionSpan">
-</parameter>
-<parameter name="start" type="int">
-</parameter>
-<parameter name="end" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
<method name="setSelection"
return="boolean"
abstract="false"
@@ -264971,27 +265008,6 @@
<parameter name="bottom" type="android.graphics.drawable.Drawable">
</parameter>
</method>
-<method name="setCorrectionSpan"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="token" type="android.os.IBinder">
-</parameter>
-<parameter name="span" type="android.text.style.CorrectionSpan">
-</parameter>
-<parameter name="start" type="int">
-</parameter>
-<parameter name="end" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
<method name="setCursorVisible"
return="void"
abstract="false"
@@ -267652,7 +267668,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 2b89759..a00a212 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -22,7 +22,7 @@
libskia \
libEGL \
libGLESv1_CM \
- libsurfaceflinger_client
+ libgui
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk
index 400a36b..ca8008b 100644
--- a/cmds/screencap/Android.mk
+++ b/cmds/screencap/Android.mk
@@ -10,7 +10,7 @@
libbinder \
libskia \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= screencap
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 1b13dd9..e9642f7 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -8,7 +8,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libutils libbinder libstagefright_foundation \
- libskia libsurfaceflinger_client libgui
+ libskia libgui
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -107,7 +107,7 @@
stream.cpp \
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libsurfaceflinger_client \
+ libstagefright liblog libutils libbinder libgui \
libstagefright_foundation libmedia
LOCAL_C_INCLUDES:= \
@@ -132,7 +132,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
- libmedia libsurfaceflinger_client libcutils libui
+ libmedia libgui libcutils libui
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 894e196..93983a6 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1786,22 +1786,6 @@
}
}
- private String getMetaValue(String key) {
- synchronized (mCacheLock) {
- final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor c = db.query(TABLE_META,
- new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
- try {
- if (c.moveToNext()) {
- return c.getString(0);
- }
- return null;
- } finally {
- c.close();
- }
- }
- }
-
public IBinder onBind(Intent intent) {
return asBinder();
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 1d217f0..850f56a 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -43,7 +43,7 @@
if (op.removed != null) numRemoved += op.removed.size();
op = op.next;
}
- mOps = new int[bse.mNumOp*5 + numRemoved];
+ mOps = new int[bse.mNumOp*7 + numRemoved];
if (!bse.mAddToBackStack) {
throw new IllegalStateException("Not on back stack");
@@ -56,6 +56,8 @@
mOps[pos++] = op.fragment.mIndex;
mOps[pos++] = op.enterAnim;
mOps[pos++] = op.exitAnim;
+ mOps[pos++] = op.popEnterAnim;
+ mOps[pos++] = op.popExitAnim;
if (op.removed != null) {
final int N = op.removed.size();
mOps[pos++] = N;
@@ -101,6 +103,8 @@
op.fragment = f;
op.enterAnim = mOps[pos++];
op.exitAnim = mOps[pos++];
+ op.popEnterAnim = mOps[pos++];
+ op.popExitAnim = mOps[pos++];
final int N = mOps[pos++];
if (N > 0) {
op.removed = new ArrayList<Fragment>(N);
@@ -177,6 +181,8 @@
Fragment fragment;
int enterAnim;
int exitAnim;
+ int popEnterAnim;
+ int popExitAnim;
ArrayList<Fragment> removed;
}
@@ -185,6 +191,8 @@
int mNumOp;
int mEnterAnim;
int mExitAnim;
+ int mPopEnterAnim;
+ int mPopExitAnim;
int mTransition;
int mTransitionStyle;
boolean mAddToBackStack;
@@ -241,6 +249,11 @@
writer.print(prefix); writer.print("enterAnim="); writer.print(op.enterAnim);
writer.print(" exitAnim="); writer.println(op.exitAnim);
}
+ if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
+ writer.print(prefix);
+ writer.print("popEnterAnim="); writer.print(op.popEnterAnim);
+ writer.print(" popExitAnim="); writer.println(op.popExitAnim);
+ }
if (op.removed != null && op.removed.size() > 0) {
for (int i=0; i<op.removed.size(); i++) {
writer.print(innerPrefix);
@@ -299,6 +312,8 @@
}
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
+ op.popEnterAnim = mPopEnterAnim;
+ op.popExitAnim = mPopExitAnim;
mNumOp++;
}
@@ -402,8 +417,15 @@
}
public FragmentTransaction setCustomAnimations(int enter, int exit) {
+ return setCustomAnimations(enter, exit, 0, 0);
+ }
+
+ public FragmentTransaction setCustomAnimations(int enter, int exit,
+ int popEnter, int popExit) {
mEnterAnim = enter;
mExitAnim = exit;
+ mPopEnterAnim = popEnter;
+ mPopExitAnim = popExit;
return this;
}
@@ -593,6 +615,7 @@
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
+ f.mNextAnim = op.popExitAnim;
f.mImmediateActivity = null;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
@@ -600,6 +623,7 @@
} break;
case OP_REPLACE: {
Fragment f = op.fragment;
+ f.mNextAnim = op.popExitAnim;
f.mImmediateActivity = null;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
@@ -607,6 +631,7 @@
if (op.removed != null) {
for (int i=0; i<op.removed.size(); i++) {
Fragment old = op.removed.get(i);
+ old.mNextAnim = op.popEnterAnim;
f.mImmediateActivity = mManager.mActivity;
mManager.addFragment(old, false);
}
@@ -614,16 +639,19 @@
} break;
case OP_REMOVE: {
Fragment f = op.fragment;
+ f.mNextAnim = op.popEnterAnim;
f.mImmediateActivity = mManager.mActivity;
mManager.addFragment(f, false);
} break;
case OP_HIDE: {
Fragment f = op.fragment;
+ f.mNextAnim = op.popEnterAnim;
mManager.showFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
case OP_SHOW: {
Fragment f = op.fragment;
+ f.mNextAnim = op.popExitAnim;
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 0cc774d..68600b3 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -116,10 +116,20 @@
/**
* Set specific animation resources to run for the fragments that are
- * entering and exiting in this transaction.
+ * entering and exiting in this transaction. These animations will not be
+ * played when popping the back stack.
*/
public abstract FragmentTransaction setCustomAnimations(int enter, int exit);
-
+
+ /**
+ * Set specific animation resources to run for the fragments that are
+ * entering and exiting in this transaction. The <code>popEnter</code>
+ * and <code>popExit</code> animations will be played for enter/exit
+ * operations specifically when popping the back stack.
+ */
+ public abstract FragmentTransaction setCustomAnimations(int enter, int exit,
+ int popEnter, int popExit);
+
/**
* Select a standard transition animation for this transaction. May be
* one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN},
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fc07478..80bed0d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1442,7 +1442,7 @@
* {@link Intent#resolveActivity} finds an activity if a class has not
* been explicitly specified.
*
- * <p><em>Note: if using an implicit Intent (without an explicit ComponentName
+ * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName
* specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
* only flag. You need to do so to resolve the activity in the same way
* that {@link android.content.Context#startActivity(Intent)} and
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index ed2b205..e525c95 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -374,6 +374,12 @@
* The preview surface texture may not otherwise change while preview is
* running.
*
+ * The timestamps provided by {@link SurfaceTexture#getTimestamp()} for a
+ * SurfaceTexture set as the preview texture have an unspecified zero point,
+ * and cannot be directly compared between different cameras or different
+ * instances of the same camera, or across multiple runs of the same
+ * program.
+ *
* @param surfaceTexture the {@link SurfaceTexture} to which the preview
* images are to be sent or null to remove the current preview surface
* texture
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f2b907b..a4ba3bd 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -66,7 +66,14 @@
/** A constant describing a pressure sensor type */
public static final int TYPE_PRESSURE = 6;
- /** A constant describing a temperature sensor type */
+ /**
+ * A constant describing a temperature sensor type
+ *
+ * @deprecated use
+ * {@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE
+ * Sensor.TYPE_AMBIENT_TEMPERATURE} instead.
+ */
+ @Deprecated
public static final int TYPE_TEMPERATURE = 7;
/**
@@ -97,6 +104,9 @@
*/
public static final int TYPE_ROTATION_VECTOR = 11;
+ /** A constant describing an ambient temperature sensor type */
+ public static final int TYPE_AMBIENT_TEMPERATURE = 13;
+
/**
* A constant describing all sensor types.
*/
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 78d7991..91f0098 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -305,6 +305,14 @@
* positive in the counter-clockwise direction).
* </p>
*
+ * <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
+ * </h4>
+ *
+ * <ul>
+ * <p>
+ * values[0]: ambient (room) temperature in degree Celsius.
+ * </ul>
+ *
* @see SensorEvent
* @see GeomagneticField
*/
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index f8f8a29..3bf64b2 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -17,18 +17,12 @@
package android.net;
import android.os.SystemProperties;
-import android.util.Config;
import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
-import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
@@ -40,7 +34,6 @@
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
@@ -128,7 +121,7 @@
*
* @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
* for none. The socket timeout is reset to 0 after the handshake.
- * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+ * @param cache The {@link SSLSessionCache} to use, or null for no cache.
* @return a new SSLSocketFactory with the specified parameters
*/
public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
@@ -144,7 +137,7 @@
*
* @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
* for none. The socket timeout is reset to 0 after the handshake.
- * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+ * @param cache The {@link SSLSessionCache} to use, or null for no cache.
* @return an insecure SSLSocketFactory with the specified parameters
*/
public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) {
@@ -157,12 +150,11 @@
*
* @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
* for none. The socket timeout is reset to 0 after the handshake.
- * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+ * @param cache The {@link SSLSessionCache} to use, or null for no cache.
* @return a new SocketFactory with the specified parameters
*/
public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
- int handshakeTimeoutMillis,
- SSLSessionCache cache) {
+ int handshakeTimeoutMillis, SSLSessionCache cache) {
return new org.apache.http.conn.ssl.SSLSocketFactory(
new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
}
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index f82702a..e8148f7 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -28,7 +28,7 @@
* MemoryFile is a wrapper for the Linux ashmem driver.
* MemoryFiles are backed by shared memory, which can be optionally
* set to be purgeable.
- * Purgeable files may have their contents reclaimed by the kernel
+ * Purgeable files may have their contents reclaimed by the kernel
* in low memory conditions (only if allowPurging is set to true).
* After a file is purged, attempts to read or write the file will
* cause an IOException to be thrown.
@@ -126,7 +126,7 @@
close();
}
}
-
+
/**
* Returns the length of the memory file.
*
@@ -190,7 +190,7 @@
* @return number of bytes read.
* @throws IOException if the memory file has been purged or deactivated.
*/
- public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
+ public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
throws IOException {
if (isDeactivated()) {
throw new IOException("Can't read from deactivated memory file.");
@@ -330,6 +330,7 @@
@Override
public void write(byte buffer[], int offset, int count) throws IOException {
writeBytes(buffer, offset, mOffset, count);
+ mOffset += count;
}
@Override
diff --git a/core/java/android/text/CharSequenceIterator.java b/core/java/android/text/CharSequenceIterator.java
new file mode 100644
index 0000000..4946406
--- /dev/null
+++ b/core/java/android/text/CharSequenceIterator.java
@@ -0,0 +1,95 @@
+/*
+ * 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.text;
+
+import android.util.MathUtils;
+
+import java.text.CharacterIterator;
+
+/** {@hide} */
+public class CharSequenceIterator implements CharacterIterator {
+ private final CharSequence mValue;
+
+ private final int mStart;
+ private final int mEnd;
+ private int mIndex;
+
+ public CharSequenceIterator(CharSequence value) {
+ mValue = value;
+ mStart = 0;
+ mEnd = value.length();
+ mIndex = 0;
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public char current() {
+ if (mIndex == mEnd) {
+ return DONE;
+ }
+ return mValue.charAt(mIndex);
+ }
+
+ /** {@inheritDoc} */
+ public int getBeginIndex() {
+ return mStart;
+ }
+
+ /** {@inheritDoc} */
+ public int getEndIndex() {
+ return mEnd;
+ }
+
+ /** {@inheritDoc} */
+ public int getIndex() {
+ return mIndex;
+ }
+
+ /** {@inheritDoc} */
+ public char first() {
+ return setIndex(mStart);
+ }
+
+ /** {@inheritDoc} */
+ public char last() {
+ return setIndex(mEnd - 1);
+ }
+
+ /** {@inheritDoc} */
+ public char next() {
+ return setIndex(mIndex + 1);
+ }
+
+ /** {@inheritDoc} */
+ public char previous() {
+ return setIndex(mIndex - 1);
+ }
+
+ /** {@inheritDoc} */
+ public char setIndex(int index) {
+ mIndex = MathUtils.constrain(index, mStart, mEnd);
+ return current();
+ }
+}
diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java
index 13cb5e6..b18570a 100644
--- a/core/java/android/text/Selection.java
+++ b/core/java/android/text/Selection.java
@@ -16,6 +16,11 @@
package android.text;
+import android.util.Log;
+
+import java.text.BreakIterator;
+import java.text.CharacterIterator;
+
/**
* Utility class for manipulating cursors and selections in CharSequences.
@@ -38,7 +43,7 @@
else
return -1;
}
-
+
/**
* Return the offset of the selection edge or cursor, or -1 if
* there is no selection or cursor.
@@ -57,7 +62,7 @@
// private static int pin(int value, int min, int max) {
// return value < min ? 0 : (value > max ? max : value);
// }
-
+
/**
* Set the selection anchor to <code>start</code> and the selection edge
* to <code>stop</code>.
@@ -69,7 +74,7 @@
int ostart = getSelectionStart(text);
int oend = getSelectionEnd(text);
-
+
if (ostart != start || oend != stop) {
text.setSpan(SELECTION_START, start, start,
Spanned.SPAN_POINT_POINT|Spanned.SPAN_INTERMEDIATE);
@@ -357,6 +362,42 @@
return true;
}
+ /** {@hide} */
+ public static interface PositionIterator {
+ public static final int DONE = BreakIterator.DONE;
+
+ public int preceding(int position);
+ public int following(int position);
+ }
+
+ /** {@hide} */
+ public static boolean moveToPreceding(
+ Spannable text, PositionIterator iter, boolean extendSelection) {
+ final int offset = iter.preceding(getSelectionEnd(text));
+ if (offset != PositionIterator.DONE) {
+ if (extendSelection) {
+ extendSelection(text, offset);
+ } else {
+ setSelection(text, offset);
+ }
+ }
+ return true;
+ }
+
+ /** {@hide} */
+ public static boolean moveToFollowing(
+ Spannable text, PositionIterator iter, boolean extendSelection) {
+ final int offset = iter.following(getSelectionEnd(text));
+ if (offset != PositionIterator.DONE) {
+ if (extendSelection) {
+ extendSelection(text, offset);
+ } else {
+ setSelection(text, offset);
+ }
+ }
+ return true;
+ }
+
private static int findEdge(Spannable text, Layout layout, int dir) {
int pt = getSelectionEnd(text);
int line = layout.getLineForOffset(pt);
@@ -419,7 +460,7 @@
private static final class START implements NoCopySpan { }
private static final class END implements NoCopySpan { }
-
+
/*
* Public constants
*/
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index a61ff13..80c0106 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -17,14 +17,23 @@
package android.text.method;
import android.graphics.Rect;
+import android.text.CharSequenceIterator;
+import android.text.Editable;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
+import android.text.Spanned;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.util.MathUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
+import java.text.BreakIterator;
+import java.text.CharacterIterator;
+
/**
* A movement method that provides cursor movement and selection.
* Supports displaying the context menu on DPad Center.
@@ -193,6 +202,20 @@
}
}
+ /** {@hide} */
+ @Override
+ protected boolean leftWord(TextView widget, Spannable buffer) {
+ mWordIterator.setCharSequence(buffer);
+ return Selection.moveToPreceding(buffer, mWordIterator, isSelecting(buffer));
+ }
+
+ /** {@hide} */
+ @Override
+ protected boolean rightWord(TextView widget, Spannable buffer) {
+ mWordIterator.setCharSequence(buffer);
+ return Selection.moveToFollowing(buffer, mWordIterator, isSelecting(buffer));
+ }
+
@Override
protected boolean home(TextView widget, Spannable buffer) {
return lineStart(widget, buffer);
@@ -205,7 +228,8 @@
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
- int initialScrollX = -1, initialScrollY = -1;
+ int initialScrollX = -1;
+ int initialScrollY = -1;
final int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
@@ -220,7 +244,7 @@
boolean cap = isSelecting(buffer);
if (cap) {
int offset = widget.getOffset((int) event.getX(), (int) event.getY());
-
+
buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
// Disallow intercepting of the touch events, so that
@@ -308,6 +332,103 @@
return sInstance;
}
+ /**
+ * Walks through cursor positions at word boundaries. Internally uses
+ * {@link BreakIterator#getWordInstance()}, and caches {@link CharSequence}
+ * for performance reasons.
+ */
+ private static class WordIterator implements Selection.PositionIterator {
+ private CharSequence mCurrent;
+ private boolean mCurrentDirty = false;
+
+ private BreakIterator mIterator;
+
+ private TextWatcher mWatcher = new TextWatcher() {
+ /** {@inheritDoc} */
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ mCurrentDirty = true;
+ }
+
+ /** {@inheritDoc} */
+ public void afterTextChanged(Editable s) {
+ // ignored
+ }
+ };
+
+ public void setCharSequence(CharSequence incoming) {
+ if (mIterator == null) {
+ mIterator = BreakIterator.getWordInstance();
+ }
+
+ // when incoming is different object, move listeners to new sequence
+ // and mark as dirty so we reload contents.
+ if (mCurrent != incoming) {
+ if (mCurrent instanceof Editable) {
+ ((Editable) mCurrent).removeSpan(mWatcher);
+ }
+
+ if (incoming instanceof Editable) {
+ ((Editable) incoming).setSpan(
+ mWatcher, 0, incoming.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ mCurrent = incoming;
+ mCurrentDirty = true;
+ }
+
+ if (mCurrentDirty) {
+ final CharacterIterator charIterator = new CharSequenceIterator(mCurrent);
+ mIterator.setText(charIterator);
+
+ mCurrentDirty = false;
+ }
+ }
+
+ private boolean isValidOffset(int offset) {
+ return offset >= 0 && offset < mCurrent.length();
+ }
+
+ private boolean isLetterOrDigit(int offset) {
+ if (isValidOffset(offset)) {
+ return Character.isLetterOrDigit(mCurrent.charAt(offset));
+ } else {
+ return false;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public int preceding(int offset) {
+ // always round cursor index into valid string index
+ offset = MathUtils.constrain(offset, 0, mCurrent.length() - 1);
+
+ do {
+ offset = mIterator.preceding(offset);
+ if (isLetterOrDigit(offset)) break;
+ } while (isValidOffset(offset));
+
+ return offset;
+ }
+
+ /** {@inheritDoc} */
+ public int following(int offset) {
+ // always round cursor index into valid string index
+ offset = MathUtils.constrain(offset, 0, mCurrent.length() - 1);
+
+ do {
+ offset = mIterator.following(offset);
+ if (isLetterOrDigit(offset - 1)) break;
+ } while (isValidOffset(offset));
+
+ return offset;
+ }
+ }
+
+ private WordIterator mWordIterator = new WordIterator();
private static final Object LAST_TAP_DOWN = new Object();
private static ArrowKeyMovementMethod sInstance;
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 94c6ed0..f554b90 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -164,6 +164,9 @@
if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
return left(widget, buffer);
} else if (KeyEvent.metaStateHasModifiers(movementMetaState,
+ KeyEvent.META_CTRL_ON)) {
+ return leftWord(widget, buffer);
+ } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
KeyEvent.META_ALT_ON)) {
return lineStart(widget, buffer);
}
@@ -173,6 +176,9 @@
if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
return right(widget, buffer);
} else if (KeyEvent.metaStateHasModifiers(movementMetaState,
+ KeyEvent.META_CTRL_ON)) {
+ return rightWord(widget, buffer);
+ } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
KeyEvent.META_ALT_ON)) {
return lineEnd(widget, buffer);
}
@@ -217,12 +223,18 @@
case KeyEvent.KEYCODE_MOVE_HOME:
if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
return home(widget, buffer);
+ } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
+ KeyEvent.META_CTRL_ON)) {
+ return top(widget, buffer);
}
break;
case KeyEvent.KEYCODE_MOVE_END:
if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
return end(widget, buffer);
+ } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
+ KeyEvent.META_CTRL_ON)) {
+ return bottom(widget, buffer);
}
break;
}
@@ -349,6 +361,16 @@
return false;
}
+ /** {@hide} */
+ protected boolean leftWord(TextView widget, Spannable buffer) {
+ return false;
+ }
+
+ /** {@hide} */
+ protected boolean rightWord(TextView widget, Spannable buffer) {
+ return false;
+ }
+
/**
* Performs a home movement action.
* Moves the cursor or scrolls to the start of the line or to the top of the
diff --git a/core/java/android/text/style/CorrectionSpan.java b/core/java/android/text/style/CorrectionSpan.java
index 6142e6f..43fb85d 100644
--- a/core/java/android/text/style/CorrectionSpan.java
+++ b/core/java/android/text/style/CorrectionSpan.java
@@ -22,23 +22,21 @@
import android.text.ParcelableSpan;
import android.text.TextUtils;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
import java.util.Locale;
+/**
+ * Sets correction candidates of words under this span.
+ */
public class CorrectionSpan implements ParcelableSpan {
/**
- * Flag for the default value.
- */
- public static final int FLAG_DEFAULT = 0x0000;
- /**
* Flag for indicating that the input is verbatim. TextView refers to this flag to determine
* how it displays a word with CorrectionSpan.
*/
public static final int FLAG_VERBATIM = 0x0001;
- private static final int SUGGESTS_MAX_SIZE = 5;
+ private static final int SUGGESTIONS_MAX_SIZE = 5;
/*
* TODO: Needs to check the validity and add a feature that TextView will change
@@ -48,7 +46,7 @@
*/
private final int mFlags;
- private final List<CharSequence> mSuggests = new ArrayList<CharSequence>();
+ private final String[] mSuggestions;
private final String mLocaleString;
private final String mOriginalString;
/*
@@ -58,35 +56,33 @@
/**
* @param context Context for the application
- * @param suggests Suggests for the string under the span
+ * @param suggestions Suggestions for the string under the span
* @param flags Additional flags indicating how this span is handled in TextView
*/
- public CorrectionSpan(Context context, List<CharSequence> suggests, int flags) {
- this(context, null, suggests, flags, null);
+ public CorrectionSpan(Context context, String[] suggestions, int flags) {
+ this(context, null, suggestions, flags, null);
}
/**
* @param locale Locale of the suggestions
- * @param suggests Suggests for the string under the span
+ * @param suggestions Suggestions for the string under the span
* @param flags Additional flags indicating how this span is handled in TextView
*/
- public CorrectionSpan(Locale locale, List<CharSequence> suggests, int flags) {
- this(null, locale, suggests, flags, null);
+ public CorrectionSpan(Locale locale, String[] suggestions, int flags) {
+ this(null, locale, suggestions, flags, null);
}
/**
* @param context Context for the application
* @param locale locale Locale of the suggestions
- * @param suggests suggests Suggests for the string under the span
+ * @param suggestions Suggestions for the string under the span
* @param flags Additional flags indicating how this span is handled in TextView
- * @param originalString originalString for suggests
+ * @param originalString originalString for suggestions
*/
- public CorrectionSpan(Context context, Locale locale, List<CharSequence> suggests, int flags,
+ public CorrectionSpan(Context context, Locale locale, String[] suggestions, int flags,
String originalString) {
- final int N = Math.min(SUGGESTS_MAX_SIZE, suggests.size());
- for (int i = 0; i < N; ++i) {
- mSuggests.add(suggests.get(i));
- }
+ final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length);
+ mSuggestions = Arrays.copyOf(suggestions, N);
mFlags = flags;
if (context != null && locale == null) {
mLocaleString = context.getResources().getConfiguration().locale.toString();
@@ -97,7 +93,7 @@
}
public CorrectionSpan(Parcel src) {
- src.readList(mSuggests, null);
+ mSuggestions = src.readStringArray();
mFlags = src.readInt();
mLocaleString = src.readString();
mOriginalString = src.readString();
@@ -106,8 +102,8 @@
/**
* @return suggestions
*/
- public List<CharSequence> getSuggests() {
- return new ArrayList<CharSequence>(mSuggests);
+ public String[] getSuggestions() {
+ return Arrays.copyOf(mSuggestions, mSuggestions.length);
}
/**
@@ -135,7 +131,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeList(mSuggests);
+ dest.writeStringArray(mSuggestions);
dest.writeInt(mFlags);
dest.writeString(mLocaleString);
dest.writeString(mOriginalString);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 8621de3..b8c5c2a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -983,6 +983,13 @@
if (b.getConfig() == Bitmap.Config.ALPHA_8) {
return setupModifiers(paint);
}
+
+ final ColorFilter filter = paint.getColorFilter();
+ if (filter != null) {
+ nSetupColorFilter(mRenderer, filter.nativeColorFilter);
+ return MODIFIER_COLOR_FILTER;
+ }
+
return MODIFIER_NONE;
}
@@ -1016,7 +1023,7 @@
nSetupColorFilter(mRenderer, filter.nativeColorFilter);
return MODIFIER_COLOR_FILTER;
}
- return MODIFIER_NONE;
+ return MODIFIER_NONE;
}
private static native void nSetupShader(int renderer, int shader);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 8584bf2..28541fe 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -20,7 +20,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
-import android.os.SystemClock;
+import android.os.*;
import android.util.EventLog;
import android.util.Log;
@@ -256,6 +256,7 @@
@SuppressWarnings({"deprecation"})
static abstract class GlRenderer extends HardwareRenderer {
+ // These values are not exposed in our EGL APIs
private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
private static final int EGL_SURFACE_TYPE = 0x3033;
private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
@@ -290,7 +291,7 @@
GlRenderer(int glVersion, boolean translucent) {
mGlVersion = glVersion;
mTranslucent = translucent;
- final String dirtyProperty = System.getProperty(RENDER_DIRTY_REGIONS_PROPERTY, "true");
+ final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
//noinspection PointlessBooleanExpression,ConstantConditions
mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a17db5d..3c34479 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -172,6 +172,8 @@
* recent point, as well as any intermediate points since the last
* hover move event.
* <p>
+ * This action is always delivered to the window or view under the pointer.
+ * </p><p>
* This action is not a touch event so it is delivered to
* {@link View#onGenericMotionEvent(MotionEvent)} rather than
* {@link View#onTouchEvent(MotionEvent)}.
@@ -184,8 +186,9 @@
* vertical and/or horizontal scroll offsets. Use {@link #getAxisValue(int)}
* to retrieve the information from {@link #AXIS_VSCROLL} and {@link #AXIS_HSCROLL}.
* The pointer may or may not be down when this event is dispatched.
- * This action is always delivered to the winder under the pointer, which
- * may not be the window currently touched.
+ * <p></p>
+ * This action is always delivered to the window or view under the pointer, which
+ * may not be the window or view currently touched.
* <p>
* This action is not a touch event so it is delivered to
* {@link View#onGenericMotionEvent(MotionEvent)} rather than
@@ -195,6 +198,32 @@
public static final int ACTION_SCROLL = 8;
/**
+ * Constant for {@link #getAction}: The pointer is not down but has entered the
+ * boundaries of a window or view.
+ * <p>
+ * This action is always delivered to the window or view under the pointer.
+ * </p><p>
+ * This action is not a touch event so it is delivered to
+ * {@link View#onGenericMotionEvent(MotionEvent)} rather than
+ * {@link View#onTouchEvent(MotionEvent)}.
+ * </p>
+ */
+ public static final int ACTION_HOVER_ENTER = 9;
+
+ /**
+ * Constant for {@link #getAction}: The pointer is not down but has exited the
+ * boundaries of a window or view.
+ * <p>
+ * This action is always delivered to the window or view that was previously under the pointer.
+ * </p><p>
+ * This action is not a touch event so it is delivered to
+ * {@link View#onGenericMotionEvent(MotionEvent)} rather than
+ * {@link View#onTouchEvent(MotionEvent)}.
+ * </p>
+ */
+ public static final int ACTION_HOVER_EXIT = 10;
+
+ /**
* Bits in the action code that represent a pointer index, used with
* {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting
* down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer
@@ -1354,9 +1383,9 @@
/**
* Returns true if this motion event is a touch event.
* <p>
- * Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE}
- * or {@link #ACTION_SCROLL} because they are not actually touch events
- * (the pointer is not down).
+ * Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE},
+ * {@link #ACTION_HOVER_ENTER}, {@link #ACTION_HOVER_EXIT}, or {@link #ACTION_SCROLL}
+ * because they are not actually touch events (the pointer is not down).
* </p>
* @return True if this motion event is a touch event.
* @hide
@@ -2313,6 +2342,10 @@
return "ACTION_HOVER_MOVE";
case ACTION_SCROLL:
return "ACTION_SCROLL";
+ case ACTION_HOVER_ENTER:
+ return "ACTION_HOVER_ENTER";
+ case ACTION_HOVER_EXIT:
+ return "ACTION_HOVER_EXIT";
}
int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
switch (action & ACTION_MASK) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c729ccd..96cddfa 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1304,6 +1304,7 @@
static final int VIEW_STATE_PRESSED = 1 << 4;
static final int VIEW_STATE_ACTIVATED = 1 << 5;
static final int VIEW_STATE_ACCELERATED = 1 << 6;
+ static final int VIEW_STATE_HOVERED = 1 << 7;
static final int[] VIEW_STATE_IDS = new int[] {
R.attr.state_window_focused, VIEW_STATE_WINDOW_FOCUSED,
@@ -1313,6 +1314,7 @@
R.attr.state_pressed, VIEW_STATE_PRESSED,
R.attr.state_activated, VIEW_STATE_ACTIVATED,
R.attr.state_accelerated, VIEW_STATE_ACCELERATED,
+ R.attr.state_hovered, VIEW_STATE_HOVERED,
};
static {
@@ -1623,6 +1625,12 @@
private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
/**
+ * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT.
+ * @hide
+ */
+ private static final int HOVERED = 0x10000000;
+
+ /**
* Indicates that pivotX or pivotY were explicitly set and we should not assume the center
* for transform operations
*
@@ -4643,23 +4651,81 @@
* <p>
* Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
* are delivered to the view under the pointer. All other generic motion events are
- * delivered to the focused view.
+ * delivered to the focused view. Hover events are handled specially and are delivered
+ * to {@link #onHoverEvent}.
* </p>
*
* @param event The motion event to be dispatched.
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ final int source = event.getSource();
+ if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ final int action = event.getAction();
+ if (action == MotionEvent.ACTION_HOVER_ENTER
+ || action == MotionEvent.ACTION_HOVER_MOVE
+ || action == MotionEvent.ACTION_HOVER_EXIT) {
+ if (dispatchHoverEvent(event)) {
+ return true;
+ }
+ } else if (dispatchGenericPointerEvent(event)) {
+ return true;
+ }
+ } else if (dispatchGenericFocusedEvent(event)) {
+ return true;
+ }
+
//noinspection SimplifiableIfStatement
if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& mOnGenericMotionListener.onGenericMotion(this, event)) {
return true;
}
-
return onGenericMotionEvent(event);
}
/**
+ * Dispatch a hover event.
+ * <p>
+ * Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
+ * </p>
+ *
+ * @param event The motion event to be dispatched.
+ * @return True if the event was handled by the view, false otherwise.
+ * @hide
+ */
+ protected boolean dispatchHoverEvent(MotionEvent event) {
+ return onHoverEvent(event);
+ }
+
+ /**
+ * Dispatch a generic motion event to the view under the first pointer.
+ * <p>
+ * Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
+ * </p>
+ *
+ * @param event The motion event to be dispatched.
+ * @return True if the event was handled by the view, false otherwise.
+ * @hide
+ */
+ protected boolean dispatchGenericPointerEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Dispatch a generic motion event to the currently focused view.
+ * <p>
+ * Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
+ * </p>
+ *
+ * @param event The motion event to be dispatched.
+ * @return True if the event was handled by the view, false otherwise.
+ * @hide
+ */
+ protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
* Dispatch a pointer event.
* <p>
* Dispatches touch related pointer events to {@link #onTouchEvent} and all
@@ -5223,15 +5289,92 @@
* </code>
*
* @param event The generic motion event being processed.
- *
- * @return Return true if you have consumed the event, false if you haven't.
- * The default implementation always returns false.
+ * @return True if the event was handled, false otherwise.
*/
public boolean onGenericMotionEvent(MotionEvent event) {
return false;
}
/**
+ * Implement this method to handle hover events.
+ * <p>
+ * Hover events are pointer events with action {@link MotionEvent#ACTION_HOVER_ENTER},
+ * {@link MotionEvent#ACTION_HOVER_MOVE}, or {@link MotionEvent#ACTION_HOVER_EXIT}.
+ * </p><p>
+ * The view receives hover enter as the pointer enters the bounds of the view and hover
+ * exit as the pointer exits the bound of the view or just before the pointer goes down
+ * (which implies that {@link #onTouchEvent} will be called soon).
+ * </p><p>
+ * If the view would like to handle the hover event itself and prevent its children
+ * from receiving hover, it should return true from this method. If this method returns
+ * true and a child has already received a hover enter event, the child will
+ * automatically receive a hover exit event.
+ * </p><p>
+ * The default implementation sets the hovered state of the view if the view is
+ * clickable.
+ * </p>
+ *
+ * @param event The motion event that describes the hover.
+ * @return True if this view handled the hover event and does not want its children
+ * to receive the hover event.
+ */
+ public boolean onHoverEvent(MotionEvent event) {
+ final int viewFlags = mViewFlags;
+
+ if (((viewFlags & CLICKABLE) != CLICKABLE &&
+ (viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) {
+ // Nothing to do if the view is not clickable.
+ return false;
+ }
+
+ if ((viewFlags & ENABLED_MASK) == DISABLED) {
+ // A disabled view that is clickable still consumes the hover events, it just doesn't
+ // respond to them.
+ return true;
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ setHovered(true);
+ break;
+
+ case MotionEvent.ACTION_HOVER_EXIT:
+ setHovered(false);
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the view is currently hovered.
+ *
+ * @return True if the view is currently hovered.
+ */
+ public boolean isHovered() {
+ return (mPrivateFlags & HOVERED) != 0;
+ }
+
+ /**
+ * Sets whether the view is currently hovered.
+ *
+ * @param hovered True if the view is hovered.
+ */
+ public void setHovered(boolean hovered) {
+ if (hovered) {
+ if ((mPrivateFlags & HOVERED) == 0) {
+ mPrivateFlags |= HOVERED;
+ refreshDrawableState();
+ }
+ } else {
+ if ((mPrivateFlags & HOVERED) != 0) {
+ mPrivateFlags &= ~HOVERED;
+ refreshDrawableState();
+ }
+ }
+ }
+
+ /**
* Implement this method to handle touch screen motion events.
*
* @param event The motion event.
@@ -7216,8 +7359,16 @@
mPrivateFlags &= ~DRAWN;
mPrivateFlags |= INVALIDATED;
mPrivateFlags &= ~DRAWING_CACHE_VALID;
- if (mParent != null && mAttachInfo != null && mAttachInfo.mHardwareAccelerated) {
- mParent.invalidateChild(this, null);
+ if (mParent != null && mAttachInfo != null) {
+ if (mAttachInfo.mHardwareAccelerated) {
+ mParent.invalidateChild(this, null);
+ } else {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ r.set(0, 0, mRight - mLeft, mBottom - mTop);
+ // Don't call invalidate -- we don't want to internally scroll
+ // our own bounds
+ mParent.invalidateChild(this, r);
+ }
}
}
}
@@ -7323,8 +7474,9 @@
*/
public boolean post(Runnable action) {
Handler handler;
- if (mAttachInfo != null) {
- handler = mAttachInfo.mHandler;
+ AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo != null) {
+ handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
ViewRoot.getRunQueue().post(action);
@@ -7352,8 +7504,9 @@
*/
public boolean postDelayed(Runnable action, long delayMillis) {
Handler handler;
- if (mAttachInfo != null) {
- handler = mAttachInfo.mHandler;
+ AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo != null) {
+ handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
ViewRoot.getRunQueue().postDelayed(action, delayMillis);
@@ -7375,8 +7528,9 @@
*/
public boolean removeCallbacks(Runnable action) {
Handler handler;
- if (mAttachInfo != null) {
- handler = mAttachInfo.mHandler;
+ AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo != null) {
+ handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
ViewRoot.getRunQueue().removeCallbacks(action);
@@ -7423,11 +7577,12 @@
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
- if (mAttachInfo != null) {
+ AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo != null) {
Message msg = Message.obtain();
msg.what = AttachInfo.INVALIDATE_MSG;
msg.obj = this;
- mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+ attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
}
}
@@ -7447,7 +7602,8 @@
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
- if (mAttachInfo != null) {
+ AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo != null) {
final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire();
info.target = this;
info.left = left;
@@ -7458,7 +7614,7 @@
final Message msg = Message.obtain();
msg.what = AttachInfo.INVALIDATE_RECT_MSG;
msg.obj = info;
- mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+ attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
}
}
@@ -9877,6 +10033,7 @@
// windows to better match their app.
viewStateIndex |= VIEW_STATE_ACCELERATED;
}
+ if ((privateFlags & HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED;
drawableState = VIEW_STATE_SETS[viewStateIndex];
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8dc86ac..058b826 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -147,6 +147,9 @@
@ViewDebug.ExportedProperty(category = "events")
private float mLastTouchDownY;
+ // Child which last received ACTION_HOVER_ENTER and ACTION_HOVER_MOVE.
+ private View mHoveredChild;
+
/**
* Internal flags.
*
@@ -1140,13 +1143,50 @@
return false;
}
- /**
- * {@inheritDoc}
- */
+ /** @hide */
@Override
- public boolean dispatchGenericMotionEvent(MotionEvent event) {
- if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- // Send the event to the child under the pointer.
+ protected boolean dispatchHoverEvent(MotionEvent event) {
+ // Send the hover enter or hover move event to the view group first.
+ // If it handles the event then a hovered child should receive hover exit.
+ boolean handled = false;
+ final boolean interceptHover;
+ final int action = event.getAction();
+ if (action == MotionEvent.ACTION_HOVER_EXIT) {
+ interceptHover = true;
+ } else {
+ handled = super.dispatchHoverEvent(event);
+ interceptHover = handled;
+ }
+
+ // Send successive hover events to the hovered child as long as the pointer
+ // remains within the child's bounds.
+ MotionEvent eventNoHistory = event;
+ if (mHoveredChild != null) {
+ final float x = event.getX();
+ final float y = event.getY();
+
+ if (interceptHover
+ || !isTransformedTouchPointInView(x, y, mHoveredChild, null)) {
+ // Pointer exited the child.
+ // Send it a hover exit with only the most recent coordinates. We could
+ // try to find the exact point in history when the pointer left the view
+ // but it is not worth the effort.
+ eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
+ eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
+ handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild);
+ eventNoHistory.setAction(action);
+
+ mHoveredChild = null;
+ } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
+ // Pointer is still within the child.
+ handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild);
+ }
+ }
+
+ // Find a new hovered child if needed.
+ if (!interceptHover && mHoveredChild == null
+ && (action == MotionEvent.ACTION_HOVER_ENTER
+ || action == MotionEvent.ACTION_HOVER_MOVE)) {
final int childrenCount = mChildrenCount;
if (childrenCount != 0) {
final View[] children = mChildren;
@@ -1155,45 +1195,88 @@
for (int i = childrenCount - 1; i >= 0; i--) {
final View child = children[i];
- if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
- && child.getAnimation() == null) {
- // Skip invisible child unless it is animating.
+ if (!canViewReceivePointerEvents(child)
+ || !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
- if (!isTransformedTouchPointInView(x, y, child, null)) {
- // Scroll point is out of child's bounds.
- continue;
- }
+ // Found the hovered child.
+ mHoveredChild = child;
+ if (action == MotionEvent.ACTION_HOVER_MOVE) {
+ // Pointer was moving within the view group and entered the child.
+ // Send it a hover enter and hover move with only the most recent
+ // coordinates. We could try to find the exact point in history when
+ // the pointer entered the view but it is not worth the effort.
+ eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
+ eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
+ handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child);
+ eventNoHistory.setAction(action);
- final float offsetX = mScrollX - child.mLeft;
- final float offsetY = mScrollY - child.mTop;
- final boolean handled;
- if (!child.hasIdentityMatrix()) {
- MotionEvent transformedEvent = MotionEvent.obtain(event);
- transformedEvent.offsetLocation(offsetX, offsetY);
- transformedEvent.transform(child.getInverseMatrix());
- handled = child.dispatchGenericMotionEvent(transformedEvent);
- transformedEvent.recycle();
- } else {
- event.offsetLocation(offsetX, offsetY);
- handled = child.dispatchGenericMotionEvent(event);
- event.offsetLocation(-offsetX, -offsetY);
+ handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child);
+ } else { /* must be ACTION_HOVER_ENTER */
+ // Pointer entered the child.
+ handled |= dispatchTransformedGenericPointerEvent(event, child);
}
-
- if (handled) {
- return true;
- }
+ break;
}
}
-
- // No child handled the event. Send it to this view group.
- return super.dispatchGenericMotionEvent(event);
}
+ // Recycle the copy of the event that we made.
+ if (eventNoHistory != event) {
+ eventNoHistory.recycle();
+ }
+
+ // Send hover exit to the view group. If there was a child, we will already have
+ // sent the hover exit to it.
+ if (action == MotionEvent.ACTION_HOVER_EXIT) {
+ handled |= super.dispatchHoverEvent(event);
+ }
+
+ // Done.
+ return handled;
+ }
+
+ private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
+ if (event.getHistorySize() == 0) {
+ return event;
+ }
+ return MotionEvent.obtainNoHistory(event);
+ }
+
+ /** @hide */
+ @Override
+ protected boolean dispatchGenericPointerEvent(MotionEvent event) {
+ // Send the event to the child under the pointer.
+ final int childrenCount = mChildrenCount;
+ if (childrenCount != 0) {
+ final View[] children = mChildren;
+ final float x = event.getX();
+ final float y = event.getY();
+
+ for (int i = childrenCount - 1; i >= 0; i--) {
+ final View child = children[i];
+ if (!canViewReceivePointerEvents(child)
+ || !isTransformedTouchPointInView(x, y, child, null)) {
+ continue;
+ }
+
+ if (dispatchTransformedGenericPointerEvent(event, child)) {
+ return true;
+ }
+ }
+ }
+
+ // No child handled the event. Send it to this view group.
+ return super.dispatchGenericPointerEvent(event);
+ }
+
+ /** @hide */
+ @Override
+ protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
// Send the event to the focused child or to this view group if it has focus.
if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
- return super.dispatchGenericMotionEvent(event);
+ return super.dispatchGenericFocusedEvent(event);
} else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
return mFocused.dispatchGenericMotionEvent(event);
}
@@ -1201,6 +1284,33 @@
}
/**
+ * Dispatches a generic pointer event to a child, taking into account
+ * transformations that apply to the child.
+ *
+ * @param event The event to send.
+ * @param child The view to send the event to.
+ * @return {@code true} if the child handled the event.
+ */
+ private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
+ final float offsetX = mScrollX - child.mLeft;
+ final float offsetY = mScrollY - child.mTop;
+
+ boolean handled;
+ if (!child.hasIdentityMatrix()) {
+ MotionEvent transformedEvent = MotionEvent.obtain(event);
+ transformedEvent.offsetLocation(offsetX, offsetY);
+ transformedEvent.transform(child.getInverseMatrix());
+ handled = child.dispatchGenericMotionEvent(transformedEvent);
+ transformedEvent.recycle();
+ } else {
+ event.offsetLocation(offsetX, offsetY);
+ handled = child.dispatchGenericMotionEvent(event);
+ event.offsetLocation(-offsetX, -offsetY);
+ }
+ return handled;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -1213,8 +1323,7 @@
final int actionMasked = action & MotionEvent.ACTION_MASK;
// Handle an initial down.
- if (actionMasked == MotionEvent.ACTION_DOWN
- || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
+ if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
@@ -1268,14 +1377,8 @@
for (int i = childrenCount - 1; i >= 0; i--) {
final View child = children[i];
- if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
- && child.getAnimation() == null) {
- // Skip invisible child unless it is animating.
- continue;
- }
-
- if (!isTransformedTouchPointInView(x, y, child, null)) {
- // New pointer is out of child's bounds.
+ if (!canViewReceivePointerEvents(child)
+ || !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
@@ -1476,6 +1579,15 @@
}
/**
+ * Returns true if a child view can receive pointer events.
+ * @hide
+ */
+ private static boolean canViewReceivePointerEvents(View child) {
+ return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
+ || child.getAnimation() != null;
+ }
+
+ /**
* Returns true if a child view contains the specified point when transformed
* into its coordinate space.
* Child must not be null.
@@ -1975,7 +2087,7 @@
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
- if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
+ if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
mGroupFlags |= FLAG_PADDING_NOT_NULL;
} else {
mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
@@ -3244,6 +3356,10 @@
mTransition.removeChild(this, view);
}
+ if (view == mHoveredChild) {
+ mHoveredChild = null;
+ }
+
boolean clearChildFocus = false;
if (view == mFocused) {
view.clearFocusForRemoval();
@@ -3307,6 +3423,7 @@
final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
final boolean notifyListener = onHierarchyChangeListener != null;
final View focused = mFocused;
+ final View hoveredChild = mHoveredChild;
final boolean detach = mAttachInfo != null;
View clearChildFocus = null;
@@ -3320,6 +3437,10 @@
mTransition.removeChild(this, view);
}
+ if (view == hoveredChild) {
+ mHoveredChild = null;
+ }
+
if (view == focused) {
view.clearFocusForRemoval();
clearChildFocus = view;
@@ -3377,6 +3498,7 @@
final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
final boolean notify = listener != null;
final View focused = mFocused;
+ final View hoveredChild = mHoveredChild;
final boolean detach = mAttachInfo != null;
View clearChildFocus = null;
@@ -3389,6 +3511,10 @@
mTransition.removeChild(this, view);
}
+ if (view == hoveredChild) {
+ mHoveredChild = null;
+ }
+
if (view == focused) {
view.clearFocusForRemoval();
clearChildFocus = view;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index c86c9a5..3c386b4 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -502,6 +502,11 @@
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
if (hardwareAccelerated) {
+ if (!HardwareRenderer.isAvailable()) {
+ mAttachInfo.mHardwareAccelerationRequested = true;
+ return;
+ }
+
// Only enable hardware acceleration if we are not in the system process
// The window manager creates ViewRoots to display animated preview windows
// of launching apps and we don't want those to be hardware accelerated
@@ -524,8 +529,6 @@
mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
= mAttachInfo.mHardwareRenderer != null;
- } else if (HardwareRenderer.isAvailable()) {
- mAttachInfo.mHardwareAccelerationRequested = true;
}
}
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index b95e7c9..dd2d00d 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -20,7 +20,6 @@
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.SystemClock;
import android.text.Editable;
import android.text.NoCopySpan;
@@ -30,7 +29,6 @@
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.MetaKeyKeyListener;
-import android.text.style.CorrectionSpan;
import android.util.Log;
import android.util.LogPrinter;
import android.view.KeyCharacterMap;
@@ -192,15 +190,6 @@
}
/**
- * Default implementation does nothing and returns false.
- */
- @Override
- public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
- int end, int flags) {
- return false;
- }
-
- /**
* The default implementation performs the deletion around the current
* selection position of the editable text.
*/
@@ -655,7 +644,7 @@
lp.println("Composing text:");
TextUtils.dumpSpans(text, lp, " ");
}
-
+
// Position the cursor appropriately, so that after replacing the
// desired range of text it will be located in the correct spot.
// This allows us to deal with filters performing edits on the text
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index a8a5346..ea9e402 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -17,8 +17,6 @@
package android.view.inputmethod;
import android.os.Bundle;
-import android.os.IBinder;
-import android.text.style.CorrectionSpan;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -355,10 +353,4 @@
* valid.
*/
public boolean performPrivateCommand(String action, Bundle data);
-
- /**
- * Add a correction span.
- */
- public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
- int end, int flags);
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index fee88d97..690ea85 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -17,8 +17,6 @@
package android.view.inputmethod;
import android.os.Bundle;
-import android.os.IBinder;
-import android.text.style.CorrectionSpan;
import android.view.KeyEvent;
/**
@@ -60,8 +58,7 @@
return mTarget.getCursorCapsMode(reqModes);
}
- public ExtractedText getExtractedText(ExtractedTextRequest request,
- int flags) {
+ public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
return mTarget.getExtractedText(request, flags);
}
@@ -128,9 +125,4 @@
public boolean performPrivateCommand(String action, Bundle data) {
return mTarget.performPrivateCommand(action, data);
}
-
- public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
- int end, int flags) {
- return mTarget.setCorrectionSpan(token, correctionSpan, start, end, flags);
- }
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 32eec9f..1f7441d 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -322,7 +322,12 @@
InputMethodInfo obj = (InputMethodInfo) o;
return mId.equals(obj.mId);
}
-
+
+ @Override
+ public int hashCode() {
+ return mId.hashCode();
+ }
+
/**
* Used to package this object into a {@link Parcel}.
*
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 0510f8b..9636513 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -153,7 +153,7 @@
// So in full screen, we reset the MediaPlayer
mPlayer.reset();
setMediaController(new MediaController(mProxy.getContext()));
-
+ mPlayer.setScreenOnWhilePlaying(true);
prepareDataAndDisplayMode(mProxy);
}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 094566f..acd7eab 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -109,7 +109,7 @@
boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
layer, currentVideoLayerId, textureName,
playerState);
- if (playerState == HTML5VideoView.STATE_PREPARED
+ if (playerState >= HTML5VideoView.STATE_PREPARED
&& !foundInTree) {
mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
mHTML5VideoView.deleteSurfaceTexture();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 056650c..e7f8796 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6041,7 +6041,6 @@
if (shouldForwardTouchEvent()) {
if (removeEvents) {
mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
- mTouchEventQueue.ignoreCurrentlyMissingEvents();
}
TouchEventData ted = new TouchEventData();
ted.mIds = new int[1];
@@ -6058,6 +6057,12 @@
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mPreventDefault = PREVENT_DEFAULT_IGNORE;
+
+ if (removeEvents) {
+ // Mark this after sending the message above; we should
+ // be willing to ignore the cancel event that we just sent.
+ mTouchEventQueue.ignoreCurrentlyMissingEvents();
+ }
}
}
@@ -7251,17 +7256,18 @@
* been queued will also be processed in their proper order.
*
* @param ted Touch data to be processed in order.
+ * @return true if the event was processed before returning, false if it was just enqueued.
*/
- public void enqueueTouchEvent(TouchEventData ted) {
+ public boolean enqueueTouchEvent(TouchEventData ted) {
if (ted.mSequence < mLastHandledTouchSequence) {
// Stale event and we already moved on; drop it. (Should not be common.)
Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) +
" received from webcore; ignoring");
- return;
+ return false;
}
if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) {
- return;
+ return false;
}
if (mLastHandledTouchSequence + 1 == ted.mSequence) {
@@ -7283,6 +7289,7 @@
QueuedTouch qd = obtainQueuedTouch().set(ted);
mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
}
+ return true;
}
/**
@@ -7839,11 +7846,11 @@
}
TouchEventData ted = (TouchEventData) msg.obj;
- // WebCore is responding to us; remove pending timeout.
- // It will be re-posted when needed.
- removeMessages(PREVENT_DEFAULT_TIMEOUT);
-
- mTouchEventQueue.enqueueTouchEvent(ted);
+ if (mTouchEventQueue.enqueueTouchEvent(ted)) {
+ // WebCore is responding to us; remove pending timeout.
+ // It will be re-posted when needed.
+ removeMessages(PREVENT_DEFAULT_TIMEOUT);
+ }
break;
case REQUEST_KEYBOARD:
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 1c0a2bb..365133b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -29,6 +29,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -156,13 +157,16 @@
// create in response to this bind
factory.onDataSetChanged();
}
- } catch (Exception e) {
+ } catch (RemoteException e) {
Log.e(TAG, "Error notifying factory of data set changed in " +
"onServiceConnected(): " + e.getMessage());
// Return early to prevent anything further from being notified
// (effectively nothing has changed)
return;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error notifying factory of data set changed in " +
+ "onServiceConnected(): " + e.getMessage());
}
// Request meta data so that we have up to date data when calling back to
@@ -777,7 +781,7 @@
tmpMetaData.count = count;
tmpMetaData.setLoadingViewTemplates(loadingView, firstView);
}
- } catch (Exception e) {
+ } catch(RemoteException e) {
processException("updateMetaData", e);
}
}
@@ -792,12 +796,15 @@
try {
remoteViews = factory.getViewAt(position);
itemId = factory.getItemId(position);
- } catch (Exception e) {
+ } catch (RemoteException e) {
Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage());
// Return early to prevent additional work in re-centering the view cache, and
// swapping from the loading view
return;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage());
+ return;
}
if (remoteViews == null) {
@@ -971,18 +978,20 @@
return getCount() <= 0;
}
-
private void onNotifyDataSetChanged() {
// Complete the actual notifyDataSetChanged() call initiated earlier
IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
try {
factory.onDataSetChanged();
- } catch (Exception e) {
+ } catch (RemoteException e) {
Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
// Return early to prevent from further being notified (since nothing has
// changed)
return;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
+ return;
}
// Flush the cache so that we can reload new items from the service
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index e0b08d4..7ba4777 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -138,34 +138,87 @@
return mIsCreated;
}
public synchronized void onDataSetChanged() {
- mFactory.onDataSetChanged();
+ try {
+ mFactory.onDataSetChanged();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
}
public synchronized int getCount() {
- return mFactory.getCount();
+ int count = 0;
+ try {
+ count = mFactory.getCount();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
+ return count;
}
public synchronized RemoteViews getViewAt(int position) {
- RemoteViews rv = mFactory.getViewAt(position);
- rv.setIsWidgetCollectionChild(true);
+ RemoteViews rv = null;
+ try {
+ rv = mFactory.getViewAt(position);
+ if (rv != null) {
+ rv.setIsWidgetCollectionChild(true);
+ }
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
return rv;
}
public synchronized RemoteViews getLoadingView() {
- return mFactory.getLoadingView();
+ RemoteViews rv = null;
+ try {
+ rv = mFactory.getLoadingView();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
+ return rv;
}
public synchronized int getViewTypeCount() {
- return mFactory.getViewTypeCount();
+ int count = 0;
+ try {
+ count = mFactory.getViewTypeCount();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
+ return count;
}
public synchronized long getItemId(int position) {
- return mFactory.getItemId(position);
+ long id = 0;
+ try {
+ id = mFactory.getItemId(position);
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
+ return id;
}
public synchronized boolean hasStableIds() {
- return mFactory.hasStableIds();
+ boolean hasStableIds = false;
+ try {
+ hasStableIds = mFactory.hasStableIds();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
+ return hasStableIds;
}
public void onDestroy(Intent intent) {
synchronized (sLock) {
Intent.FilterComparison fc = new Intent.FilterComparison(intent);
if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) {
RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc);
- factory.onDestroy();
+ try {
+ factory.onDestroy();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
RemoteViewsService.sRemoteViewFactories.remove(fc);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 222bc84..baf20a1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -128,7 +128,6 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.HashSet;
/**
* Displays text to the user and optionally allows them to edit it. A TextView
@@ -3980,13 +3979,6 @@
observer.removeOnPreDrawListener(this);
mPreDrawState = PREDRAW_NOT_REGISTERED;
}
- // No need to create the controller, as getXXController would.
- if (mInsertionPointCursorController != null) {
- observer.removeOnTouchModeChangeListener(mInsertionPointCursorController);
- }
- if (mSelectionModifierCursorController != null) {
- observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController);
- }
if (mError != null) {
hideError();
@@ -8339,19 +8331,6 @@
sLastCutOrCopyTime = SystemClock.uptimeMillis();
}
- public boolean setCorrectionSpan(IBinder token, CorrectionSpan span, int start, int end,
- int flags) {
- if (getWindowToken() != token || !(mText instanceof Spannable)) return false;
- Spannable spannable = (Spannable)mText;
- CorrectionSpan[] spans = spannable.getSpans(start, end, CorrectionSpan.class);
- final int N = spans.length;
- for (int i = 0; i < N; ++i) {
- spannable.removeSpan(spans[i]);
- }
- spannable.setSpan(span, start, end, flags);
- return true;
- }
-
/**
* An ActionMode Callback class that is used to provide actions while in text selection mode.
*
@@ -9221,6 +9200,9 @@
@Override
public void onDetached() {
+ final ViewTreeObserver observer = getViewTreeObserver();
+ observer.removeOnTouchModeChangeListener(this);
+
if (mHandle != null) mHandle.onDetached();
}
}
@@ -9349,6 +9331,9 @@
@Override
public void onDetached() {
+ final ViewTreeObserver observer = getViewTreeObserver();
+ observer.removeOnTouchModeChangeListener(this);
+
if (mStartHandle != null) mStartHandle.onDetached();
if (mEndHandle != null) mEndHandle.onDetached();
}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index b712fdb..11b594c 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -25,13 +25,13 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Dialog;
-import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -44,7 +44,6 @@
import android.view.View;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.SpinnerAdapter;
@@ -59,6 +58,7 @@
* which is normally hidden.
*/
public class ActionBarImpl extends ActionBar {
+ private static final String TAG = "ActionBarImpl";
private static final int NORMAL_VIEW = 0;
private static final int CONTEXT_VIEW = 1;
@@ -92,60 +92,34 @@
final Handler mHandler = new Handler();
- private Animator mCurrentAnim;
+ private Animator mCurrentShowAnim;
+ private Animator mCurrentModeAnim;
private boolean mShowHideAnimationEnabled;
+ boolean mWasHiddenBeforeMode;
private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
- new AnimatorListener() { // NORMAL_VIEW
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
+ new AnimatorListenerAdapter() { // NORMAL_VIEW
@Override
public void onAnimationEnd(Animator animation) {
if (mLowerContextView != null) {
mLowerContextView.removeAllViews();
}
- mCurrentAnim = null;
+ mCurrentModeAnim = null;
hideAllExcept(NORMAL_VIEW);
}
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
},
- new AnimatorListener() { // CONTEXT_VIEW
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
+ new AnimatorListenerAdapter() { // CONTEXT_VIEW
@Override
public void onAnimationEnd(Animator animation) {
- mCurrentAnim = null;
+ mCurrentModeAnim = null;
hideAllExcept(CONTEXT_VIEW);
}
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
}
};
- final AnimatorListener mHideListener = new AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
+ final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mContentView != null) {
@@ -153,36 +127,16 @@
}
mContainerView.setVisibility(View.GONE);
mContainerView.setTransitioning(false);
- mCurrentAnim = null;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
+ mCurrentShowAnim = null;
}
};
- final AnimatorListener mShowListener = new AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
+ final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mCurrentAnim = null;
+ mCurrentShowAnim = null;
mContainerView.requestLayout();
}
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
};
public ActionBarImpl(Activity activity) {
@@ -229,8 +183,8 @@
*/
public void setShowHideAnimationEnabled(boolean enabled) {
mShowHideAnimationEnabled = enabled;
- if (!enabled && mCurrentAnim != null) {
- mCurrentAnim.end();
+ if (!enabled && mCurrentShowAnim != null) {
+ mCurrentShowAnim.end();
}
}
@@ -370,6 +324,7 @@
mUpperContextView.killMode();
ActionMode mode = new ActionModeImpl(callback);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
+ mWasHiddenBeforeMode = !isShowing();
mode.invalidate();
mUpperContextView.initForMode(mode);
animateTo(CONTEXT_VIEW);
@@ -378,7 +333,6 @@
mLowerContextView.setVisibility(View.VISIBLE);
}
mActionMode = mode;
- show();
return mode;
}
return null;
@@ -498,10 +452,15 @@
@Override
public void show() {
- if (mCurrentAnim != null) {
- mCurrentAnim.end();
+ show(true);
+ }
+
+ void show(boolean markHiddenBeforeMode) {
+ if (mCurrentShowAnim != null) {
+ mCurrentShowAnim.end();
}
if (mContainerView.getVisibility() == View.VISIBLE) {
+ if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
return;
}
mContainerView.setVisibility(View.VISIBLE);
@@ -517,17 +476,19 @@
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
}
anim.addListener(mShowListener);
- mCurrentAnim = anim;
+ mCurrentShowAnim = anim;
anim.start();
} else {
+ mContainerView.setAlpha(1);
+ mContainerView.setTranslationY(0);
mShowListener.onAnimationEnd(null);
}
}
@Override
public void hide() {
- if (mCurrentAnim != null) {
- mCurrentAnim.end();
+ if (mCurrentShowAnim != null) {
+ mCurrentShowAnim.end();
}
if (mContainerView.getVisibility() == View.GONE) {
return;
@@ -545,7 +506,7 @@
-mContainerView.getHeight()));
}
anim.addListener(mHideListener);
- mCurrentAnim = anim;
+ mCurrentShowAnim = anim;
anim.start();
} else {
mHideListener.onAnimationEnd(null);
@@ -556,13 +517,17 @@
return mContainerView.getVisibility() == View.VISIBLE;
}
- private long animateTo(int viewIndex) {
- show();
+ long animateTo(int viewIndex) {
+ show(false);
+ if (mCurrentModeAnim != null) {
+ mCurrentModeAnim.end();
+ }
AnimatorSet set = new AnimatorSet();
final View targetChild = mContainerView.getChildAt(viewIndex);
targetChild.setVisibility(View.VISIBLE);
+ targetChild.setAlpha(0);
AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
final int count = mContainerView.getChildCount();
@@ -581,7 +546,7 @@
set.addListener(mAfterAnimation[viewIndex]);
- mCurrentAnim = set;
+ mCurrentModeAnim = set;
set.start();
return set.getDuration();
}
@@ -636,6 +601,10 @@
mLowerContextView.setVisibility(View.GONE);
}
mActionMode = null;
+
+ if (mWasHiddenBeforeMode) {
+ hide();
+ }
}
@Override
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index 8c256e0..268a9d4 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -20,7 +20,8 @@
import android.os.Build;
import android.os.SystemProperties;
import android.util.Log;
-import dalvik.system.SamplingProfiler;
+import dalvik.system.profiler.AsciiHprofWriter;
+import dalvik.system.profiler.SamplingProfiler;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -162,7 +163,7 @@
try {
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path)));
generateSnapshotHeader(name, packageInfo, out);
- new SamplingProfiler.AsciiHprofWriter(INSTANCE.getHprofData(), out).write();
+ new AsciiHprofWriter(INSTANCE.getHprofData(), out).write();
if (out.checkError()) {
throw new IOException();
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 8719fde..c792d78 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -18,11 +18,9 @@
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.text.style.CorrectionSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
@@ -47,7 +45,6 @@
private static final int DO_PERFORM_EDITOR_ACTION = 58;
private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
private static final int DO_SET_COMPOSING_TEXT = 60;
- private static final int DO_SET_SECURE_CORRECTION_SPAN = 61;
private static final int DO_SET_COMPOSING_REGION = 63;
private static final int DO_FINISH_COMPOSING_TEXT = 65;
private static final int DO_SEND_KEY_EVENT = 70;
@@ -178,13 +175,6 @@
dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
}
- @Override
- public void setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
- int end, int flags) {
- dispatchMessage(obtainMessageOOIII(DO_SET_SECURE_CORRECTION_SPAN, token, correctionSpan,
- start, end, flags));
- }
-
void dispatchMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
@@ -430,17 +420,6 @@
(Bundle)args.arg2);
return;
}
- case DO_SET_SECURE_CORRECTION_SPAN: {
- InputConnection ic = mInputConnection.get();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setCorrectionSpan on inactive InputConnection");
- return;
- }
- SomeArgs args = (SomeArgs)msg.obj;
- ic.setCorrectionSpan((IBinder)args.arg1, (CorrectionSpan)args.arg2, msg.arg1,
- msg.arg2, args.seq);
- return;
- }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -490,12 +469,4 @@
args.arg2 = arg2;
return mH.obtainMessage(what, 0, 0, args);
}
-
- Message obtainMessageOOIII(int what, Object arg1, Object arg2, int arg3, int arg4, int arg5) {
- SomeArgs args = new SomeArgs();
- args.arg1 = arg1;
- args.arg2 = arg2;
- args.seq = arg5;
- return mH.obtainMessage(what, arg3, arg4, args);
- }
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index eb20d61..719a24f 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -17,7 +17,6 @@
package com.android.internal.view;
import android.os.Bundle;
-import android.text.style.CorrectionSpan;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -74,6 +73,4 @@
void getSelectedText(int flags, int seq, IInputContextCallback callback);
- void setCorrectionSpan(in IBinder token, in CorrectionSpan correctionSpan, int start,
- int end, int flags);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index efe315f..a235d9a 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -17,10 +17,8 @@
package com.android.internal.view;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.text.style.CorrectionSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
@@ -253,7 +251,7 @@
}
return value;
}
-
+
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
ExtractedText value = null;
try {
@@ -415,14 +413,4 @@
return false;
}
}
- @Override
- public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
- int end, int flags) {
- try {
- mIInputContext.setCorrectionSpan(token, correctionSpan, start, end, flags);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 3325df6..ca1aa0b 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -56,6 +56,7 @@
mTextButton = (Button) findViewById(com.android.internal.R.id.textButton);
mImageButton.setOnClickListener(this);
mTextButton.setOnClickListener(this);
+ setOnClickListener(this);
}
public MenuItemImpl getItemData() {
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index ea82bc7..5bf6026 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -146,13 +146,4 @@
return success;
}
-
- @Override
- public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
- int end, int flags) {
- mTextView.beginBatchEdit();
- boolean retval = mTextView.setCorrectionSpan(token, correctionSpan, start, end, flags);
- mTextView.endBatchEdit();
- return retval;
- }
}
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 5857acb..18076c4 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -22,7 +22,7 @@
/** {@hide} */
interface IRemoteViewsFactory {
void onDataSetChanged();
- void onDestroy(in Intent intent);
+ oneway void onDestroy(in Intent intent);
int getCount();
RemoteViews getViewAt(int position);
RemoteViews getLoadingView();
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 076a1cb..c34cb9e 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -357,6 +357,12 @@
case MotionEvent.ACTION_HOVER_MOVE:
prefix = "HOVER MOVE";
break;
+ case MotionEvent.ACTION_HOVER_ENTER:
+ prefix = "HOVER ENTER";
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT:
+ prefix = "HOVER EXIT";
+ break;
case MotionEvent.ACTION_SCROLL:
prefix = "SCROLL";
break;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index b4a0e4f..54b7fbb 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -93,6 +93,7 @@
android/graphics/DrawFilter.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \
android/graphics/Graphics.cpp \
+ android/graphics/HarfbuzzSkia.cpp \
android/graphics/Interpolator.cpp \
android/graphics/LayerRasterizer.cpp \
android/graphics/MaskFilter.cpp \
@@ -174,6 +175,7 @@
external/icu4c/i18n \
external/icu4c/common \
external/jpeg \
+ external/harfbuzz/src \
frameworks/opt/emoji
LOCAL_SHARED_LIBRARIES := \
@@ -185,7 +187,6 @@
libnetutils \
libui \
libgui \
- libsurfaceflinger_client \
libcamera_client \
libskia \
libsqlite \
@@ -206,6 +207,7 @@
libjpeg \
libnfc_ndef \
libusbhost \
+ libharfbuzz \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 0cdb357..b4ad9e9 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -755,6 +755,27 @@
env->ReleaseStringChars(text, textArray);
}
+ static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jcharArray glyphs, int index, int count,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
+ jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
+
+ // TODO: need to suppress this code after the GL renderer is modified for not
+ // copying the paint
+
+ // Save old text encoding
+ SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
+ // Define Glyph encoding
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ TextLayout::drawText(paint, glyphArray + index, count, flags, x, y, canvas);
+
+ // Get back old encoding
+ paint->setTextEncoding(oldEncoding);
+
+ env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
+ }
+
static void drawTextRun___CIIIIFFIPaint(
JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
int count, int contextIndex, int contextCount,
@@ -946,6 +967,8 @@
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
{"native_drawText","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
+ {"native_drawGlyphs","(I[CIIFFII)V",
+ (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
{"native_drawTextRun","(I[CIIIIFFII)V",
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
{"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp
new file mode 100644
index 0000000..58fb32b
--- /dev/null
+++ b/core/jni/android/graphics/HarfbuzzSkia.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ * Copyright 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HarfbuzzSkia.h"
+
+#include "SkFontHost.h"
+
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkTypeface.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+}
+
+// This file implements the callbacks which Harfbuzz requires by using Skia
+// calls. See the Harfbuzz source for references about what these callbacks do.
+
+namespace android {
+
+static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
+{
+ // HB_Fixed is a 26.6 fixed point format.
+ return value * 64;
+}
+
+static void setupPaintWithFontData(SkPaint* paint, FontData* data) {
+ paint->setAntiAlias(true);
+ paint->setSubpixelText(true);
+ paint->setHinting(SkPaint::kSlight_Hinting);
+ paint->setTextSize(SkFloatToScalar(data->textSize));
+ paint->setTypeface(data->typeFace);
+ paint->setFakeBoldText(data->fakeBold);
+ paint->setTextSkewX(data->fakeItalic ? -SK_Scalar1/4 : 0);
+}
+
+static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
+ HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t),
+ reinterpret_cast<uint16_t*>(glyphs));
+
+ // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
+ // |glyphs| array needs to be converted.
+ for (int i = numGlyphs - 1; i >= 0; --i) {
+ uint16_t value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value));
+ glyphs[i] = value;
+ }
+
+ *glyphsSize = numGlyphs;
+ return 1;
+}
+
+static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs,
+ HB_Fixed* advances, int flags)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ uint16_t* glyphs16 = new uint16_t[numGlyphs];
+ if (!glyphs16)
+ return;
+ for (unsigned i = 0; i < numGlyphs; ++i)
+ glyphs16[i] = glyphs[i];
+ paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+
+ // The |advances| values which Skia outputs are SkScalars, which are floats
+ // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
+ // These two formats are both 32-bits long.
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ float value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value));
+ advances[i] = SkiaScalarToHarfbuzzFixed(value);
+ }
+ delete glyphs16;
+}
+
+static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ uint16_t* glyphs16 = new uint16_t[length];
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16);
+
+ bool result = true;
+ for (int i = 0; i < numGlyphs; ++i) {
+ if (!glyphs16[i]) {
+ result = false;
+ break;
+ }
+ }
+ delete glyphs16;
+ return result;
+}
+
+static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point,
+ HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ if (flags & HB_ShaperFlag_UseDesignMetrics)
+ // This is requesting pre-hinted positions. We can't support this.
+ return HB_Err_Invalid_Argument;
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkPath path;
+ paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
+ uint32_t numPoints = path.getPoints(0, 0);
+ if (point >= numPoints)
+ return HB_Err_Invalid_SubTable;
+ SkPoint* points = reinterpret_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1)));
+ if (!points)
+ return HB_Err_Invalid_SubTable;
+ // Skia does let us get a single point from the path.
+ path.getPoints(points, point + 1);
+ *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
+ *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+ *resultingNumPoints = numPoints;
+ delete points;
+
+ return HB_Err_Ok;
+}
+
+static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkScalar width;
+ SkRect bounds;
+ paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
+
+ metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+ metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+ metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+ metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+
+ metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
+ // We can't actually get the |y| correct because Skia doesn't export
+ // the vertical advance. However, nor we do ever render vertical text at
+ // the moment so it's unimportant.
+ metrics->yOffset = 0;
+}
+
+static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ SkPaint::FontMetrics skiaMetrics;
+ paint.getFontMetrics(&skiaMetrics);
+
+ switch (metric) {
+ case HB_FontAscent:
+ return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+ // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+const HB_FontClass harfbuzzSkiaClass = {
+ stringToGlyphs,
+ glyphsToAdvances,
+ canRender,
+ getOutlinePoint,
+ getGlyphMetrics,
+ getFontMetric,
+};
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
+{
+ FontData* data = reinterpret_cast<FontData*>(voidface);
+ SkTypeface* typeface = data->typeFace;
+
+ const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag);
+ if (!tableSize)
+ return HB_Err_Invalid_Argument;
+ // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
+ if (!buffer) {
+ *len = tableSize;
+ return HB_Err_Ok;
+ }
+
+ if (*len < tableSize)
+ return HB_Err_Invalid_Argument;
+ SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer);
+ return HB_Err_Ok;
+}
+
+} // namespace android
diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfbuzzSkia.h
new file mode 100644
index 0000000..d057d76
--- /dev/null
+++ b/core/jni/android/graphics/HarfbuzzSkia.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ * Copyright 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HarfbuzzSkia_h
+#define HarfbuzzSkia_h
+
+#include "SkTypeface.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+}
+
+namespace android {
+ typedef struct {
+ SkTypeface* typeFace;
+ float textSize;
+ bool fakeBold;
+ bool fakeItalic;
+ } FontData;
+
+ HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+ extern const HB_FontClass harfbuzzSkiaClass;
+} // namespace android
+
+#endif
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e62b034..5c3497f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -393,13 +393,40 @@
return count;
}
- static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloatArray widths) {
+ static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
+ int start, int end, jfloatArray widths) {
const jchar* textArray = env->GetStringChars(text, NULL);
int count = dotextwidths(env, paint, textArray + start, end - start, widths);
env->ReleaseStringChars(text, textArray);
return count;
}
+ static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
+ jint contextCount, jint flags, jcharArray glyphs) {
+ jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
+ HB_ShaperItem shaperItem;
+ HB_FontRec font;
+ FontData fontData;
+ RunAdvanceDescription::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text,
+ start, count, contextCount, flags);
+
+ int glyphCount = shaperItem.num_glyphs;
+ for (int i = 0; i < glyphCount; i++) {
+ glyphsArray[i] = (jchar) shaperItem.glyphs[i];
+ }
+ return glyphCount;
+ }
+
+ static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
+ jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+ jcharArray glyphs) {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
+ end - start, contextEnd - contextStart, flags, glyphs);
+ env->ReleaseStringChars(text, textArray);
+ return count;
+ }
+
static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
jint start, jint count, jint contextCount, jint flags,
jfloatArray advances, jint advancesIndex) {
@@ -725,6 +752,8 @@
SkPaintGlue::getTextRunAdvances___CIIIII_FI},
{"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+ {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
+ (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
{"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
{"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
(void*) SkPaintGlue::getTextRunCursor__String},
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index 6d8ba91..2c68fa3 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,5 +45,7 @@
return kRtlDebugDisabled;
}
+#define RTL_USE_HARFBUZZ 1
+
} // namespace android
#endif // ANDROID_RTL_PROPERTIES_H
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 7888769..a7265be 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -47,8 +47,16 @@
if (mDebugEnabled) {
LOGD("TextLayoutCache start time: %lld", mCacheStartTime);
}
-
mInitialized = true;
+
+ if (mDebugEnabled) {
+#if RTL_USE_HARFBUZZ
+ LOGD("TextLayoutCache is using HARFBUZZ");
+#else
+ LOGD("TextLayoutCache is using ICU");
+#endif
+ }
+
if (mDebugEnabled) {
LOGD("TextLayoutCache initialization is done");
}
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 9d55918..925bb7c 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -30,6 +30,8 @@
#include "unicode/ubidi.h"
#include "unicode/ushape.h"
+#include "HarfbuzzSkia.h"
+#include "harfbuzz-shaper.h"
#include <android_runtime/AndroidRuntime.h>
@@ -52,8 +54,14 @@
// Define the interval in number of cache hits between two statistics dump
#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
+// Define if we want to have Advances debug values
+#define DEBUG_ADVANCES 0
+
namespace android {
+// Harfbuzz uses 26.6 fixed point values for pixel offsets
+#define HB_FIXED_TO_FLOAT(v) (((float) v) * (1.0 / 64))
+
/**
* TextLayoutCacheKey is the Cache key
*/
@@ -149,8 +157,18 @@
advances = new float[count];
this->count = count;
- computeAdvances(paint, chars, start, count, contextCount, dirFlags,
+#if RTL_USE_HARFBUZZ
+ computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
advances, &totalAdvance);
+#else
+ computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
+ advances, &totalAdvance);
+#endif
+#if DEBUG_ADVANCES
+ LOGD("Advances - count=%d - countextCount=%d - totalAdvance=%f - "
+ "adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, totalAdvance,
+ advances[0], advances[1], advances[2], advances[3]);
+#endif
}
void copyResult(jfloat* outAdvances, jfloat* outTotalAdvance) {
@@ -165,8 +183,108 @@
return sizeof(RunAdvanceDescription) + sizeof(jfloat) * count;
}
- static void computeAdvances(SkPaint* paint, const UChar* chars, size_t start, size_t count,
- size_t contextCount, int dirFlags, jfloat* outAdvances, jfloat* outTotalAdvance) {
+ static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
+ SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
+ int dirFlags) {
+ bool isRTL = dirFlags & 0x1;
+
+ font->klass = &harfbuzzSkiaClass;
+ font->userData = 0;
+ // The values which harfbuzzSkiaClass returns are already scaled to
+ // pixel units, so we just set all these to one to disable further
+ // scaling.
+ font->x_ppem = 1;
+ font->y_ppem = 1;
+ font->x_scale = 1;
+ font->y_scale = 1;
+
+ memset(shaperItem, 0, sizeof(*shaperItem));
+ shaperItem->font = font;
+ shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable);
+
+ // We cannot know, ahead of time, how many glyphs a given script run
+ // will produce. We take a guess that script runs will not produce more
+ // than twice as many glyphs as there are code points plus a bit of
+ // padding and fallback if we find that we are wrong.
+ createGlyphArrays(shaperItem, (contextCount + 2) * 2);
+
+ // Free memory for clusters if needed and recreate the clusters array
+ if (shaperItem->log_clusters) {
+ delete shaperItem->log_clusters;
+ }
+ shaperItem->log_clusters = new unsigned short[contextCount];
+
+ shaperItem->item.pos = start;
+ shaperItem->item.length = count;
+ shaperItem->item.bidiLevel = isRTL;
+ shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
+
+ shaperItem->string = chars;
+ shaperItem->stringLength = contextCount;
+
+ fontData->textSize = paint->getTextSize();
+ fontData->fakeBold = paint->isFakeBoldText();
+ fontData->fakeItalic = (paint->getTextSkewX() > 0);
+ fontData->typeFace = paint->getTypeface();
+
+ shaperItem->font->userData = fontData;
+ }
+
+ static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
+ SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
+ int dirFlags) {
+ // Setup Harfbuzz Shaper
+ setupShaperItem(shaperItem, font, fontData, paint, chars, start, count,
+ contextCount, dirFlags);
+
+ // Shape
+ resetGlyphArrays(shaperItem);
+ while (!HB_ShapeItem(shaperItem)) {
+ // We overflowed our arrays. Resize and retry.
+ // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size.
+ deleteGlyphArrays(shaperItem);
+ createGlyphArrays(shaperItem, shaperItem->num_glyphs << 1);
+ resetGlyphArrays(shaperItem);
+ }
+ }
+
+ static void computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
+ size_t count, size_t contextCount, int dirFlags,
+ jfloat* outAdvances, jfloat* outTotalAdvance) {
+
+ bool isRTL = dirFlags & 0x1;
+
+ HB_ShaperItem shaperItem;
+ HB_FontRec font;
+ FontData fontData;
+ shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count,
+ contextCount, dirFlags);
+
+#if DEBUG_ADVANCES
+ LOGD("HARFBUZZ -- num_glypth=%d", shaperItem.num_glyphs);
+#endif
+
+ jfloat totalAdvance = 0;
+ for (size_t i = 0; i < count; i++) {
+ // Be careful: we need to use ceilf() for doing the same way as what Skia is doing
+ totalAdvance += outAdvances[i] = ceilf(HB_FIXED_TO_FLOAT(shaperItem.advances[i]));
+
+#if DEBUG_ADVANCES
+ LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
+ totalAdvance);
+#endif
+ }
+
+ deleteGlyphArrays(&shaperItem);
+ HB_FreeFace(shaperItem.face);
+
+ *outTotalAdvance = totalAdvance;
+ }
+
+ static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, size_t start,
+ size_t count, size_t contextCount, int dirFlags,
+ jfloat* outAdvances, jfloat* outTotalAdvance) {
+
SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
jchar* buffer = tempBuffer.get();
@@ -199,6 +317,9 @@
jfloat totalAdvance = 0;
if (widths < count) {
+#if DEBUG_ADVANCES
+ LOGD("ICU -- count=%d", widths);
+#endif
// Skia operates on code points, not code units, so surrogate pairs return only
// one value. Expand the result so we have one value per UTF-16 code unit.
@@ -213,10 +334,19 @@
text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
outAdvances[p++] = 0;
}
+#if DEBUG_ADVANCES
+ LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
}
} else {
+#if DEBUG_ADVANCES
+ LOGD("ICU -- count=%d", count);
+#endif
for (size_t i = 0; i < count; i++) {
totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
+#if DEBUG_ADVANCES
+ LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
}
}
*outTotalAdvance = totalAdvance;
@@ -228,6 +358,32 @@
size_t count;
uint32_t elapsedTime;
+
+ static void deleteGlyphArrays(HB_ShaperItem* shaperItem) {
+ delete[] shaperItem->glyphs;
+ delete[] shaperItem->attributes;
+ delete[] shaperItem->advances;
+ delete[] shaperItem->offsets;
+ }
+
+ static void createGlyphArrays(HB_ShaperItem* shaperItem, int size) {
+ shaperItem->glyphs = new HB_Glyph[size];
+ shaperItem->attributes = new HB_GlyphAttributes[size];
+ shaperItem->advances = new HB_Fixed[size];
+ shaperItem->offsets = new HB_FixedPoint[size];
+ shaperItem->num_glyphs = size;
+ }
+
+ static void resetGlyphArrays(HB_ShaperItem* shaperItem) {
+ int size = shaperItem->num_glyphs;
+ // All the types here don't have pointers. It is safe to reset to
+ // zero unless Harfbuzz breaks the compatibility in the future.
+ memset(shaperItem->glyphs, 0, size * sizeof(shaperItem->glyphs[0]));
+ memset(shaperItem->attributes, 0, size * sizeof(shaperItem->attributes[0]));
+ memset(shaperItem->advances, 0, size * sizeof(shaperItem->advances[0]));
+ memset(shaperItem->offsets, 0, size * sizeof(shaperItem->offsets[0]));
+ }
+
}; // RunAdvanceDescription
diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp
index bbf1ae5..5b21c56 100644
--- a/core/jni/android_bluetooth_HeadsetBase.cpp
+++ b/core/jni/android_bluetooth_HeadsetBase.cpp
@@ -96,11 +96,12 @@
return 0;
}
-static int is_ascii(char *line) {
- for (;;line++) {
- if (*line == 0) return 1;
- if (*line >> 7) return 0;
- }
+static void mask_eighth_bit(char *line)
+{
+ for (;;line++) {
+ if (0 == *line) return;
+ *line &= 0x7F;
+ }
}
static const char* get_line(int fd, char *buf, int len, int timeout_ms,
@@ -164,16 +165,15 @@
*bufit = NULL;
- // Simple validation. Must be all ASCII.
- // (we sometimes send non-ASCII UTF-8 in address book, but should
- // never receive non-ASCII UTF-8).
- // This was added because of the BMW 2005 E46 which sends binary junk.
- if (is_ascii(buf)) {
- IF_LOGV() LOG(LOG_VERBOSE, "Bluetooth AT recv", "%s", buf);
- } else {
- LOGW("Ignoring invalid AT command: %s", buf);
- buf[0] = NULL;
- }
+ // According to ITU V.250 section 5.1, IA5 7 bit chars are used,
+ // the eighth bit or higher bits are ignored if they exists
+ // We mask out only eighth bit, no higher bit, since we do char
+ // string here, not wide char.
+ // We added this processing due to 2 real world problems.
+ // 1 BMW 2005 E46 which sends binary junk
+ // 2 Audi 2010 A3, dial command use 0xAD (soft-hyphen) as number
+ // formater, which was rejected by the AT handler
+ mask_eighth_bit(buf);
return buf;
}
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 0f71b9f..1c326ba 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -533,16 +533,69 @@
static void
android_glGetBufferParameteriv__II_3II
(JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glGetBufferParameteriv");
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetBufferParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
}
/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
static void
android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
- _env->ThrowNew(UOEClass,
- "glGetBufferParameteriv");
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetBufferParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
}
/* void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) */
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 942a0d9..1390506 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -1621,171 +1621,495 @@
static jboolean
android_glIsRenderbufferOES__I
(JNIEnv *_env, jobject _this, jint renderbuffer) {
- _env->ThrowNew(UOEClass,
- "glIsRenderbufferOES");
- return JNI_FALSE;
+ GLboolean _returnValue;
+ _returnValue = glIsRenderbufferOES(
+ (GLuint)renderbuffer
+ );
+ return _returnValue;
}
/* void glBindRenderbufferOES ( GLenum target, GLuint renderbuffer ) */
static void
android_glBindRenderbufferOES__II
(JNIEnv *_env, jobject _this, jint target, jint renderbuffer) {
- _env->ThrowNew(UOEClass,
- "glBindRenderbufferOES");
+ glBindRenderbufferOES(
+ (GLenum)target,
+ (GLuint)renderbuffer
+ );
}
/* void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) */
static void
android_glDeleteRenderbuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glDeleteRenderbuffersOES");
+ GLuint *renderbuffers_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *renderbuffers = (GLuint *) 0;
+
+ if (!renderbuffers_ref) {
+ _env->ThrowNew(IAEClass, "renderbuffers == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ renderbuffers_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(renderbuffers_ref, (jboolean *)0);
+ renderbuffers = renderbuffers_base + offset;
+
+ glDeleteRenderbuffersOES(
+ (GLsizei)n,
+ (GLuint *)renderbuffers
+ );
+
+exit:
+ if (renderbuffers_base) {
+ _env->ReleasePrimitiveArrayCritical(renderbuffers_ref, renderbuffers_base,
+ JNI_ABORT);
+ }
}
/* void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) */
static void
android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
- _env->ThrowNew(UOEClass,
- "glDeleteRenderbuffersOES");
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *renderbuffers = (GLuint *) 0;
+
+ renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glDeleteRenderbuffersOES(
+ (GLsizei)n,
+ (GLuint *)renderbuffers
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, renderbuffers, JNI_FALSE);
+ }
}
/* void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) */
static void
android_glGenRenderbuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glGenRenderbuffersOES");
+ jint _exception = 0;
+ GLuint *renderbuffers_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *renderbuffers = (GLuint *) 0;
+
+ if (!renderbuffers_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "renderbuffers == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ renderbuffers_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(renderbuffers_ref, (jboolean *)0);
+ renderbuffers = renderbuffers_base + offset;
+
+ glGenRenderbuffersOES(
+ (GLsizei)n,
+ (GLuint *)renderbuffers
+ );
+
+exit:
+ if (renderbuffers_base) {
+ _env->ReleasePrimitiveArrayCritical(renderbuffers_ref, renderbuffers_base,
+ _exception ? JNI_ABORT: 0);
+ }
}
/* void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) */
static void
android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
- _env->ThrowNew(UOEClass,
- "glGenRenderbuffersOES");
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *renderbuffers = (GLuint *) 0;
+
+ renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glGenRenderbuffersOES(
+ (GLsizei)n,
+ (GLuint *)renderbuffers
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, renderbuffers, _exception ? JNI_FALSE : JNI_TRUE);
+ }
}
/* void glRenderbufferStorageOES ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) */
static void
android_glRenderbufferStorageOES__IIII
(JNIEnv *_env, jobject _this, jint target, jint internalformat, jint width, jint height) {
- _env->ThrowNew(UOEClass,
- "glRenderbufferStorageOES");
+ glRenderbufferStorageOES(
+ (GLenum)target,
+ (GLenum)internalformat,
+ (GLsizei)width,
+ (GLsizei)height
+ );
}
/* void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) */
static void
android_glGetRenderbufferParameterivOES__II_3II
(JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glGetRenderbufferParameterivOES");
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetRenderbufferParameterivOES(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
}
/* void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) */
static void
android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
- _env->ThrowNew(UOEClass,
- "glGetRenderbufferParameterivOES");
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetRenderbufferParameterivOES(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
}
/* GLboolean glIsFramebufferOES ( GLuint framebuffer ) */
static jboolean
android_glIsFramebufferOES__I
(JNIEnv *_env, jobject _this, jint framebuffer) {
- _env->ThrowNew(UOEClass,
- "glIsFramebufferOES");
- return JNI_FALSE;
+ GLboolean _returnValue;
+ _returnValue = glIsFramebufferOES(
+ (GLuint)framebuffer
+ );
+ return _returnValue;
}
/* void glBindFramebufferOES ( GLenum target, GLuint framebuffer ) */
static void
android_glBindFramebufferOES__II
(JNIEnv *_env, jobject _this, jint target, jint framebuffer) {
- _env->ThrowNew(UOEClass,
- "glBindFramebufferOES");
+ glBindFramebufferOES(
+ (GLenum)target,
+ (GLuint)framebuffer
+ );
}
/* void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) */
static void
android_glDeleteFramebuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glDeleteFramebuffersOES");
+ GLuint *framebuffers_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *framebuffers = (GLuint *) 0;
+
+ if (!framebuffers_ref) {
+ _env->ThrowNew(IAEClass, "framebuffers == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ framebuffers_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(framebuffers_ref, (jboolean *)0);
+ framebuffers = framebuffers_base + offset;
+
+ glDeleteFramebuffersOES(
+ (GLsizei)n,
+ (GLuint *)framebuffers
+ );
+
+exit:
+ if (framebuffers_base) {
+ _env->ReleasePrimitiveArrayCritical(framebuffers_ref, framebuffers_base,
+ JNI_ABORT);
+ }
}
/* void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) */
static void
android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
- _env->ThrowNew(UOEClass,
- "glDeleteFramebuffersOES");
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *framebuffers = (GLuint *) 0;
+
+ framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glDeleteFramebuffersOES(
+ (GLsizei)n,
+ (GLuint *)framebuffers
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, framebuffers, JNI_FALSE);
+ }
}
/* void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) */
static void
android_glGenFramebuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glGenFramebuffersOES");
+ jint _exception = 0;
+ GLuint *framebuffers_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *framebuffers = (GLuint *) 0;
+
+ if (!framebuffers_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "framebuffers == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ framebuffers_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(framebuffers_ref, (jboolean *)0);
+ framebuffers = framebuffers_base + offset;
+
+ glGenFramebuffersOES(
+ (GLsizei)n,
+ (GLuint *)framebuffers
+ );
+
+exit:
+ if (framebuffers_base) {
+ _env->ReleasePrimitiveArrayCritical(framebuffers_ref, framebuffers_base,
+ _exception ? JNI_ABORT: 0);
+ }
}
/* void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) */
static void
android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
- _env->ThrowNew(UOEClass,
- "glGenFramebuffersOES");
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *framebuffers = (GLuint *) 0;
+
+ framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glGenFramebuffersOES(
+ (GLsizei)n,
+ (GLuint *)framebuffers
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, framebuffers, _exception ? JNI_FALSE : JNI_TRUE);
+ }
}
/* GLenum glCheckFramebufferStatusOES ( GLenum target ) */
static jint
android_glCheckFramebufferStatusOES__I
(JNIEnv *_env, jobject _this, jint target) {
- _env->ThrowNew(UOEClass,
- "glCheckFramebufferStatusOES");
- return 0;
+ GLenum _returnValue;
+ _returnValue = glCheckFramebufferStatusOES(
+ (GLenum)target
+ );
+ return _returnValue;
}
/* void glFramebufferRenderbufferOES ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) */
static void
android_glFramebufferRenderbufferOES__IIII
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) {
- _env->ThrowNew(UOEClass,
- "glFramebufferRenderbufferOES");
+ glFramebufferRenderbufferOES(
+ (GLenum)target,
+ (GLenum)attachment,
+ (GLenum)renderbuffertarget,
+ (GLuint)renderbuffer
+ );
}
/* void glFramebufferTexture2DOES ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) */
static void
android_glFramebufferTexture2DOES__IIIII
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint textarget, jint texture, jint level) {
- _env->ThrowNew(UOEClass,
- "glFramebufferTexture2DOES");
+ glFramebufferTexture2DOES(
+ (GLenum)target,
+ (GLenum)attachment,
+ (GLenum)textarget,
+ (GLuint)texture,
+ (GLint)level
+ );
}
/* void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) */
static void
android_glGetFramebufferAttachmentParameterivOES__III_3II
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glGetFramebufferAttachmentParameterivOES");
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetFramebufferAttachmentParameterivOES(
+ (GLenum)target,
+ (GLenum)attachment,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
}
/* void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) */
static void
android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) {
- _env->ThrowNew(UOEClass,
- "glGetFramebufferAttachmentParameterivOES");
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetFramebufferAttachmentParameterivOES(
+ (GLenum)target,
+ (GLenum)attachment,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
}
/* void glGenerateMipmapOES ( GLenum target ) */
static void
android_glGenerateMipmapOES__I
(JNIEnv *_env, jobject _this, jint target) {
- _env->ThrowNew(UOEClass,
- "glGenerateMipmapOES");
+ glGenerateMipmapOES(
+ (GLenum)target
+ );
}
/* void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) */
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index ef25319..7ac0f6e 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -249,16 +249,19 @@
static void
android_glBlendEquation__I
(JNIEnv *_env, jobject _this, jint mode) {
- _env->ThrowNew(UOEClass,
- "glBlendEquation");
+ glBlendEquation(
+ (GLenum)mode
+ );
}
/* void glBlendEquationSeparate ( GLenum modeRGB, GLenum modeAlpha ) */
static void
android_glBlendEquationSeparate__II
(JNIEnv *_env, jobject _this, jint modeRGB, jint modeAlpha) {
- _env->ThrowNew(UOEClass,
- "glBlendEquationSeparate");
+ glBlendEquationSeparate(
+ (GLenum)modeRGB,
+ (GLenum)modeAlpha
+ );
}
/* void glBlendFunc ( GLenum sfactor, GLenum dfactor ) */
@@ -275,8 +278,12 @@
static void
android_glBlendFuncSeparate__IIII
(JNIEnv *_env, jobject _this, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) {
- _env->ThrowNew(UOEClass,
- "glBlendFuncSeparate");
+ glBlendFuncSeparate(
+ (GLenum)srcRGB,
+ (GLenum)dstRGB,
+ (GLenum)srcAlpha,
+ (GLenum)dstAlpha
+ );
}
/* void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) */
@@ -1643,16 +1650,69 @@
static void
android_glGetBufferParameteriv__II_3II
(JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
- _env->ThrowNew(UOEClass,
- "glGetBufferParameteriv");
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetBufferParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
}
/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
static void
android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
- _env->ThrowNew(UOEClass,
- "glGetBufferParameteriv");
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetBufferParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
}
/* GLenum glGetError ( void ) */
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 15dfea3..4a73368 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -24,7 +24,8 @@
android:paddingLeft="12dip"
android:paddingRight="12dip"
android:minWidth="64dip"
- android:minHeight="?attr/actionBarSize">
+ android:minHeight="?attr/actionBarSize"
+ android:focusable="true">
<ImageButton android:id="@+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -34,7 +35,8 @@
android:paddingRight="4dip"
android:minHeight="56dip"
android:scaleType="center"
- android:background="@null" />
+ android:background="@null"
+ android:focusable="false" />
<Button android:id="@+id/textButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -45,5 +47,6 @@
android:textColor="?attr/actionMenuTextColor"
android:background="@null"
android:paddingLeft="4dip"
- android:paddingRight="4dip" />
+ android:paddingRight="4dip"
+ android:focusable="false" />
</com.android.internal.view.menu.ActionMenuItemView>
diff --git a/core/res/res/layout/tab_indicator_holo.xml b/core/res/res/layout/tab_indicator_holo.xml
index d37476b..60c80e9 100644
--- a/core/res/res/layout/tab_indicator_holo.xml
+++ b/core/res/res/layout/tab_indicator_holo.xml
@@ -15,32 +15,24 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="56dip"
- android:layout_weight="0"
- android:layout_marginLeft="0dip"
- android:layout_marginRight="0dip"
+ android:layout_width="0dp"
+ android:layout_height="58dp"
+ android:layout_weight="1"
+ android:layout_marginLeft="-3dip"
+ android:layout_marginRight="-3dip"
+ android:paddingBottom="8dp"
android:background="@android:drawable/tab_indicator_holo">
- <View android:id="@+id/tab_indicator_left_spacer"
- android:layout_width="16dip"
- android:layout_height="0dip" />
-
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:visibility="gone"
- android:layout_toRightOf="@id/tab_indicator_left_spacer"
- android:paddingRight="8dip" />
+ android:layout_centerHorizontal="true" />
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@id/icon"
- android:paddingLeft="0dip"
- android:paddingRight="16dip"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
style="?android:attr/tabWidgetStyle" />
-
+
</RelativeLayout>
diff --git a/core/res/res/layout/tab_indicator_holo_large.xml b/core/res/res/layout/tab_indicator_holo_large.xml
new file mode 100644
index 0000000..bdd8d11
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_holo_large.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="56dip"
+ android:layout_weight="0"
+ android:layout_marginLeft="0dip"
+ android:layout_marginRight="0dip"
+ android:background="@android:drawable/tab_indicator_holo">
+
+ <View android:id="@+id/tab_indicator_left_spacer"
+ android:layout_width="16dip"
+ android:layout_height="0dip" />
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:visibility="gone"
+ android:layout_toRightOf="@id/tab_indicator_left_spacer"
+ android:paddingRight="8dip" />
+
+ <TextView android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@id/icon"
+ android:paddingLeft="0dip"
+ android:paddingRight="16dip"
+ style="?android:attr/tabWidgetStyle" />
+
+</RelativeLayout>
diff --git a/core/res/res/values-xlarge/styles.xml b/core/res/res/values-xlarge/styles.xml
index dd78920..a39d9d6 100644
--- a/core/res/res/values-xlarge/styles.xml
+++ b/core/res/res/values-xlarge/styles.xml
@@ -36,6 +36,22 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="TextAppearance.Holo.Widget.TabWidget">
+ <item name="android:textSize">18sp</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">@android:color/tab_indicator_text</item>
+ </style>
+
+ <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
+ <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
+ <item name="android:tabStripLeft">@null</item>
+ <item name="android:tabStripRight">@null</item>
+ <item name="android:tabStripEnabled">false</item>
+ <item name="android:divider">@null</item>
+ <item name="android:gravity">left|center_vertical</item>
+ <item name="android:tabLayout">@android:layout/tab_indicator_holo_large</item>
+ </style>
+
<style name="PreferencePanel">
<item name="android:layout_marginLeft">@dimen/preference_screen_side_margin</item>
<item name="android:layout_marginRight">@dimen/preference_screen_side_margin</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c81f8c0..e2c440a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3817,6 +3817,7 @@
<li>"state_rect"
<li>"state_grow"
<li>"state_move"
+ <li>"state_hovered"
</ul> -->
<declare-styleable name="DrawableStates">
<!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable},
@@ -3866,6 +3867,9 @@
ignored even if it specifies a solid color, since that optimization
is not needed. -->
<attr name="state_accelerated" format="boolean" />
+ <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable},
+ set when a pointer is hovering over the view. -->
+ <attr name="state_hovered" format="boolean" />
</declare-styleable>
<declare-styleable name="ViewDrawableStates">
<attr name="state_pressed" />
@@ -3875,6 +3879,7 @@
<attr name="state_enabled" />
<attr name="state_activated" />
<attr name="state_accelerated" />
+ <attr name="state_hovered" />
</declare-styleable>
<!-- State array representing a menu item that is currently checked. -->
<declare-styleable name="MenuItemCheckedState">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f1ec398..5432212 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1648,4 +1648,11 @@
<eat-comment />
<public type="attr" name="textCursorDrawable" id="0x01010362" />
<public type="attr" name="resizeMode" />
+
+<!-- ===============================================================
+ Resources added in version 13 of the platform (Ice Cream Sandwich)
+ =============================================================== -->
+ <eat-comment />
+ <public type="attr" name="state_hovered" />
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 08f5410..f7d3c3f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1214,8 +1214,10 @@
<item name="android:textColor">?textColorPrimary</item>
</style>
+ <!-- This style is for smaller screens; values-xlarge defines a version
+ for larger screens. -->
<style name="TextAppearance.Holo.Widget.TabWidget">
- <item name="android:textSize">18sp</item>
+ <item name="android:textSize">14sp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@android:color/tab_indicator_text</item>
</style>
@@ -1664,6 +1666,9 @@
<item name="android:button">@android:drawable/btn_star_holo_dark</item>
</style>
+ <!-- The holo style for smaller screens actually uses the non-holo layout,
+ which is more compact. values-xlarge defines an alternative version
+ for the real holo look on a large screen. -->
<style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
<item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
<item name="android:tabStripLeft">@null</item>
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 5dedd4a..7f13791 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -60,6 +60,7 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.disable(adapter);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations);
@@ -78,7 +79,9 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
+ mTestUtils.undiscoverable(adapter);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
@@ -99,7 +102,9 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
+ mTestUtils.stopScan(adapter);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations);
@@ -116,7 +121,9 @@
public void testEnablePan() {
int iterations = BluetoothTestRunner.sEnablePanIterations;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
+ mTestUtils.disablePan(adapter);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
@@ -141,13 +148,15 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
+ mTestUtils.unpair(adapter, device);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations);
- mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
mTestUtils.unpair(adapter, device);
}
mTestUtils.disable(adapter);
@@ -162,13 +171,15 @@
public void testAcceptPair() {
int iterations = BluetoothTestRunner.sPairIterations;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
+ mTestUtils.unpair(adapter, device);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations);
- mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
mTestUtils.unpair(adapter, device);
}
mTestUtils.disable(adapter);
@@ -187,15 +198,20 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sA2dpAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
- mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP, null);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP);
- mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
+ mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP,
+ String.format("connectA2dp(device=%s)", device));
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP,
+ String.format("disconnectA2dp(device=%s)", device));
}
mTestUtils.unpair(adapter, device);
@@ -215,15 +231,20 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
- mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
- mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+ mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET,
+ String.format("connectHeadset(device=%s)", device));
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET,
+ String.format("disconnectHeadset(device=%s)", device));
}
mTestUtils.unpair(adapter, device);
@@ -243,15 +264,20 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
- mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE, null);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
- mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
+ mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+ String.format("connectInput(device=%s)", device));
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+ String.format("disconnectInput(device=%s)", device));
}
mTestUtils.unpair(adapter, device);
@@ -271,10 +297,12 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
- mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
@@ -299,11 +327,14 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
+ mTestUtils.disablePan(adapter);
mTestUtils.enablePan(adapter);
- mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
@@ -330,11 +361,15 @@
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.disable(adapter);
mTestUtils.enable(adapter);
- mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
- BluetoothTestRunner.sPairPin);
- mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+ BluetoothTestRunner.sDevicePairPin);
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+ mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+ mTestUtils.stopSco(adapter, device);
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
@@ -342,7 +377,7 @@
mTestUtils.stopSco(adapter, device);
}
- mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
mTestUtils.unpair(adapter, device);
mTestUtils.disable(adapter);
}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 1febc5c..64d2c12 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -65,14 +65,9 @@
public static int sConnectPanIterations = 100;
public static int sStartStopScoIterations = 100;
- public static String sPairAddress = "";
- public static String sHeadsetAddress = "";
- public static String sA2dpAddress = "";
- public static String sInputAddress = "";
- public static String sPanAddress = "";
-
- public static byte[] sPairPin = {'1', '2', '3', '4'};
- public static int sPairPasskey = 123456;
+ public static String sDeviceAddress = "";
+ public static byte[] sDevicePairPin = {'1', '2', '3', '4'};
+ public static int sDevicePairPasskey = 123456;
@Override
public TestSuite getAllTests() {
@@ -177,40 +172,24 @@
// Invalid argument, fall back to default value
}
}
- val = arguments.getString("pair_address");
+
+ val = arguments.getString("device_address");
if (val != null) {
- sPairAddress = val;
+ sDeviceAddress = val;
}
- val = arguments.getString("headset_address");
+ val = arguments.getString("device_pair_pin");
if (val != null) {
- sHeadsetAddress = val;
+ byte[] pin = BluetoothDevice.convertPinToBytes(val);
+ if (pin != null) {
+ sDevicePairPin = pin;
+ }
}
- val = arguments.getString("a2dp_address");
- if (val != null) {
- sA2dpAddress = val;
- }
-
- val = arguments.getString("input_address");
- if (val != null) {
- sInputAddress = val;
- }
-
- val = arguments.getString("pan_address");
- if (val != null) {
- sPanAddress = val;
- }
-
- val = arguments.getString("pair_pin");
- if (val != null) {
- sPairPin = BluetoothDevice.convertPinToBytes(val);
- }
-
- val = arguments.getString("pair_passkey");
+ val = arguments.getString("device_pair_passkey");
if (val != null) {
try {
- sPairPasskey = Integer.parseInt(val);
+ sDevicePairPasskey = Integer.parseInt(val);
} catch (NumberFormatException e) {
// Invalid argument, fall back to default value
}
@@ -225,13 +204,9 @@
Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations));
- Log.i(TAG, String.format("pair_address=%s", sPairAddress));
- Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
- Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
- Log.i(TAG, String.format("input_address=%s", sInputAddress));
- Log.i(TAG, String.format("pan_address=%s", sPanAddress));
- Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
- Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
+ Log.i(TAG, String.format("device_address=%s", sDeviceAddress));
+ Log.i(TAG, String.format("device_pair_pin=%s", new String(sDevicePairPin)));
+ Log.i(TAG, String.format("device_pair_passkey=%d", sDevicePairPasskey));
// Call onCreate last since we want to set the static variables first.
super.onCreate(arguments);
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 1741119..f1dd8fe 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -37,44 +37,21 @@
public class BluetoothTestUtils extends Assert {
- /**
- * Timeout for enable/disable in ms.
- */
+ /** Timeout for enable/disable in ms. */
private static final int ENABLE_DISABLE_TIMEOUT = 20000;
-
- /**
- * Timeout for discoverable/undiscoverable in ms.
- */
+ /** Timeout for discoverable/undiscoverable in ms. */
private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
-
- /**
- * Timeout for starting/stopping a scan in ms.
- */
+ /** Timeout for starting/stopping a scan in ms. */
private static final int START_STOP_SCAN_TIMEOUT = 5000;
-
- /**
- * Timeout for pair/unpair in ms.
- */
+ /** Timeout for pair/unpair in ms. */
private static final int PAIR_UNPAIR_TIMEOUT = 20000;
-
- /**
- * Timeout for connecting/disconnecting a profile in ms.
- */
+ /** Timeout for connecting/disconnecting a profile in ms. */
private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
-
- /**
- * Timeout to connect a profile proxy in ms.
- */
- private static final int CONNECT_PROXY_TIMEOUT = 5000;
-
- /**
- * Timeout to start or stop a SCO channel in ms.
- */
+ /** Timeout to start or stop a SCO channel in ms. */
private static final int START_STOP_SCO_TIMEOUT = 10000;
-
- /**
- * Time between polls in ms.
- */
+ /** Timeout to connect a profile proxy in ms. */
+ private static final int CONNECT_PROXY_TIMEOUT = 5000;
+ /** Time between polls in ms. */
private static final int POLL_TIME = 100;
private abstract class FlagReceiver extends BroadcastReceiver {
@@ -249,6 +226,9 @@
case BluetoothProfile.INPUT_DEVICE:
mConnectionAction = BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED;
break;
+ case BluetoothProfile.PAN:
+ mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
+ break;
default:
mConnectionAction = null;
}
@@ -281,47 +261,22 @@
}
}
- private class ConnectPanReceiver extends FlagReceiver {
- private static final int STATE_DISCONNECTED_FLAG = 1;
- private static final int STATE_CONNECTING_FLAG = 1 << 1;
- private static final int STATE_CONNECTED_FLAG = 1 << 2;
- private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
-
- private BluetoothDevice mDevice;
+ private class ConnectPanReceiver extends ConnectProfileReceiver {
private int mRole;
public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
- super (expectedFlags);
+ super(device, BluetoothProfile.PAN, expectedFlags);
- mDevice = device;
mRole = role;
}
@Override
public void onReceive(Context context, Intent intent) {
- if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
- || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+ if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
return;
}
- if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
- int state = intent.getIntExtra(BluetoothPan.EXTRA_STATE, -1);
- assertNotSame(-1, state);
- switch (state) {
- case BluetoothPan.STATE_DISCONNECTED:
- setFiredFlag(STATE_DISCONNECTED_FLAG);
- break;
- case BluetoothPan.STATE_CONNECTING:
- setFiredFlag(STATE_CONNECTING_FLAG);
- break;
- case BluetoothPan.STATE_CONNECTED:
- setFiredFlag(STATE_CONNECTED_FLAG);
- break;
- case BluetoothPan.STATE_DISCONNECTING:
- setFiredFlag(STATE_DISCONNECTING_FLAG);
- break;
- }
- }
+ super.onReceive(context, intent);
}
}
@@ -353,6 +308,7 @@
private BluetoothProfile.ServiceListener mServiceListener =
new BluetoothProfile.ServiceListener() {
+ @Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
synchronized (this) {
switch (profile) {
@@ -372,6 +328,7 @@
}
}
+ @Override
public void onServiceDisconnected(int profile) {
synchronized (this) {
switch (profile) {
@@ -399,10 +356,10 @@
private String mOutputFile;
private Context mContext;
- private BluetoothA2dp mA2dp;
- private BluetoothHeadset mHeadset;
- private BluetoothInputDevice mInput;
- private BluetoothPan mPan;
+ private BluetoothA2dp mA2dp = null;
+ private BluetoothHeadset mHeadset = null;
+ private BluetoothInputDevice mInput = null;
+ private BluetoothPan mPan = null;
/**
* Creates a utility instance for testing Bluetooth.
@@ -818,10 +775,15 @@
byte[] pin, boolean shouldPair) {
int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
long start = -1;
- String methodName = shouldPair ? "pair()" : "acceptPair()";
+ String methodName;
+ if (shouldPair) {
+ methodName = String.format("pair(device=%s)", device);
+ } else {
+ methodName = String.format("acceptPair(device=%s)", device);
+ }
if (!adapter.isEnabled()) {
- fail(methodName + " bluetooth not enabled");
+ fail(String.format("%s bluetooth not enabled", methodName));
}
PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
@@ -843,8 +805,7 @@
return;
default:
removeReceiver(receiver);
- fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
- state));
+ fail(String.format("%s invalid state: state=%d", methodName, state));
}
long s = System.currentTimeMillis();
@@ -854,10 +815,10 @@
assertTrue(adapter.getBondedDevices().contains(device));
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
- (finish - start), device));
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
} else {
- writeOutput(String.format("%s completed: device=%s", methodName, device));
+ writeOutput(String.format("%s completed", methodName));
}
removeReceiver(receiver);
return;
@@ -867,9 +828,8 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
- + "flags=0x%x (expected 0x%x)", methodName, device, state,
- BluetoothDevice.BOND_BONDED, firedFlags, mask));
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+ methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
}
/**
@@ -882,9 +842,10 @@
public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
int mask = PairReceiver.STATE_NONE_FLAG;
long start = -1;
+ String methodName = String.format("unpair(device=%s)", device);
if (!adapter.isEnabled()) {
- fail("unpair() bluetooth not enabled");
+ fail(String.format("%s bluetooth not enabled", methodName));
}
PairReceiver receiver = getPairReceiver(device, 0, null, mask);
@@ -906,7 +867,7 @@
break;
default:
removeReceiver(receiver);
- fail(String.format("unpair() invalid state: device=%s, state=%d", device, state));
+ fail(String.format("%s invalid state: state=%d", methodName, state));
}
long s = System.currentTimeMillis();
@@ -916,10 +877,10 @@
assertFalse(adapter.getBondedDevices().contains(device));
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
- writeOutput(String.format("unpair() completed in %d ms: device=%s",
- (finish - start), device));
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
} else {
- writeOutput(String.format("unpair() completed: device=%s", device));
+ writeOutput(String.format("%s completed", methodName));
}
removeReceiver(receiver);
return;
@@ -928,9 +889,8 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("unpair() timeout: device=%s, state=%d (expected %d), "
- + "flags=0x%x (expected 0x%x)", device, state, BluetoothDevice.BOND_BONDED,
- firedFlags, mask));
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+ methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
}
/**
@@ -939,29 +899,30 @@
*
* @param adapter The BT adapter.
* @param device The remote device.
- * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
- * {@link BluetoothProfile#HEADSET}.
+ * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
+ * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
+ * @param methodName The method name to printed in the logs. If null, will be
+ * "connectProfile(profile=<profile>, device=<device>)"
*/
- public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
+ public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
+ String methodName) {
+ if (methodName == null) {
+ methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
+ }
int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
| ConnectProfileReceiver.STATE_CONNECTED_FLAG);
long start = -1;
if (!adapter.isEnabled()) {
- fail(String.format("connectProfile() bluetooth not enabled: device=%s, profile=%d",
- device, profile));
+ fail(String.format("%s bluetooth not enabled", methodName));
}
if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("connectProfile() device not paired: device=%s, profile=%d",
- device, profile));
+ fail(String.format("%s device not paired", methodName));
}
BluetoothProfile proxy = connectProxy(adapter, profile);
- if (proxy == null) {
- fail(String.format("connectProfile() unknown profile: device=%s, profile=%d",
- device, profile));
- }
+ assertNotNull(proxy);
ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
@@ -980,8 +941,7 @@
break;
default:
removeReceiver(receiver);
- fail(String.format("connectProfile() invalid state: device=%s, profile=%d, "
- + "state=%d", device, profile, state));
+ fail(String.format("%s invalid state: state=%d", methodName, state));
}
long s = System.currentTimeMillis();
@@ -991,11 +951,10 @@
&& (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
- writeOutput(String.format("connectProfile() completed in %d ms: "
- + "device=%s, profile=%d", (finish - start), device, profile));
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
} else {
- writeOutput(String.format("connectProfile() completed: device=%s, "
- + "profile=%d", device, profile));
+ writeOutput(String.format("%s completed", methodName));
}
removeReceiver(receiver);
return;
@@ -1005,9 +964,8 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("connectProfile() timeout: device=%s, profile=%s, "
- + "state=%d (expected %d), flags=0x%x (expected 0x%x)", device, profile, state,
- BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+ methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
}
/**
@@ -1016,29 +974,30 @@
*
* @param adapter The BT adapter.
* @param device The remote device.
- * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
- * {@link BluetoothProfile#HEADSET}.
+ * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP},
+ * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
+ * @param methodName The method name to printed in the logs. If null, will be
+ * "connectProfile(profile=<profile>, device=<device>)"
*/
- public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
+ public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
+ String methodName) {
+ if (methodName == null) {
+ methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
+ }
int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
| ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
long start = -1;
if (!adapter.isEnabled()) {
- fail(String.format("disconnectProfile() bluetooth not enabled: device=%s, profile=%d",
- device, profile));
+ fail(String.format("%s bluetooth not enabled", methodName));
}
if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("disconnectProfile() device not paired: device=%s, profile=%d",
- device, profile));
+ fail(String.format("%s device not paired", methodName));
}
BluetoothProfile proxy = connectProxy(adapter, profile);
- if (proxy == null) {
- fail(String.format("disconnectProfile() unknown profile: device=%s, profile=%d",
- device, profile));
- }
+ assertNotNull(proxy);
ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
@@ -1057,8 +1016,7 @@
break;
default:
removeReceiver(receiver);
- fail(String.format("disconnectProfile() invalid state: device=%s, profile=%d, "
- + "state=%d", device, profile, state));
+ fail(String.format("%s invalid state: state=%d", methodName, state));
}
long s = System.currentTimeMillis();
@@ -1068,11 +1026,10 @@
&& (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
- writeOutput(String.format("disconnectProfile() completed in %d ms: "
- + "device=%s, profile=%d", (finish - start), device, profile));
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
} else {
- writeOutput(String.format("disconnectProfile() completed: device=%s, "
- + "profile=%d", device, profile));
+ writeOutput(String.format("%s completed", methodName));
}
removeReceiver(receiver);
return;
@@ -1082,9 +1039,8 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("disconnectProfile() timeout: device=%s, profile=%s, "
- + "state=%d (expected %d), flags=0x%x (expected 0x%x)", device, profile, state,
- BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+ methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
}
/**
@@ -1125,25 +1081,25 @@
String methodName;
if (connect) {
- methodName = "connectPan()";
- mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
- ConnectPanReceiver.STATE_CONNECTING_FLAG);
+ methodName = String.format("connectPan(device=%s)", device);
+ mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
+ ConnectProfileReceiver.STATE_CONNECTING_FLAG);
role = BluetoothPan.LOCAL_PANU_ROLE;
} else {
- methodName = "incomingPanConnection()";
- mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+ methodName = String.format("incomingPanConnection(device=%s)", device);
+ mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
role = BluetoothPan.LOCAL_NAP_ROLE;
}
if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+ fail(String.format("%s bluetooth not enabled", methodName));
}
if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired: device=%s", methodName, device));
+ fail(String.format("%s device not paired", methodName));
}
- if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+ mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
assertNotNull(mPan);
ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
@@ -1165,8 +1121,7 @@
break;
default:
removeReceiver(receiver);
- fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
- state));
+ fail(String.format("%s invalid state: state=%d", methodName, state));
}
long s = System.currentTimeMillis();
@@ -1176,10 +1131,10 @@
&& (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
- (finish - start), device));
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
} else {
- writeOutput(String.format("%s completed: device=%s", methodName, device));
+ writeOutput(String.format("%s completed", methodName));
}
removeReceiver(receiver);
return;
@@ -1189,9 +1144,8 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
- + "flags=0x%x (expected 0x%s)", methodName, device, state,
- BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+ methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
}
/**
@@ -1232,25 +1186,25 @@
String methodName;
if (disconnect) {
- methodName = "disconnectPan()";
- mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
- ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+ methodName = String.format("disconnectPan(device=%s)", device);
+ mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
+ ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
role = BluetoothPan.LOCAL_PANU_ROLE;
} else {
- methodName = "incomingPanDisconnection()";
- mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+ methodName = String.format("incomingPanDisconnection(device=%s)", device);
+ mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
role = BluetoothPan.LOCAL_NAP_ROLE;
}
if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+ fail(String.format("%s bluetooth not enabled", methodName));
}
if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired: device=%s", methodName, device));
+ fail(String.format("%s device not paired", methodName));
}
- if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+ mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
assertNotNull(mPan);
ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
@@ -1271,8 +1225,7 @@
break;
default:
removeReceiver(receiver);
- fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
- state));
+ fail(String.format("%s invalid state: state=%d", methodName, state));
}
long s = System.currentTimeMillis();
@@ -1282,10 +1235,10 @@
&& (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
- (finish - start), device));
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
} else {
- writeOutput(String.format("%s completed: device=%s", methodName, device));
+ writeOutput(String.format("%s completed", methodName));
}
removeReceiver(receiver);
return;
@@ -1295,9 +1248,8 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
- + "flags=0x%x (expected 0x%s)", methodName, device, state,
- BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+ methodName, state, BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
}
/**
@@ -1335,29 +1287,26 @@
String methodName;
if (isStart) {
- methodName = "startSco()";
+ methodName = String.format("startSco(device=%s)", device);
mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
} else {
- methodName = "stopSco()";
+ methodName = String.format("stopSco(device=%s)", device);
mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
}
if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled: device=%s, start=%b", methodName, device,
- isStart));
+ fail(String.format("%s bluetooth not enabled", methodName));
}
if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired: device=%s, start=%b", methodName, device,
- isStart));
+ fail(String.format("%s device not paired", methodName));
}
AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
assertNotNull(manager);
if (!manager.isBluetoothScoAvailableOffCall()) {
- fail(String.format("%s device does not support SCO: device=%s, start=%b", methodName,
- device, isStart));
+ fail(String.format("%s device does not support SCO", methodName));
}
boolean isScoOn = manager.isBluetoothScoOn();
@@ -1376,8 +1325,7 @@
long s = System.currentTimeMillis();
while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
isScoOn = manager.isBluetoothScoOn();
- if ((isStart == isScoOn) &&
- (receiver.getFiredFlags() & mask) == mask) {
+ if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
if (start != -1 && finish != -1) {
writeOutput(String.format("%s completed in %d ms", methodName,
@@ -1393,7 +1341,7 @@
int firedFlags = receiver.getFiredFlags();
removeReceiver(receiver);
- fail(String.format("%s timeout: start=%b (expected %b), flags=0x%x (expected 0x%x)",
+ fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)",
methodName, isScoOn, isStart, firedFlags, mask));
}
@@ -1478,6 +1426,30 @@
}
private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ if (mA2dp != null) {
+ return mA2dp;
+ }
+ break;
+ case BluetoothProfile.HEADSET:
+ if (mHeadset != null) {
+ return mHeadset;
+ }
+ break;
+ case BluetoothProfile.INPUT_DEVICE:
+ if (mInput != null) {
+ return mInput;
+ }
+ break;
+ case BluetoothProfile.PAN:
+ if (mPan != null) {
+ return mPan;
+ }
+ break;
+ default:
+ return null;
+ }
adapter.getProfileProxy(mContext, mServiceListener, profile);
long s = System.currentTimeMillis();
switch (profile) {
diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java
index e627bb4..82af662e 100644
--- a/core/tests/coretests/src/android/os/MemoryFileTest.java
+++ b/core/tests/coretests/src/android/os/MemoryFileTest.java
@@ -20,13 +20,11 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class MemoryFileTest extends AndroidTestCase {
@@ -101,6 +99,25 @@
file.close();
}
+ // http://code.google.com/p/android/issues/detail?id=11415
+ public void testOutputStreamAdvances() throws IOException {
+ MemoryFile file = new MemoryFile("MemoryFileTest", 10);
+
+ OutputStream os = file.getOutputStream();
+ os.write(new byte[] { 1, 2, 3, 4, 5 });
+ os.write(new byte[] { -1, -1, 6, 7, 8, -1 }, 2, 3);
+ os.write(9);
+ try {
+ os.write(new byte[] { -1, -1 });
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ }
+
+ byte[] copy = new byte[file.length()];
+ file.readBytes(copy, 0, 0, file.length());
+ assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]", Arrays.toString(copy));
+ }
+
// Tests for the IndexOutOfBoundsException cases in read().
private void readIndexOutOfBoundsException(int offset, int count, String msg)
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index fa588cb..46763c2 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -364,7 +364,7 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot?>guide/market/billing/index.html">
<span class="en">In-app Billing</span></a>
- <span class="new">new!</span>
+ <span class="new">updated</span>
</div>
<ul>
<li><a href="<?cs var:toroot?>guide/market/billing/billing_about.html">
@@ -698,6 +698,9 @@
</li>
</ul>
<ul>
+ <li><a href="<?cs var:toroot ?>guide/practices/design/accessibility.html">
+ <span class="en">Designing for Accessibility</span>
+ </a> <span class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>guide/practices/design/performance.html">
<span class="en">Designing for Performance</span>
</a></li>
diff --git a/docs/html/guide/market/billing/billing_about.jd b/docs/html/guide/market/billing/billing_about.jd
index dac9738..5924170 100755
--- a/docs/html/guide/market/billing/billing_about.jd
+++ b/docs/html/guide/market/billing/billing_about.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -31,45 +25,6 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
+<p>Android Market In-app Billing has reached the final launch milestone and is now available to developers and users. You can now publish applications that use Android Market's in-app billing service, and users can make in-app purchases. To find out how to implement in-app billing in your applications, see the <a href="{@docRoot}guide/market/billing/index.html">documentation</a> and the <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
-<p>This documentation gives you an early look at the Android Market In-app Billing service. We are providing this documentation to help you get started designing your in-app billing implementation. </p>
-<p>In addition to this documentation, we are providing a <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a> that shows you how to implement in-app billing. Although you can compile the sample application, load it on a device, and run it, you cannot use it to make purchases at this time. In-app billing relies on version 2.3.0 (and higher) of the Android Market application, which may not be available yet.</p>
-
-<p>In the coming weeks we plan to launch the testing phase of the in-app billing release. Following the testing phase we will launch in-app billing to the general public (see table 1 for a summary of upcoming launch milestones).
-
-<p class="table-caption"><strong>Table 1.</strong> Summary of launch milestones for in-app billing.</p>
-
-<table>
-
-<tr>
-<th>Release Phase</th>
-<th>Android Market Application</th>
-<th>Description</th>
-</tr>
-<tr>
- <td>Early Development</td>
- <td>Version 2.3.0 not available</td>
- <td>Provides an early look at documentation and sample application.</td>
-</tr>
-<tr>
- <td>Test Development</td>
- <td>Version 2.3.0 available to developers and users</td>
- <td>In-app billing service allows static testing with reserved product IDs. You cannot publish applications that use in-app billing.</td>
-</tr>
-<tr>
- <td>Final Release</td>
- <td>Version 2.3.0 available to developers and users</td>
- <td>In-app billing service allows end-to-end testing of in-app billing. You can publish applications that use in-app billing.</td>
-</tr>
-
-</table>
-
-<p>During the testing phase we will release version 2.3.0 of the Android Market application. This will allow you to test your in-app billing implementation using the <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-static">reserved product IDs and test responses</a>. However, you will not be able to test end-to-end in-app purchases during the testing phase, and you will not be able to publish an application that uses in in-app billing. </p>
-
-<p>After the testing phase is complete, we will release in-app billing to the general public. This will enable you to perform end-to-end tests of your in-app billing implementation using your actual in-app products. You will also be able to publish applications that use in-app billing.</p>
-
-<p>This documentation may change in the coming weeks as we move from the preview phase to the testing phase of this beta release. Be sure to check this documentation frequently for updates.</p>
\ No newline at end of file
diff --git a/docs/html/guide/market/billing/billing_admin.jd b/docs/html/guide/market/billing/billing_admin.jd
index cd8f960..38099ee 100755
--- a/docs/html/guide/market/billing/billing_admin.jd
+++ b/docs/html/guide/market/billing/billing_admin.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -34,26 +28,29 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
-
<p>In-app billing frees you from processing financial transactions, but you still need to perform a few administrative tasks, including setting up and maintaining your product list on the publisher site, registering test accounts, and handling refunds when necessary.</p>
-<p>You must have an Android Market publisher account to set up a product list and register test accounts. And you must have a Google Checkout merchant account to issue refunds to your users. If you already have a publisher account on Android Market, you can use your existing account. You do not need to register for a new account to support in-app billing. If you do not have a publisher account, you can register as an Android Market developer and set up a publisher account at the Android Market <a href="http://market.android.com/publish">publisher site</a>. If you do not have a Google Checkout merchant account, you can register for one at the <a href="http://checkout.google.com">Google Checkout site</a>.</p>
+<p>You must have an Android Market publisher account to register test accounts. And you must have a Google Checkout Merchant account to create a product list and issue refunds to your users. If you already have a publisher account on Android Market, you can use your existing account. You do not need to register for a new account to support in-app billing. If you do not have a publisher account, you can register as an Android Market developer and set up a publisher account at the Android Market <a href="http://market.android.com/publish">publisher site</a>. If you do not have a Google Checkout Merchant account, you can register for one at the <a href="http://checkout.google.com">Google Checkout site</a>.</p>
<h2 id="billing-list-setup">Creating a Product List</h2>
-<p>The Android Market publisher site provides a product list for each of your published applications. You can sell an item using the in-app billing feature only if the item is listed on an application's product list. Each application has its own product list; you cannot sell items that are listed in another application's product list.</p>
+<p>The Android Market publisher site provides a product list for each of your published applications. You can sell an item using Android Market's in-app billing feature only if the item is listed on an application's product list. Each application has its own product list; you cannot sell items that are listed in another application's product list.</p>
-<p>A product list contains information about the items you are selling, such as a product id, product description, and price (see figure 1). The product list stores only metadata about the items you are selling in your application. It does not store any digital content. You are responsible for storing and delivering the digital content that you sell in your applications.</p>
+<p>You can access an application's product list by clicking the <strong>In-App Products</strong> link that appears under each of the applications that are listed for your publisher account (see figure 1). The <strong>In-App Products</strong> link appears only if you have a Google Checkout Merchant account and an application's manifest includes the <code>com.android.vending.BILLING</code> permission.</p>
-<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_product_list.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 1.</strong> An application's product list.</div>
-</div>
+<img src="{@docRoot}images/billing_product_list_entry.png" height="548" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> You can access an application's product list by clicking the <strong>In-App Products</strong> link.
+</p>
-<p>You can create a product list for a published application or a draft application that's been uploaded and saved to the Android Market site. However, the application's manifest must include the com.android.vending.BILLING permission. If an application's manifest does not include this permission, you will be able to edit existing items in the product list but you will not be able to add new items to the list. For more information, see <a href="#billing-permission">Modifying your application's AndroidManifest.xml file</a>.</p>
+<p>A product list contains information about the items you are selling, such as a product id, product description, and price (see figure 2). The product list stores only metadata about the items you are selling in your application. It does not store any digital content. You are responsible for storing and delivering the digital content that you sell in your applications.</p>
+
+<img src="{@docRoot}images/billing_product_list.png" height="560" id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> An application's product list.
+</p>
+
+<p>You can create a product list for a published application or a draft application that's been uploaded and saved to the Android Market site. However, you must have a Google Checkout Merchant account and the application's manifest must include the <code>com.android.vending.BILLING</code> permission. If an application's manifest does not include this permission, you will be able to edit existing items in the product list but you will not be able to add new items to the list. For more information, see <a href="#billing-permission">Modifying your application's AndroidManifest.xml file</a>.</p>
<p>To create a product list for an application, follow these steps:</p>
@@ -61,13 +58,13 @@
<li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
<li>In the <strong>All Android Market listings</strong> panel, under the application name, click <strong>In-app Products</strong>.</li>
<li>On the In-app Products List page, click <strong>Add in-app product</strong>.</li>
- <li>On the Create New In-app Product page (see figure 2), provide details about the item you are selling and then click <strong>Save</strong>.</li>
+ <li>On the Create New In-app Product page (see figure 3), provide details about the item you are selling and then click <strong>Save</strong>.</li>
</ol>
-<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_list_form.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 2.</strong> The Create New In-app Product page lets you add items to an application's product list.</div>
-</div>
+<img src="{@docRoot}images/billing_list_form.png" height="840" id="figure3" />
+<p class="img-caption">
+ f<strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an application's product list.
+</p>
<p>You must enter the following information for each item in a product list:</p>
<ul>
@@ -79,23 +76,26 @@
<p>The purchase type can be "managed per user account" or "unmanaged." You can specify an item's purchase type only through the publisher site and you can never change an item's purchase type once you specify it. For more information, see <a href="#billing_purchase_type">Choosing a purchase type</a> later in this document.</p>
</li>
<li><strong>Publishing State</strong>
- <p>An item's publishing state can be "published" or "unpublished." However, to be visible to a user during checkout, an item's publishing state must be set to "published" and the item's application must be published on Android Market. (Note: This is not true for test accounts: that is, an item is visible to a trusted tester if the application is not published and the item is published. See <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">Testing In-app Billing</a> for more information.)</p>
+ <p>An item's publishing state can be "published" or "unpublished." However, to be visible to a user during checkout, an item's publishing state must be set to "published" and the item's application must be published on Android Market.</p>
+ <p class="note"><strong>Note:</strong> This is not true for test accounts. An item is visible to a test account if the application is not published and the item is published. See <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">Testing In-app Billing</a> for more information.</p>
</li>
<li><strong>Language</strong>
<p>A product list inherits its language from the parent application.</p>
</li>
<li><strong>Title</strong>
- <p>The title is a short descriptor for the item. For example, "sleeping potion." Titles must be unique across an application's namespace. Every item must have a title. The title is visible to users during checkout.</p>
+ <p>The title is a short descriptor for the item. For example, "Sleeping potion." Titles must be unique across an application's namespace. Every item must have a title. The title is visible to users during checkout. For optimum appearance, titles should be no longer than 25 characters; however, titles can be up to 55 characters in length.</p>
</li>
<li><strong>Description</strong>
- <p>The description is a long descriptor for the item. For example, "Instantly puts creatures to sleep. Does not work on angry elves." Every item must have a description. The description is visible to users during checkout.</p>
+ <p>The description is a long descriptor for the item. For example, "Instantly puts creatures to sleep. Does not work on angry elves." Every item must have a description. The description is visible to users during checkout. Descriptions can be up to 80 characters in length.</p>
</li>
<li><strong>Price</strong>
- <p>Every item must have a price greater than zero; you cannot sell free items.</p>
+ <p>Every item must have a price greater than zero; you cannot set a price of "0" (free).</p>
</li>
</ul>
-<p class="note"><strong>Note</strong>: Be sure to plan your product ID namespace. You cannot reuse or modify product IDs after you save them.</p>
+<p>For more information about product IDs and product lists, see <a href="http://market.android.com/support/bin/answer.py?answer=1072599">Creating In-App Product IDs</a>. For more information about pricing, see <a href="http://market.android.com/support/bin/answer.py?answer=1153485">In-App Billing Pricing</a>.</p>
+
+<p class="note"><strong>Note</strong>: Be sure to plan your product ID namespace. You cannot reuse or modify product IDs after you save them.</p>
<h3 id="billing-purchase-type">Choosing a Purchase Type</h3>
@@ -113,7 +113,7 @@
<h2 id="billing-refunds">Handling Refunds</h2>
-<p>The in-app billing feature does not allow users to send a refund request to Android Market. Refunds for purchases that were made with the in-app billing feature must be directed to you (the application developer). You can then process the refund through your Google Checkout merchant account. When you do this, Android Market receives a refund notification from Google Checkout, and Android Market sends a refund message to your application. Your application can handle this message the same way it handles the response from an application-initiated <code>REQUEST_PURCHASE</code> message so that ultimately your application receives a purchase state change message that includes information about the item that's been refunded.</p>
+<p>In-app billing does not allow users to send a refund request to Android Market. Refunds for in-app purchases must be directed to you (the application developer). You can then process the refund through your Google Checkout Merchant account. When you do this, Android Market receives a refund notification from Google Checkout, and Android Market sends a refund message to your application. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling IN_APP_NOTIFY messages</a> and <a href="http://www.google.com/support/androidmarket/bin/answer.py?answer=1153485">In-app Billing Pricing</a>.</p>
<h2 id="billing-testing-setup">Setting Up Test Accounts</h2>
@@ -134,16 +134,15 @@
<ol>
<li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
<li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
- <li>On the Edit Profile page, scroll down to the Licensing & In-app Billing panel (see figure 3).</li>
+ <li>On the Edit Profile page, scroll down to the Licensing & In-app Billing panel (see figure 4).</li>
<li>In Test Accounts, add the email addresses for the test accounts you want to register, separating each account with a comma.</li>
<li>Click <strong>Save</strong> to save your profile changes.</li>
</ol>
-<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_public_key.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 3.</strong> The Licensing and In-app Billing
-panel of your account's Edit Profile page lets you register test accounts.</div>
-</div>
+<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure4" />
+<p class="img-caption">
+ <strong>Figure 4.</strong> The Licensing and In-app Billing panel of your account's Edit Profile page lets you register test accounts.
+</p>
<h2 id="billing-support">Where to Get Support</h2>
@@ -168,12 +167,6 @@
href="http://stackoverflow.com/questions/tagged/android">http://stackoverflow.com/questions/tagged/android</a></td>
</tr>
<tr>
-<td>Accounts, publishing, and deployment issues</td>
-<td><a href="http://www.google.com/support/forum/p/Android+Market">Android
-Market Help Forum</a></td>
-<td>Publisher accounts, Android Market key pair, test accounts, server responses, test responses, application deployment and results.</td>
-</tr>
-<tr>
<td>Market billing issue tracker</td>
<td><a href="http://code.google.com/p/marketbilling/issues/">Market billing
project issue tracker</a></td>
diff --git a/docs/html/guide/market/billing/billing_best_practices.jd b/docs/html/guide/market/billing/billing_best_practices.jd
index 4743e88..6f9f64c 100755
--- a/docs/html/guide/market/billing/billing_best_practices.jd
+++ b/docs/html/guide/market/billing/billing_best_practices.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -30,10 +24,7 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
-<p>As you design your in-app billing implementation, be sure to follow the security and design guidelines that are discussed in this document. These guidelines are recommended best practices for anyone who is using the Android Market In-app Billing service and can be incorporated into any in-app billing implementation.</p>
+<p>As you design your in-app billing implementation, be sure to follow the security and design guidelines that are discussed in this document. These guidelines are recommended best practices for anyone who is using Android Market's in-app billing service.</p>
<h2>Security Best Practices</h2>
@@ -58,7 +49,7 @@
</ul>
<p>Using these techniques can help reduce the attack surface of your application and help minimize attacks that can compromise your in-app billing implementation.</p>
<div class="note">
- <p><strong>Note:</strong> If you use Proguard to obfuscate your code, you must add the following line to your Proguard configuration file:</p>
+ <p><strong>Note:</strong> If you use Proguard to obfuscate your code, you must add the following line to your Proguard configuration file:</p>
<p><code>-keep class com.android.vending.billing.**</code></p>
</div>
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index 0cac2eb..26bda66 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -16,7 +10,7 @@
<li><a href="#billing-download">Downloading the Sample Application</a></li>
<li><a href="#billing-add-aidl">Adding the AIDL file to your project</a></li>
<li><a href="#billing-permission">Updating Your Application's Manifest</a></li>
- <li><a href="#billing-service">Creating a Service</a></li>
+ <li><a href="#billing-service">Creating a Service</a></li>
<li><a href="#billing-broadcast-receiver">Creating a BroadcastReceiver</a></li>
<li><a href="#billing-signatures">Creating a security processing component</a></li>
<li><a href="#billing-implement">Modifying Your Application Code</a></li>
@@ -36,11 +30,7 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
-
-<p>The Android Market In-app Billing service provides a straightforward, simple interface for sending in-app billing requests and managing in-app billing transactions using Android Market. This document helps you implement in-app billing by stepping through the primary implementation tasks, using the in-app billing sample application as an example.</p>
+<p>Android Market In-app Billing provides a straightforward, simple interface for sending in-app billing requests and managing in-app billing transactions using Android Market. This document helps you implement in-app billing by stepping through the primary implementation tasks, using the in-app billing sample application as an example.</p>
<p>Before you implement in-app billing in your own application, be sure that you read <a href="{@docRoot}guide/market/billing/billing_overview.html">Overview of In-app Billing</a> and <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>. These documents provide background information that will make it easier for you to implement in-app billing.</p>
@@ -57,7 +47,7 @@
<h2 id="billing-download">Downloading the Sample Application</h2>
-<p>The in-app billing sample application shows you how to perform several tasks that are common to all in-app billing implementations, including:</p>
+<p>The in-app billing sample application shows you how to perform several tasks that are common to all Android Market in-app billing implementations, including:</p>
<ul>
<li>Sending in-app billing requests to the Android Market application.</li>
@@ -67,11 +57,10 @@
<li>Creating a user interface that lets users select items for purchase.</li>
</ul>
-<p>The sample application includes an application file (<code><code>Dungeons.java</code></code>), the AIDL file for the <code>MarketBillingService</code> (<code>IMarketBillingService.aidl</code>), and several classes that demonstrate in-app billing messaging. It also includes a class that demonstrates basic security tasks, such as signature verification.</p>
+<p>The sample application includes an application file (<code>Dungeons.java</code>), the AIDL file for the <code>MarketBillingService</code> (<code>IMarketBillingService.aidl</code>), and several classes that demonstrate in-app billing messaging. It also includes a class that demonstrates basic security tasks, such as signature verification.</p>
<p>Table 1 lists the source files that are included with the sample application.</p>
-<p class="table-caption" id="source-files-table"><strong>Table 1.</strong>
-In-app billing sample application source files.</p>
+<p class="table-caption" id="source-files-table"><strong>Table 1.</strong> In-app billing sample application source files.</p>
<table>
<tr>
@@ -81,12 +70,12 @@
<tr>
<td>IMarketBillingService.aidl</td>
-<td>Android Interface Definition Library (AIDL) file that defines the IPC interface to the Android Market in-app billing service (<code>MarketBillingService</code>).</td>
+<td>Android Interface Definition Library (AIDL) file that defines the IPC interface to Android Market's in-app billing service (<code>MarketBillingService</code>).</td>
</tr>
<tr>
<td>Dungeons.java</td>
-<td>Sample application file that provides a UI for making purchases and diplaying purchase history.</td>
+<td>Sample application file that provides a UI for making purchases and displaying purchase history.</td>
</tr>
<tr>
@@ -130,22 +119,104 @@
</table>
-<p>The in-app billing sample application is available as a downloadable component of the Android SDK. To download the sample application component, launch the Android SDK and AVD Manager and then select the "Market Billing package, revision 1" component (see figure 1), and click <strong>Install Selected</strong> to begin the download.</p>
+<p>The in-app billing sample application is available as a downloadable component of the Android SDK. To download the sample application component, launch the Android SDK and AVD Manager and then select the "Google Market Billing package" component (see figure 1), and click <strong>Install Selected</strong> to begin the download.</p>
<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_package.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 1.</strong> The Google Market
-Billing package contains the sample application and the AIDL file. </div>
-</div>
+<img src="{@docRoot}images/billing_package.png" height="325" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> The Google Market Billing package contains the sample application and the AIDL file.
+</p>
<p>When the download is complete, the Android SDK and AVD Manager saves the component into the following directory:</p>
<p><code><sdk>/google-market_billing/</code></p>
+<p>If you want to see an end-to-end demonstration of in-app billing before you integrate in-app billing into your own application, you can build and run the sample application. Building and running the sample application involves three tasks:<p>
+
+<ul>
+ <li>Configuring and building the sample application.</li>
+ <li>Uploading the sample application to Android Market.</li>
+ <li>Setting up test accounts and running the sample application.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Building and running the sample application is necessary only if you want to see a demonstration of in-app billing. If you do not want to run the sample application, you can skip to the next section, <a href="#billing-add-aidl">Adding the AIDL file to your project</a>.</p>
+
+<h3>Configuring and building the sample application</h3>
+
+<p>Before you can run the sample application, you need to configure it and build it by doing the following:</p>
+
+<ol>
+ <li><strong>Add your Android Market public key to the sample application code.</strong>
+ <p>This enables the application to verify the signature of the transaction information that is returned from Android Market. To add your public key to the sample application code, do the following:</p>
+ <ol>
+ <li>Log in to your Android Market <a href="http://market.android.com/publish">publisher account</a>.</li>
+ <li>On the upper left part of the page, under your name, click <strong>Edit Profile</strong>.</li>
+ <li>On the Edit Profile page, scroll down to the <strong>Licensing & In-app Billing</strong> panel.</li>
+ <li>Copy your public key.</li>
+ <li>Open <code>src/com/example/dungeons/Security.java</code> in the editor of your choice.
+ <p>You can find this file in the sample application's project folder.</p>
+ </li>
+ <li>Add your public key to the following line of code:
+ <p><code>String base64EncodedPublicKey = "your public key here";</code></p>
+ </li>
+ <li>Save the file.</li>
+ </ol>
+ </li>
+ <li><strong>Change the package name of the sample application.</strong>
+ <p>The current package name is <code>com.example.dungeons</code>. Android Market does not let you upload applications with package names that contain <code>com.example</code>, so you must change the package name to something else.</p>
+ </li>
+ <li><strong>Build the sample application in release mode and sign it.</strong>
+ <p>To learn how to build and sign applications, see <a href="{@docRoot}guide/developing/building/index.html">Building and Running</a>.</p>
+ </li>
+</ol>
+
+<h3>Uploading the sample application</h3>
+
+<p>After you build a release version of the sample application and sign it, you need to upload it as a draft to the Android Market publisher site. You also need to create a product list for the in-app items that are available for purchase in the sample application. The following instructions show you how to do this.</p>
+<ol>
+ <li><strong>Upload the release version of the sample application to Android Market.</strong>
+ <p>Do not publish the sample application; leave it as an unpublished draft application. The sample application is for demonstration purposes only and should not be made publicly available on Android Market. To learn how to upload an application to Android Market, see <a href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading applications</a>.</p>
+ </li>
+ <li><strong>Create a product list for the sample application.</strong>
+ <p>The sample application lets you purchase two items: a two-handed sword (<code>sword_001</code>) and a potion (<code>potion_001</code>). We recommend that you set up your product list so that <code>sword_001</code> has a purchase type of "Managed per user account" and <code>potion_001</code> has a purchase type of "Unmanaged" so you can see how these two purchase types behave. To learn how to set up a product list, see <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-list-setup">Creating a Product List</a>.</p>
+ <p class="note"><strong>Note:</strong> You must publish the items in your product list (<code>sword_001</code> and <code>potion_001</code>) even though you are not publishing the sample application. Also, you must have a Google Checkout Merchant account to add items to the sample application's product list.</p>
+ </li>
+</ol>
+
+<h3>Running the sample application</h3>
+
+<p>You cannot run the sample application in the emulator. You must install the sample application onto a device to run it. To run the sample application, do the following:</p>
+
+<ol>
+ <li><strong>Make sure you have at least one test account registered under your Android Market publisher account.</strong>
+ <p>You cannot purchase items from yourself (Google Checkout prohibits this), so you need to create at least one test account that you can use to purchase items in the sample application. To learn how to set up a test account, see <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-setup">Setting up Test Accounts</a>.</p>
+ </li>
+ <li><strong>Verify that your device is running a supported version of the Android Market application or the MyApps application.</strong>
+ <p>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application. To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>.</p>
+ </li>
+ <li><strong>Install the application onto your device.</strong>
+ <p>Even though you uploaded the application to Android Market, the application is not published, so you cannot download it from Android Market to a device. Instead, you must install the application onto your device. To learn how to install an application onto a device, see <a href="{@docRoot}guide/developing/building/building-cmdline.html#RunningOnDevice">Running on a device</a>.</p>
+ </li>
+ <li><strong>Make one of your test accounts the primary account on your device.</strong>
+ <p>The primary account on your device must be one of the <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">test accounts</a> that you registered on the Android Market site. If the primary account on your device is not a test account, you must do a factory reset of the device and then sign in with one of your test accounts. To perform a factory reset, do the following:</p>
+ <ol>
+ <li>Open Settings on your device.</li>
+ <li>Touch <strong>Privacy</strong>.</li>
+ <li>Touch <strong>Factory data reset</strong>.</li>
+ <li>Touch <strong>Reset phone</strong>.</li>
+ <li>After the phone resets, be sure to sign in with one of your test accounts during the device setup process.</li>
+ </ol>
+ </li>
+ <li><strong>Run the application and purchase the sword or the potion.</strong>
+ <p>When you use a test account to purchase items, the test account is billed through Google Checkout and your Google Checkout Merchant account receives a payout for the purchase. Therefore, you may want to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.</p>
+</ol>
+
+<p class="note"><strong>Note</strong>: Debug log messages are turned off by default in the sample application. You can turn them on by setting the variable <code>DEBUG</code> to <code>true</code> in the <code>Consts.java</code> file.</p>
+
<h2 id="billing-add-aidl">Adding the AIDL file to your project</h2>
-<p>The sample application contains an Android Interface Definition Language (AIDL) file, which defines the interface to the Android Market in-app billing service <code>MarketBillingService</code>). When you add this file to your project, the Android build environment creates an interface file (<code>IMarketBillingService.java</code>). You can then use this interface to make billing requests by invoking IPC method calls.</p>
+<p>The sample application contains an Android Interface Definition Language (AIDL) file, which defines the interface to Android Market's in-app billing service (<code>MarketBillingService</code>). When you add this file to your project, the Android build environment creates an interface file (<code>IMarketBillingService.java</code>). You can then use this interface to make billing requests by invoking IPC method calls.</p>
<p>If you are using the ADT plug-in with Eclipse, you can just add this file to your <code>/src</code> directory. Eclipse will automatically generate the interface file when you build your project (which should happen immediately). If you are not using the ADT plug-in, you can put the AIDL file into your project and use the Ant tool to build your project so that the <code>IMarketBillingService.java</code> file gets generated.</p>
@@ -159,15 +230,15 @@
<li>Build your application.</li>
</ol>
-<p>You should now find a generated interface file named <code><code>IMarketBillingService.java</code></code> in the <code>gen</code> folder of your project.</p>
+<p>You should now find a generated interface file named <code>IMarketBillingService.java</code> in the <code>gen</code> folder of your project.</p>
<h2 id="billing-permission">Updating Your Application's Manifest</h2>
<p>In-app billing relies on the Android Market application, which handles all communication between your application and the Android Market server. To use the Android Market application, your application must request the proper permission. You can do this by adding the <code>com.android.vending.BILLING</code> permission to your AndroidManifest.xml file. If your application does not declare the in-app billing permission, but attempts to send billing requests, Android Market will refuse the requests and respond with a <code>RESULT_DEVELOPER_ERROR</code> response code.</p>
-<p>In addition to the billing permission, you need to declare the {@link android.content.BroadcastReceiver} that you will use to receive asynchronous response messages (broadcast intents) from Android Market, and you need to declare the {@link android.app.Service} that you will use to bind with the <code>IMarketBillingService</code> and send messages to Android Market. You must also declare <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filters</a> for the {@link android.content.BroadcastReceiver} so that the Android system knows how to handle broadcast intents that are sent from the Android Market application.</p>
+<p>In addition to the billing permission, you need to declare the {@link android.content.BroadcastReceiver} that you will use to receive asynchronous response messages (broadcast intents) from Android Market, and you need to declare the {@link android.app.Service} that you will use to bind with the <code>IMarketBillingService</code> and send messages to Android Market. You must also declare <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filters</a> for the {@link android.content.BroadcastReceiver} so that the Android system knows how to handle the broadcast intents that are sent from the Android Market application.</p>
-<p>For example, here's how the in-app billing sample application declares the billing permission, the {@link android.content.BroadcastReceiver}, the {@link android.app.Service}, and the intent filters. In the sample application, <code>BillingReceiver</code> is the {@link android.content.BroadcastReceiver} that handles broadcast intents from the Android Market application and <code>BillingService</code> is the {@link android.app.Service} that sends requests to the Android Market application.</p>
+<p>For example, here is how the in-app billing sample application declares the billing permission, the {@link android.content.BroadcastReceiver}, the {@link android.app.Service}, and the intent filters. In the sample application, <code>BillingReceiver</code> is the {@link android.content.BroadcastReceiver} that handles broadcast intents from the Android Market application and <code>BillingService</code> is the {@link android.app.Service} that sends requests to the Android Market application.</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
@@ -236,7 +307,7 @@
}
</pre>
-<p>After you bind to the service, you need to create a reference to the <code>IMarketBillingService</code> interface so you can make billing requests via IPC method calls. The following code shows you how to do this using the {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method.</p>
+<p>After you bind to the service, you need to create a reference to the <code>IMarketBillingService</code> interface so you can make billing requests via IPC method calls. The following code shows you how to do this using the {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method.</p>
<pre>
/**
@@ -265,7 +336,7 @@
<li><code>RESTORE_TRANSACTIONS</code>—retrieves a user's transaction history for <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">managed purchases</a>.</li>
</ul>
-<p>To make any of these billing requests, you first need to build an initial Bundle that contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The following code sample shows you how to create a helper method named <code>makeRequestBundle()</code> that does this.</p>
+<p>To make any of these billing requests, you first need to build an initial {@link android.os.Bundle} that contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The following code sample shows you how to create a helper method named <code>makeRequestBundle()</code> that does this.</p>
<pre>
protected Bundle makeRequestBundle(String method) {
@@ -296,13 +367,17 @@
<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The request returns a synchronous {@link android.os.Bundle} response, which contains only a single key: <code>RESPONSE_CODE</code>. The <code>RESPONSE_CODE</code> key can have the following values:</p>
<ul>
<li><code>RESULT_OK</code>—in-app billing is supported.</li>
- <li><code>RESULT_BILLING_UNAVAILABLE</code>—in-app billing is not supported or the in-app billing API version you specified is not recognized.</li>
- <li><code>RESULT_ERROR</code>—there was an error connecting with the Android Market appliction.</li>
- <li><code>RESULT_DEVELOPER_ERROR</code>—the application is trying to make an in-app billing request but the application has not declared the com.android.vending.BILLING permission in its manifest. Can also indicate that an application is not properly signed, or that you sent a malformed request.</li>
+ <li><code>RESULT_BILLING_UNAVAILABLE</code>—in-app billing is not available because the API version you specified is not recognized or the user is not eligible to make in-app purchases (for example, the user resides in a country that prohibits in-app purchases).</li>
+ <li><code>RESULT_ERROR</code>—there was an error connecting with the Android Market application.</li>
+ <li><code>RESULT_DEVELOPER_ERROR</code>—the application is trying to make an in-app billing request but the application has not declared the <code>com.android.vending.BILLING</code> permission in its manifest. Can also indicate that an application is not properly signed, or that you sent a malformed request.</li>
</ul>
<p>The <code>CHECK_BILLING_SUPPORTED</code> request does not trigger any asynchronous responses (broadcast intents).</p>
+<p>We recommend that you invoke the <code>CHECK_BILLING_SUPPORTED</code> request within a <code>RemoteException</code> block. When your code throws a <code>RemoteException</code> it indicates that the remote method call failed, which means that the Android Market application is out of date and needs to be updated. In this case, you can provide users with an error message that contains a link to the <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a> Help topic.</p>
+
+<p>The sample application demonstrates how you can handle this error condition (see <code>DIALOG_CANNOT_CONNECT_ID</code> in <code>Dungeons.java</code>).</p>
+
<h4>Making a purchase request (REQUEST_PURCHASE)</h4>
<p>To make a purchase request you must do the following:</p>
@@ -336,7 +411,7 @@
<h5>Launching the pending intent</h5>
-<p>How you use the pending intent depends on which version of Android a device is running. On Android 1.6, you must use the pending intent to launch the checkout UI in its own separate task instead of your application's activity stack. On Android 2.0 and higher, you can use the pending intent to launch the checkout UI on your application's activity stack. The following code shows you how to do this. You can find this code in the PurchaseObserver.java file in the sample application.</p>
+<p>How you use the pending intent depends on which version of Android a device is running. On Android 1.6, you must use the pending intent to launch the checkout UI in its own separate task instead of your application's activity stack. On Android 2.0 and higher, you can use the pending intent to launch the checkout UI on your application's activity stack. The following code shows you how to do this. You can find this code in the <code>PurchaseObserver.java</code> file in the sample application.</p>
<pre>
void startBuyPageActivity(PendingIntent pendingIntent, Intent intent) {
@@ -369,17 +444,17 @@
}
</pre>
-<p class="note">You must launch the pending intent from an activity context and not an application context.</p>
+<p class="caution"><strong>Important:</strong> You must launch the pending intent from an activity context and not an application context. Also, you cannot use the <code>singleTop</code> <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launch mode</a> to launch the pending intent. If you do either of these, the Android system will not attach the pending intent to your application process. Instead, it will bring Android Market to the foreground, disrupting your application.</p>
<h5>Handling broadcast intents</h5>
-<p>A <code>REQUEST_PURCHASE</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides error information about the request. Next, if the request was successful, the Android Market application sends an <code>ACTION_NOTIFY</code> broadcast intent. This message contains a notification ID, which you can use to retrieve the transaction details for the <code>REQUEST_PURCHASE</code> request.</p>
+<p>A <code>REQUEST_PURCHASE</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides error information about the request. Next, if the request was successful, the Android Market application sends an <code>IN_APP_NOTIFY</code> broadcast intent. This message contains a notification ID, which you can use to retrieve the transaction details for the <code>REQUEST_PURCHASE</code> request.</p>
-<p>Keep in mind, the Android Market application also sends an <code>ACTION_NOTIFY</code> for refunds. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling ACTION_NOTIFY messages</a>.</p>
+<p>Keep in mind, the Android Market application also sends an <code>IN_APP_NOTIFY</code> for refunds. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling IN_APP_NOTIFY messages</a>.</p>
<h4>Retrieving transaction information for a purchase or refund (GET_PURCHASE_INFORMATION)</h4>
-<p>You retrieve transaction information in response to an <code>ACTION_NOTIFY</code> broadcast intent. The <code>ACTION_NOTIFY</code> message contains a notification ID, which you can use to retrieve transaction information.</p>
+<p>You retrieve transaction information in response to an <code>IN_APP_NOTIFY</code> broadcast intent. The <code>IN_APP_NOTIFY</code> message contains a notification ID, which you can use to retrieve transaction information.</p>
<p>To retrieve transaction information for a purchase or refund you must specify five keys in the request {@link android.os.Bundle}. The following code sample shows how to set these keys and make the request. In the sample, <code>mService</code> is an instance of the <code>MarketBillingService</code> interface.</p>
@@ -394,11 +469,11 @@
// Do something with this response.
}
</pre>
-<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional keys are then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in the <code>ACTION_NOTIFY</code> broadcast intent.</p>
+<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional keys are then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the <code>PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in the <code>IN_APP_NOTIFY</code> broadcast intent.</p>
<p>The request returns a synchronous {@link android.os.Bundle} response, which contains two keys: <code>RESPONSE_CODE</code> and <code>REQUEST_ID</code>. The <code>RESPONSE_CODE</code> key provides you with the status of the request and the <code>REQUEST_ID</code> key provides you with a unique request identifier for the request.</p>
-<p>A <code>GET_PURCHASE_INFORMATION</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends an <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
+<p>A <code>GET_PURCHASE_INFORMATION</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends a <code>PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
<h4>Acknowledging transaction information (CONFIRM_NOTIFICATIONS)</h4>
@@ -414,11 +489,13 @@
// Do something with this response.
}
</pre>
-<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>NOTIFY_IDS</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in an <code>ACTION_NOTIFY</code> broadcast intent and also used in a <code>GET_PURCHASE_INFORMATION</code> request.</p>
+<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>NOTIFY_IDS</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in an <code>IN_APP_NOTIFY</code> broadcast intent and also used in a <code>GET_PURCHASE_INFORMATION</code> request.</p>
<p>The request returns a synchronous {@link android.os.Bundle} response, which contains two keys: <code>RESPONSE_CODE</code> and <code>REQUEST_ID</code>. The <code>RESPONSE_CODE</code> key provides you with the status of the request and the <code>REQUEST_ID</code> key provides you with a unique request identifier for the request.</p>
-<p>A <code>CONFIRM_NOTIFICATIONS</code> request triggers a single asynchronous response—an <code>ACTION_RESPONSE_CODE</code> broadcast intent. This broadcast intent provides status and error information about the request.</p>
+<p>A <code>CONFIRM_NOTIFICATIONS</code> request triggers a single asynchronous response—a <code>RESPONSE_CODE</code> broadcast intent. This broadcast intent provides status and error information about the request.</p>
+
+<p class="note"><strong>Note:</strong> As a best practice, you should not send a <code>CONFIRM_NOTIFICATIONS</code> request for a purchased item until you have delivered the item to the user. This way, if your application crashes or something else prevents your application from delivering the product, your application will still receive an <code>IN_APP_NOTIFY</code> broadcast intent from Android Market indicating that you need to deliver the product.</p>
<h4>Restoring transaction information (RESTORE_TRANSACTIONS)</h4>
@@ -434,29 +511,29 @@
// Do something with this response.
}
</pre>
-<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>REQUEST_NONCE</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the transactions information contained in the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information.</p>
+<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>REQUEST_NONCE</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the transactions information contained in the <code>PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information.</p>
<p>The request returns a synchronous {@link android.os.Bundle} response, which contains two keys: <code>RESPONSE_CODE</code> and <code>REQUEST_ID</code>. The <code>RESPONSE_CODE</code> key provides you with the status of the request and the <code>REQUEST_ID</code> key provides you with a unique request identifier for the request.</p>
-<p>A <code>RESTORE_TRANSACTIONS</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends an <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains the detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
+<p>A <code>RESTORE_TRANSACTIONS</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends a <code>PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains the detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
<h3>Other service tasks</h3>
-<p>You may also want your {@link android.app.Service} to receive intent messages from your {@link android.content.BroadcastReceiver}. You can use these intent messages to convey the information that was sent asynchronously from the Android Market application to your {@link android.content.BroadcastReceiver}. To see an example of how you can send and receive these intent messages, see the BillingReceiver.java and BillingService.java files in the sample application. You can use these samples as a basis for your own implementation. However, if you use any of the code from the sample application, be sure you follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
+<p>You may also want your {@link android.app.Service} to receive intent messages from your {@link android.content.BroadcastReceiver}. You can use these intent messages to convey the information that was sent asynchronously from the Android Market application to your {@link android.content.BroadcastReceiver}. To see an example of how you can send and receive these intent messages, see the <code>BillingReceiver.java</code> and <code>BillingService.java</code> files in the sample application. You can use these samples as a basis for your own implementation. However, if you use any of the code from the sample application, be sure you follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
<h2 id="billing-broadcast-receiver">Creating a BroadcastReceiver</h2>
<p>The Android Market application uses broadcast intents to send asynchronous billing responses to your application. To receive these intent messages, you need to create a {@link android.content.BroadcastReceiver} that can handle the following intents:</p>
<ul>
- <li>ACTION_RESPONSE_CODE
+ <li>com.android.vending.billing.RESPONSE_CODE
<p>This broadcast intent contains an Android Market response code, and is sent after you make an in-app billing request. For more information about the response codes that are sent with this response, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-codes">Android Market Response Codes for In-app Billing</a>.</p>
</li>
- <li>ACTION_NOTIFY
+ <li>com.android.vending.billing.IN_APP_NOTIFY
<p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. For more information about notification messages, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-intents">In-app Billing Broadcast Intents</a></p>
</li>
- <li>ACTION_PURCHASE_STATE_CHANGED
+ <li>com.android.vending.billing.PURCHASE_STATE_CHANGED
<p>This broadcast intent contains detailed information about one or more transactions. For more information about purchase state messages, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-intents">In-app Billing Broadcast Intents</a></p>
</li>
</ul>
@@ -473,28 +550,28 @@
<th>Description</th>
</tr>
<tr>
- <td><code>ACTION_RESPONSE_CODE</code></td>
- <td><code>INAPP_REQUEST_ID</code></td>
+ <td><code>com.android.vending.billing.RESPONSE_CODE</code></td>
+ <td><code>request_id</code></td>
<td>A <code>long</code> representing a request ID. A request ID identifies a specific billing request and is returned by Android Market at the time a request is made.</td>
</tr>
<tr>
- <td><code>ACTION_RESPONSE_CODE</code></td>
- <td><code>INAPP_RESPONSE_CODE</code></td>
+ <td><code>com.android.vending.billing.RESPONSE_CODE</code></td>
+ <td><code>response_code</code></td>
<td>An <code>int</code> representing the actual Android Market server response code.</td>
</tr>
<tr>
- <td><code>ACTION_NOTIFY</code></td>
- <td><code>NOTIFICATION_ID</code></td>
+ <td><code>com.android.vending.billing.IN_APP_NOTIFY</code></td>
+ <td><code>notification_id</code></td>
<td>A <code>String</code> representing the notification ID for a given purchase state change. Android Market notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the <code>GET_PURCHASE_INFORMATION</code> request.</td>
</tr>
<tr>
- <td><code>ACTION_PURCHASE_STATE_CHANGED</code></td>
- <td><code>INAPP_SIGNED_DATA</code></td>
+ <td><code>com.android.vending.billing.PURCHASE_STATE_CHANGED</code></td>
+ <td><code>inapp_signed_data</code></td>
<td>A <code>String</code> representing the signed JSON string. The JSON string contains information about the billing transaction, such as order number, amount, and the item that was purchased or refunded.</td>
</tr>
<tr>
- <td><code>ACTION_PURCHASE_STATE_CHANGED</code></td>
- <td><code>INAPP_SIGNATURE</code></td>
+ <td><code>com.android.vending.billing.PURCHASE_STATE_CHANGED</code></td>
+ <td><code>inapp_signature</code></td>
<td>A <code>String</code> representing the signature of the JSON string.</td>
</tr>
</table>
@@ -547,17 +624,17 @@
}
</pre>
-<p>In addition to receiving broadcast intents from the Android Market application, your {@link android.content.BroadcastReceiver} must handle the information it received in the broadcast intents. Usually, your {@link android.content.BroadcastReceiver} does this by sending the information to a local service (discussed in the next section). The BillingReceiver.java file in the sample application shows you how to do this. You can use this sample as a basis for your own {@link android.content.BroadcastReceiver}. However, if you use any of the code from the sample application, be sure you follow the guidelines that are discussed in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design </a>.</p>
+<p>In addition to receiving broadcast intents from the Android Market application, your {@link android.content.BroadcastReceiver} must handle the information it received in the broadcast intents. Usually, your {@link android.content.BroadcastReceiver} does this by sending the information to a local service (discussed in the next section). The <code>BillingReceiver.java</code> file in the sample application shows you how to do this. You can use this sample as a basis for your own {@link android.content.BroadcastReceiver}. However, if you use any of the code from the sample application, be sure you follow the guidelines that are discussed in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design </a>.</p>
<h2 id="billing-signatures">Verifying Signatures and Nonces</h2>
-<p>The in-app billing service uses two mechanisms to help verify the integrity of the transaction information you receive from Android Market: nonces and signatures. A nonce (number used once) is a cryptographically secure number that your application generates and sends with every <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent, enabling you to verify that any given <code>ACTION_PURCHASE_STATE_CHANGED</code> response corresponds to an actual request that you made. Every <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent also includes a signed JSON string and a signature, which you can use to verify the integrity of the response.</p>
+<p>Android Market's in-app billing service uses two mechanisms to help verify the integrity of the transaction information you receive from Android Market: nonces and signatures. A nonce (number used once) is a cryptographically secure number that your application generates and sends with every <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>PURCHASE_STATE_CHANGED</code> broadcast intent, enabling you to verify that any given <code>PURCHASE_STATE_CHANGED</code> response corresponds to an actual request that you made. Every <code>PURCHASE_STATE_CHANGED</code> broadcast intent also includes a signed JSON string and a signature, which you can use to verify the integrity of the response.</p>
<p>Your application must provide a way to generate, manage, and verify nonces. The following sample code shows some simple methods you can use to do this.</p>
<pre>
private static final SecureRandom RANDOM = new SecureRandom();
- private static HashSet<Long> sKnownNonces = new HashSet<Long>();
+ private static HashSet<Long> sKnownNonces = new HashSet<Long>();
public static long generateNonce() {
long nonce = RANDOM.nextLong();
@@ -574,7 +651,7 @@
}
</pre>
-<p>Your application must also provide a way to verify the signatures that accompany every <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. The Security.java file in the sample application shows you how to do this. If you use this file as a basis for your own security implementation, be sure to follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a> and obfuscate your code.</p>
+<p>Your application must also provide a way to verify the signatures that accompany every <code>PURCHASE_STATE_CHANGED</code> broadcast intent. The <code>Security.java</code> file in the sample application shows you how to do this. If you use this file as a basis for your own security implementation, be sure to follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a> and obfuscate your code.</p>
<p>You will need to use your Android Market public key to perform the signature verification. The following procedure shows you how to retrieve Base64-encoded public key from the Android Market publisher site.</p>
@@ -582,17 +659,17 @@
<li>Log in to your <a href="http://market.android.com/publish">publisher account</a>.</li>
<li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
<li>On the Edit Profile page, scroll down to the Licensing & In-app Billing panel (see figure 2).</li>
- <li>Copy your public key to the clipboard.</li>
+ <li>Copy your public key.</li>
</ol>
<p class="caution"><strong>Important</strong>: To keep your public key safe from malicious users and hackers, do not embed your public key as an entire literal string. Instead, construct the string at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but you do not want to make it easy for a hacker or malicious user to replace the public key with another key.</p>
<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_public_key.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 2.</strong> The Licensing and In-app Billing
-panel of your account's Edit Profile page lets you see your public key.</div>
-</div>
+<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> The Licensing and In-app Billing panel of your account's Edit Profile page lets you see your public key.
+</p>
<h2 id="billing-implement">Modifying Your Application Code</h2>
diff --git a/docs/html/guide/market/billing/billing_overview.jd b/docs/html/guide/market/billing/billing_overview.jd
index b899b9b..feac5b0 100755
--- a/docs/html/guide/market/billing/billing_overview.jd
+++ b/docs/html/guide/market/billing/billing_overview.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -19,7 +13,7 @@
<li><a href="#billing-request">Request messages</a></li>
<li><a href="#billing-response">Broadcast intents</a></li>
<li><a href="#billing-message-sequence">Messaging sequence</a></li>
- <li><a href="#billing-action-notify">Handling ACTION_NOTIFY messages</a></li>
+ <li><a href="#billing-action-notify">Handling IN_APP_NOTIFY messages</a></li>
</ol>
<li><a href="#billing-security">Security Controls</a></li>
<li><a href="#billing-limitations">Requirements and Limitations</a></li>
@@ -39,11 +33,7 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
-
-<p>The Android Market In-app Billing service is an Android Market feature that provides checkout processing for in-app purchases. To use the service, your application sends a billing request to the service for a specific in-app product. The service then handles all of the checkout details for the transaction, including requesting and validating the form of payment and processing the financial transaction. When the checkout process is complete, the service sends your application the purchase details, such as the order number, the order date and time, and the price paid. At no point does your application have to handle any financial transactions; that role is provided by the in-app billing service.</p>
+<p>Android Market In-app Billing is an Android Market service that provides checkout processing for in-app purchases. To use the service, your application sends a billing request for a specific in-app product. The service then handles all of the checkout details for the transaction, including requesting and validating the form of payment and processing the financial transaction. When the checkout process is complete, the service sends your application the purchase details, such as the order number, the order date and time, and the price paid. At no point does your application have to handle any financial transactions; that role is provided by Android Market's in-app billing service.</p>
<h2 id="billing-arch">In-app Billing Architecture</h2>
@@ -52,13 +42,14 @@
<p>Some in-app billing implementations may also use a private remote server to deliver content or validate transactions, but a remote server is not required to implement in-app billing. A remote server can be useful if you are selling digital content that needs to be delivered to a user's device, such as media files or photos. You might also use a remote server to store users' transaction history or perform various in-app billing security tasks, such as signature verification. Although you can handle all security-related tasks in your application, performing those tasks on a remote server is recommended because it helps make your application less vulnerable to security attacks.</p>
<div class="figure" style="width:440px">
-<img src="{@docRoot}images/billing_arch.png" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> Your application sends and receives billing messages through the Android Market application, which handles all communication with the Android Market server.</p>
+<img src="{@docRoot}images/billing_arch.png" alt="" height="582" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Your application sends and receives billing messages through the Android Market application, which handles all communication with the Android Market server.</p>
</div>
<p>A typical in-app billing implementation relies on three components:</p>
<ul>
- <li>A {@link android.app.Service} (named <code>BillingService</code> in the sample application), which processes purchase messages from the application and sends billing requests to the in-app billing service.</li>
+ <li>A {@link android.app.Service} (named <code>BillingService</code> in the sample application), which processes purchase messages from the application and sends billing requests to Android Market's in-app billing service.</li>
<li>A {@link android.content.BroadcastReceiver} (named <code>BillingReceiver</code> in the sample application), which receives all asynchronous billing responses from the Android Market application.</li>
<li>A security component (named <code>Security</code> in the sample application), which performs security-related tasks, such as signature verification and nonce generation. For more information about in-app billing security, see <a href="#billing-security">Security controls</a> later in this document.</li>
</ul>
@@ -73,15 +64,15 @@
<h2 id="billing-msgs">In-app Billing Messages</h2>
-<p>When the user initiates a purchase, your application sends billing messages to the in-app billing service (named <code>MarketBillingService</code>) using simple IPC method calls. The Android Market application responds to all billing requests synchronously, providing your application with status notifications and other information. The Android Market application also responds to some billing requests asynchronously, providing your application with error messages and detailed transaction information. The following section describes the basic request-response messaging that takes place between your application and the Android Market application.</p>
+<p>When the user initiates a purchase, your application sends billing messages to Android Market's in-app billing service (named <code>MarketBillingService</code>) using simple IPC method calls. The Android Market application responds to all billing requests synchronously, providing your application with status notifications and other information. The Android Market application also responds to some billing requests asynchronously, providing your application with error messages and detailed transaction information. The following section describes the basic request-response messaging that takes place between your application and the Android Market application.</p>
<h3 id="billing-request">In-app billing requests</h3>
-<p>Your application sends in-app billing requests by invoking a single IPC method (<code>sendBillingRequest()</code>), which is exposed by the <code>MarketBillingService</code> interface. This interface is defined in an <a href="{@docRoot}guide/developing/tools/aidl.html">Android Interface Definition Language</a> file (<code>IMarketBillingService.aidl</code>). You can download this AIDL file with the in-app billing sample application.</p>
+<p>Your application sends in-app billing requests by invoking a single IPC method (<code>sendBillingRequest()</code>), which is exposed by the <code>MarketBillingService</code> interface. This interface is defined in an <a href="{@docRoot}guide/developing/tools/aidl.html">Android Interface Definition Language</a> file (<code>IMarketBillingService.aidl</code>). You can <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">download</a> this AIDL file with the in-app billing sample application.</p>
<p>The <code>sendBillingRequest()</code> method has a single {@link android.os.Bundle} parameter. The Bundle that you deliver must include several key-value pairs that specify various parameters for the request, such as the type of billing request you are making, the item that is being purchased, and the application that is making the request. For more information about the Bundle keys that are sent with a request, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-interface">In-app Billing Service Interface</a>.
-<p>One of the most important keys that every request Bundle must have is the <code>BILLING_REQUEST</code> key. This key lets you specify the type of billing request you are making. The in-app billing service supports the following five types of billing requests:</p>
+<p>One of the most important keys that every request Bundle must have is the <code>BILLING_REQUEST</code> key. This key lets you specify the type of billing request you are making. Android Market's in-app billing service supports the following five types of billing requests:</p>
<ul>
<li><code>CHECK_BILLING_SUPPORTED</code>
@@ -97,7 +88,7 @@
<p>This request acknowledges that your application received the details of a purchase state change. Android Market sends purchase state change notifications to your application until you confirm that you received them.</p>
</li>
<li><code>RESTORE_TRANSACTIONS</code>
- <p>This request retrieves a user's transaction status for managed purchases (see <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">Choosing a Purchase Type</a> for more information). You should send this request only when you need to retrieve a user's transaction status, which is usually only when your application is reinstalled or installed for the first time on a device.</p>
+ <p>This request retrieves a user's transaction status for <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">managed purchases</a>. You should send this request only when you need to retrieve a user's transaction status, which is usually only when your application is reinstalled or installed for the first time on a device.</p>
</li>
</ul>
@@ -121,18 +112,18 @@
<p>The asynchronous response messages are sent in the form of individual broadcast intents and include the following:</p>
<ul>
- <li><code>ACTION_RESPONSE_CODE</code>
+ <li><code>com.android.vending.billing.RESPONSE_CODE</code>
<p>This response contains an Android Market server response code, and is sent after you make an in-app billing request. A server response code can indicate that a billing request was successfully sent to Android Market or it can indicate that some error occurred during a billing request. This response is <em>not</em> used to report any purchase state changes (such as refund or purchase information). For more information about the response codes that are sent with this response, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-codes">Server Response Codes for In-app Billing</a>.</p>
</li>
- <li><code>ACTION_NOTIFY</code>
- <p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>ACTION_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve message details.</p>
+ <li><code>com.android.vending.billing.IN_APP_NOTIFY</code>
+ <p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>IN_APP_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve message details.</p>
</li>
- <li><code>ACTION_PURCHASE_STATE_CHANGED</code>
+ <li><code>com.android.vending.billing.PURCHASE_STATE_CHANGED</code>
<p>This response contains detailed information about one or more transactions. The transaction information is contained in a JSON string. The JSON string is signed and the signature is sent to your application along with the JSON string (unencrypted). To help ensure the security of your in-app billing messages, your application can verify the signature of this JSON string.</p>
</li>
</ul>
-<p>The JSON string that is returned with the <code>ACTION_PURCHASE_STATE_CHANGED</code> intent provides your application with the details of one or more billing transactions. An example of this JSON string is shown below:</p>
+<p>The JSON string that is returned with the <code>PURCHASE_STATE_CHANGED</code> intent provides your application with the details of one or more billing transactions. An example of this JSON string is shown below:</p>
<pre class="no-pretty-print" style="color:black">
{ "nonce" : 1836535032137741465,
"orders" :
@@ -146,113 +137,85 @@
}
</pre>
-<p>The fields in the JSON string are described in the following table (see table 1):</p>
-
-<p class="table-caption"><strong>Table 1.</strong> Description of JSON fields that are returned with an <code>ACTION_PURCHASE_STATE_CHANGED</code> intent.</p>
-
-<table>
-
-<tr>
-<th>Field</th>
-<th>Description</th>
-</tr>
-<tr>
- <td>nonce</td>
- <td>A number used once. Your application generates the nonce and sends it with the <code>GET_PURCHASE_INFORMATION</code> request. Android Market sends the nonce back as part of the JSON string so you can verify the integrity of the message.</td>
-</tr>
-<tr>
- <td>notificationId</td>
- <td>A unique identifier that is sent with an <code>ACTION_NOTIFY</code> broadcast intent. Each <code>notificationId</code> corresponds to a specify message that is waiting to be retrieved on the Android Market server. Your application sends back the <code>notificationId</code> with the <code>GET_PURCHASE_INFORMATION</code> message so Android Market can determine which messages you are retrieving.</td>
-</tr>
-<tr>
- <td>orderId</td>
- <td>A unique order identifier for the transaction. This corresponds to the Google Checkout Order ID.</td>
-</tr>
-<tr>
- <td>packageName</td>
- <td>The application package from which the purchase originated.</td>
-</tr>
-<tr>
- <td>productId</td>
- <td>The item's product identifier. Every item has a product ID, which you must specify in the application's product list on the Android Market publisher site.</td>
-</tr>
-<tr>
- <td>purchaseTime</td>
- <td>The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).</td>
-</tr>
-
-<tr>
- <td>purchaseState</td>
- <td>The enum value for the purchase state, which indicates whether the purchase was successful, canceled, or refunded.</td>
-</tr>
-<tr>
- <td>developerPayload</td>
- <td>A developer-specified string that is associated with an order. This field is returned in the JSON string that contains transaction information for an order. You can use this field to send information with an order. For example, you can use this field to send index keys with an order, which is useful if you are using a database to store purchase information. We recommend that you do not use this field to send data or content.</td>
-</tr>
-</table>
+<p>For more information about the fields in this JSON string, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-intents">In-app Billing Broadcast Intents</a>.</p>
<h3 id="billing-message-sequence">Messaging sequence</h3>
-<p>The messaging sequence for a typical purchase request is shown in Figure 2. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, responses are shown in standard text. For clarity, Figure 2 does not show the <code>ACTION_RESPONSE_CODE</code> broadcast intents that are sent for every request. These responses provide status information or error information and are returned after each request.</p>
+<p>The messaging sequence for a typical purchase request is shown in figure 2. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, broadcast intents are shown in <em>italic</em>. For clarity, figure 2 does not show the <code>RESPONSE_CODE</code> broadcast intents that are sent for every request.</p>
<p>The basic message sequence for an in-app purchase request is as follows:</p>
<ol>
<li>Your application sends a purchase request (<code>REQUEST_PURCHASE</code> type), specifying a product ID and other parameters.</li>
- <li>The Android Market application sends your application a Bundle with a <code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and <code>REQUEST_ID</code>. The <code>PURCHASE_INTENT</code> provides a {@link android.app.PendingIntent}, which your application uses to start the checkout flow for the given product ID.</li>
+ <li>The Android Market application sends your application a Bundle with the following keys: <code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and <code>REQUEST_ID</code>. The <code>PURCHASE_INTENT</code> key provides a {@link android.app.PendingIntent}, which your application uses to start the checkout UI for the given product ID.</li>
<li>Your application launches the pending intent, which launches the checkout UI.</li>
- <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels the purchase), Android Market sends your application a notification message (an <code>ACTION_NOTIFY</code> intent). The notification message includes a notification ID, which references the completed transaction.</li>
+ <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels the purchase), Android Market sends your application a notification message (an <code>IN_APP_NOTIFY</code> broadcast intent). The notification message includes a notification ID, which references the transaction.</li>
<li>Your application requests the transaction information by sending a <code>GET_PURCHASE_STATE_CHANGED</code> request, specifying the notification ID for the transaction.</li>
- <li>The Android Market application sends a Bundle with a <code>RESPONSE_CODE</code> and a <code>REQUEST_ID</code>.
- <li>Android Market sends the transaction information to your application in an <code>ACTION_PURCHASE_STATE_CHANGED</code> intent.</li>
+ <li>The Android Market application sends a Bundle with a <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key.
+ <li>Android Market sends the transaction information to your application in a <code>PURCHASE_STATE_CHANGED</code> broadcast intent.</li>
<li>Your application confirms that you received the transaction information for the given notification ID by sending a confirmation message (<code>CONFIRM_NOTIFICATIONS</code> type), specifying the notification ID for which you received transaction information.</li>
- <li>The Android Market applications sends your application a Bundle with a <code>RESPONSE_CODE</code> and a <code>REQUEST_ID</code>.</li>
+ <li>The Android Market application sends your application a Bundle with a <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key.</li>
</ol>
<p class="note"><strong>Note:</strong> You must launch the pending intent from an activity context and not an application context.</p>
-<div style="margin:2em 1em 1em 1em;">
-<img src="{@docRoot}images/billing_request_purchase.png" style="text-align:left;" />
-<div style="margin:.25em 1.25em;padding:0"><strong>Figure 2.</strong> Message sequence for a typical purchase request. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong> (<code>ACTION_RESPONSE_CODE</code> broadcast intents have been omitted).</div>
-</div>
+<img src="{@docRoot}images/billing_request_purchase.png" height="231" id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> Message sequence for a purchase request.
+</p>
-<p>The messaging sequence for a restore transaction request is shown in Figure 3. The request type for the <code>sendBillingRequest()</code> method is shown in <strong>bold</strong>, the responses are shown in standard text.</p>
+<p>The messaging sequence for a restore transaction request is shown in figure 3. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, broadcast intents are shown in <em>italic</em>. For clarity, figure 3 does not show the <code>RESPONSE_CODE</code> broadcast intents that are sent for every request.</p>
<div class="figure" style="width:490px">
-<img src="{@docRoot}images/billing_restore_transactions.png" alt=""/>
-<p class="img-caption"><strong>Figure 3.</strong> Message sequence for a restore transactions request.</p>
+<img src="{@docRoot}images/billing_restore_transactions.png" alt="" height="168" />
+<p class="img-caption">
+ <strong>Figure 3.</strong> Message sequence for a restore transactions request.
+</p>
</div>
-<p>The request triggers three responses. The first is a {@link android.os.Bundle} with a <code>RESPONSE_CODE</code> and a <code>REQUEST_ID</code>. Next, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides status information or error information about the request. As always, the <code>ACTION_RESPONSE_CODE</code> message references a specific request ID, so you can determine which request an <code>ACTION_RESPONSE_CODE</code> message pertains to.</p>
+<p>The request triggers three responses. The first is a {@link android.os.Bundle} with a <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key. Next, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides status information or error information about the request. As always, the <code>RESPONSE_CODE</code> message references a specific request ID, so you can determine which request a <code>RESPONSE_CODE</code> message pertains to.</p>
-<p>The <code>RESTORE_TRANSACTIONS</code> request type also triggers an <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the same type of transaction information that is sent during a purchase request, although you do not need to respond to this intent with a <code>CONFIRM_NOTIFICATIONS</code> message.</p>
+<p>The <code>RESTORE_TRANSACTIONS</code> request type also triggers a <code>PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the same type of transaction information that is sent during a purchase request, although you do not need to respond to this intent with a <code>CONFIRM_NOTIFICATIONS</code> message.</p>
-<p>The messaging sequence for checking whether in-app billing is supported is shown in Figure 4. The request type for the <code>sendBillingRequest()</code> method is shown in <strong>bold</strong>, the response is shown in regular text.</p>
+<p>The messaging sequence for checking whether in-app billing is supported is shown in figure 4. The request type for the <code>sendBillingRequest()</code> method is shown in <strong>bold</strong>.</p>
<div class="figure" style="width:454px">
-<img src="{@docRoot}images/billing_check_supported.png" alt=""/>
-<p class="img-caption"><strong>Figure 4.</strong> Message sequence for checking whether in-app billing is supported.</p>
+<img src="{@docRoot}images/billing_check_supported.png" alt="" height="168" />
+<p class="img-caption">
+ <strong>Figure 4.</strong> Message sequence for checking whether in-app billing is supported.
+</p>
</div>
-<p>The synchronous response for a <code>CHECK_BILLING_SUPPORTED</code> request provides a server response code. A <code>RESULT_OK</code> response code indicates that in-app billing is supported; a <code>RESULT_BILLING_UNAVAILABLE</code> response code indicates that the Android Market application does not support in-app billing and may need to be updated. A <code>SERVER_ERROR</code> can also be returned, indicating that there was a problem with the Android Market server. The <code>RESULT_BILLING_UNAVAILABLE</code> response code can also indicate that the user is ineligible for in-app billing (for example, the user resides in a country that does not allow in-app billing).</p>
+<p>The synchronous response for a <code>CHECK_BILLING_SUPPORTED</code> request provides a Bundle with a server response code. A <code>RESULT_OK</code> response code indicates that in-app billing is supported; a <code>RESULT_BILLING_UNAVAILABLE</code> response code indicates that in-app billing is unavailable because the API version you specified is unrecognized or the user is not eligible to make in-app purchases (for example, the user resides in a country that does not allow in-app billing). A <code>SERVER_ERROR</code> can also be returned, indicating that there was a problem with the Android Market server.</p>
-<h3 id="billing-action-notify">Handling ACTION_NOTIFY messages</h3>
+<h3 id="billing-action-notify">Handling IN_APP_NOTIFY messages</h3>
-<p>Usually, your application receives an <code>ACTION_NOTIFY</code> intent from Android Market in response to a <code>REQUEST_PURCHASE</code> message (see figure 2). The <code>ACTION_NOTIFY</code> intent informs your application that the state of a requested purchase has changed. To retrieve the details of that state change, your application sends a <code>GET_PURCHASE_INFORMATION</code> request. Android Market responds with an <code>ACTION_PURCHASE_STATE_CHANGED</code> intent, which contains the details of the purchase state change. Your application then sends a <code>CONFIRM_NOTIFICATIONS</code> message, informing Android Market that you've received the purchase state change information.</p>
+<p>Usually, your application receives an <code>IN_APP_NOTIFY</code> broadcast intent from Android Market in response to a <code>REQUEST_PURCHASE</code> message (see figure 2). The <code>IN_APP_NOTIFY</code> broadcast intent informs your application that the state of a requested purchase has changed. To retrieve the details of that purchase, your application sends a <code>GET_PURCHASE_INFORMATION</code> request. Android Market responds with a <code>PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the details of the purchase state change. Your application then sends a <code>CONFIRM_NOTIFICATIONS</code> message, informing Android Market that you've received the purchase state change information.</p>
-<p>When Android Market receives a <code>CONFIRM_NOTIFICATIONS</code> message for a given message, it usually stops sending <code>ACTION_NOTIFY</code> intents for that message. However, there are some cases where Android Market may send repeated <code>ACTION_NOTIFY</code> intents for a message even though your application has sent a <code>CONFIRM_NOTIFICATIONS</code> message. This can occur if a device loses network connectivity while you are sending the <code>CONFIRM_NOTIFICATIONS</code> message. In this case, Android Market might not receive your <code>CONFIRM_NOTIFICATIONS</code> message and it could send multiple <code>ACTION_NOTIFY</code> messages until it receives acknowledgement that you received the message. Therefore, your application must be able to recognize that the subsequent <code>ACTION_NOTIFY</code> messages are for a previously processed transaction. You can do this by checking the <code>orderID</code> that's contained in the JSON string because every transaction has a unique <code>orderId</code>.</p>
+<p>When Android Market receives a <code>CONFIRM_NOTIFICATIONS</code> message for a given message, it usually stops sending <code>IN_APP_NOTIFY</code> intents for that message. However, there are some cases where Android Market may send repeated <code>IN_APP_NOTIFY</code> intents for a message even though your application has sent a <code>CONFIRM_NOTIFICATIONS</code> message. This can occur if a device loses network connectivity while you are sending the <code>CONFIRM_NOTIFICATIONS</code> message. In this case, Android Market might not receive your <code>CONFIRM_NOTIFICATIONS</code> message and it could send multiple <code>IN_APP_NOTIFY</code> messages until it receives acknowledgement that you received the message. Therefore, your application must be able to recognize that the subsequent <code>IN_APP_NOTIFY</code> messages are for a previously processed transaction. You can do this by checking the <code>orderID</code> that's contained in the JSON string because every transaction has a unique <code>orderId</code>.</p>
-<p>Your application may also receive <code>ACTION_NOTIFY</code> intents even though your application has not sent a <code>REQUEST_PURCHASE</code> message. This can occur when a user has your application installed on two (or more) devices and the user makes an in-app purchase from one of the devices. In this case, Android Market sends an <code>ACTION_NOTIFY</code> message to the second device, informing the application that there is a purchase state change. Your application can handle this message the same way it handles the response from an application-initiated <code>REQUEST_PURCHASE</code> message, so that ultimately your application receives a purchase state change message that includes information about the item that's been purchased. This scenario applies only to items that have their <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">purchase type</a> set to "managed per user account."</p>
+<p>There are two cases where your application may also receive <code>IN_APP_NOTIFY</code> broadcast intents even though your application has not sent a <code>REQUEST_PURCHASE</code> message. Figure 5 shows the messaging sequence for both of these cases. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, broadcast intents are shown in <em>italic</em>. For clarity, figure 5 does not show the <code>RESPONSE_CODE</code> broadcast intents that are sent for every request.</p>
+
+<div class="figure" style="width:481px">
+<img src="{@docRoot}images/billing_refund.png" alt="" height="189" />
+<p class="img-caption">
+ <strong>Figure 5.</strong> Message sequence for refunds and other unsolicited IN_APP_NOTIFY messages.
+</p>
+</div>
+
+<p>In the first case, your application can receive an <code>IN_APP_NOTIFY</code> broadcast intent when a user has your application installed on two (or more) devices and the user makes an in-app purchase from one of the devices. In this case, Android Market sends an <code>IN_APP_NOTIFY</code> message to the second device, informing the application that there is a purchase state change. Your application can handle this message the same way it handles the response from an application-initiated <code>REQUEST_PURCHASE</code> message, so that ultimately your application receives a <code>PURCHASE_STATE_CHANGED</code> broadcast intent message that includes information about the item that has been purchased. This applies only to items that have their <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">purchase type</a> set to "managed per user account."</p>
+
+<p>In the second case, your application can receive an <code>IN_APP_NOTIFY</code> broadcast intent when Android Market receives a refund notification from Google Checkout. In this case, Android Market sends an <code>IN_APP_NOTIFY</code> message to your application. Your application can handle this message the same way it handles responses from an application-initiated <code>REQUEST_PURCHASE</code> message so that ultimately your application receives a <code>PURCHASE_STATE_CHANGED</code> message that includes information about the item that has been refunded. The refund information is included in the JSON string that accompanies the <code>PURCHASE_STATE_CHANGED</code> broadcast intent. Also, the <code>purchaseState</code> field in the JSON string is set to 2.</p>
<h2 id="billing-security">Security Controls</h2>
-<p>To help ensure the integrity of the transaction information that is sent to your application, Android Market signs the JSON string that is contained in the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. Android Market uses the private key that is associated with your publisher account to create this signature. The publisher site generates an RSA key pair for each publisher account. You can find the public key portion of this key pair on your account's profile page. It is the same public key that is used with Android Market licensing.</p>
+<p>To help ensure the integrity of the transaction information that is sent to your application, Android Market signs the JSON string that is contained in the <code>PURCHASE_STATE_CHANGED</code> broadcast intent. Android Market uses the private key that is associated with your publisher account to create this signature. The publisher site generates an RSA key pair for each publisher account. You can find the public key portion of this key pair on your account's profile page. It is the same public key that is used with Android Market licensing.</p>
<p>When Android Market signs a billing response, it includes the signed JSON string (unencrypted) and the signature. When your application receives this signed response you can use the public key portion of your RSA key pair to verify the signature. By performing signature verification you can help detect responses that have been tampered with or that have been spoofed. You can perform this signature verification step in your application; however, if your application connects to a secure remote server then we recommend that you perform the signature verification on that server.</p>
<p>In-app billing also uses nonces (a random number used once) to help verify the integrity of the purchase information that's returned from Android Market. Your application must generate a nonce and send it with a <code>GET_PURCHASE_INFORMATION</code> request and a <code>RESTORE_TRANSACTIONS</code> request. When Android Market receives the request, it adds the nonce to the JSON string that contains the transaction information. The JSON string is then signed and returned to your application. When your application receives the JSON string, you need to verify the nonce as well as the signature of the JSON string.</p>
-<p>For more information about best practices for security and design, see <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
+<p>For more information about best practices for security and design, see <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
<h2 id="billing-limitations">In-app Billing Requirements and Limitations</h2>
@@ -260,10 +223,12 @@
<ul>
<li>In-app billing can be implemented only in applications that you publish through Android Market.</li>
- <li>You must have a Google Checkout merchant account to use the in-app billing service.</li>
- <li>An application can use in-app billing only if the current Android Market application is installed on its host device and the device is running Android 1.6 (API level 4) or higher.</li>
- <li>A device must be running version 2.3.0 (or higher) of the Android Market application to support in-app billing.</li>
+ <li>You must have a Google Checkout Merchant account to use Android Market In-app Billing.</li>
+ <li>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application.</li>
+ <li>An application can use in-app billing only if the device is running Android 1.6 (API level 4) or higher.</li>
<li>You can use in-app billing to sell only digital content. You cannot use in-app billing to sell physical goods, personal services, or anything that requires physical delivery.</li>
<li>Android Market does not provide any form of content delivery. You are responsible for delivering the digital content that you sell in your applications.</li>
<li>You cannot implement in-app billing on a device that never connects to the network. To complete in-app purchase requests, a device must be able to access the Android Market server over the network. </li>
</ul>
+
+<p>For more information about in-app billing requirements, see <a href="http://market.android.com/support/bin/answer.py?answer=1153481">In-App Billing Availability and Policies</a>.</p>
diff --git a/docs/html/guide/market/billing/billing_reference.jd b/docs/html/guide/market/billing/billing_reference.jd
index 2e5c9c6..292823d 100755
--- a/docs/html/guide/market/billing/billing_reference.jd
+++ b/docs/html/guide/market/billing/billing_reference.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -33,10 +27,6 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
-
<p>The following document provides technical reference information for the following:</p>
<ul>
@@ -47,7 +37,7 @@
<h2 id="billing-codes">Android Market Server Response Codes for In-app Billing</h2>
-<p>The following table lists all of the server response codes that are sent from Android Market to your application. Android Market sends these response codes asynchronously as <code>INAPP_RESPONSE_CODE</code> extras in the <code>ACTION_RESPONSE_CODE</code> broadcast intent. Your application must handle all of these response codes.</p>
+<p>The following table lists all of the server response codes that are sent from Android Market to your application. Android Market sends these response codes asynchronously as <code>response_code</code> extras in the <code>com.android.vending.billing.RESPONSE_CODE</code> broadcast intent. Your application must handle all of these response codes.</p>
<p class="table-caption" id="response-codes-table"><strong>Table 1.</strong> Summary of response codes returned by Android Market.</p>
@@ -71,7 +61,7 @@
</tr>
<tr>
<td><code>RESULT_BILLING_UNAVAILABLE</code></td>
- <td>Indicates that the <code>BILLING_API_VERSION</code> that you specified is not recognized by the Android Market application and that the Android Market application may have to be updated. Can also indicate that the user is ineligible for in-app billing. For example, the user resides in a country that does not allow in-app purchases.</td>
+ <td>Indicates that in-app billing is not available because the <code>API_VERSION</code> that you specified is not recognized by the Android Market application or the user is ineligible for in-app billing (for example, the user resides in a country that prohibits in-app purchases).</td>
</tr>
<tr>
<td><code>RESULT_ITEM_UNAVAILABLE</code></td>
@@ -90,8 +80,8 @@
<h2 id="billing-interface">In-app Billing Service Interface</h2>
-<p>The following section describes the interface for the Android Market In-app Billing service. The interface is defined in the <code>IMarketBillingService.aidl</code> file, which is included with the in-app billing <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
-<p>The interface consists of a single request method <code>sendBillingRequest()</code>. This method takes a single {@link android.os.Bundle} parameter. The Bundle parameter includes several key-value pairs, which are summarized in Table 2.</p>
+<p>The following section describes the interface for Android Market's in-app billing service. The interface is defined in the <code>IMarketBillingService.aidl</code> file, which is included with the in-app billing <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
+<p>The interface consists of a single request method <code>sendBillingRequest()</code>. This method takes a single {@link android.os.Bundle} parameter. The Bundle parameter includes several key-value pairs, which are summarized in table 2.</p>
<p class="table-caption"><strong>Table 2.</strong> Description of Bundle keys passed in a <code>sendBillingRequest()</code> request.</p>
@@ -106,52 +96,52 @@
</tr>
<tr>
<td><code>BILLING_REQUEST</code></td>
- <td>String</td>
+ <td><code>String</code></td>
<td><code>CHECK_BILLING_SUPPORTED</code>, <code>REQUEST_PURCHASE</code>, <code>GET_PURCHASE_INFORMATION</code>, <code>CONFIRM_NOTIFICATIONS</code>, or <code>RESTORE_TRANSACTIONS</code></td>
<td>Yes</td>
<td>The type of billing request you are making with the <code>sendBillingRequest()</code> request. The possible values are discussed more below this table.</td>
</tr>
<tr>
- <td><code>BILLING_API_VERSION</code></td>
- <td>int</td>
- <td>0 (for alpha release); 1 (for beta release)</td>
+ <td><code>API_VERSION</code></td>
+ <td><code>int</code></td>
+ <td>1</td>
<td>Yes</td>
- <td>The version of the in-app billing service you are using.</td>
+ <td>The version of Android Market's in-app billing service you are using. The current version is 1.</td>
</tr>
<tr>
<td><code>PACKAGE_NAME</code></td>
- <td>String</td>
+ <td><code>String</code></td>
<td>A valid package name.</td>
<td>Yes</td>
<td>The name of the application that is making the request.</td>
</tr>
<tr>
<td><code>ITEM_ID</code></td>
- <td>String</td>
+ <td><code>String</code></td>
<td>Any valid product identifier.</td>
<td>Required for <code>REQUEST_PURCHASE</code> requests.</td>
- <td>The product ID of the item you are making a billing request for. Every in-app item that you sell using the in-app billing service must have a unique product ID, which you specify on the Android Market publisher site.</td>
+ <td>The product ID of the item you are making a billing request for. Every in-app item that you sell using Android Market's in-app billing service must have a unique product ID, which you specify on the Android Market publisher site.</td>
</tr>
<tr>
<td><code>NONCE</code></td>
- <td>long</td>
- <td>Any valid long value.</td>
+ <td><code>long</code></td>
+ <td>Any valid <code>long</code> value.</td>
<td>Required for <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> requests.</td>
- <td>A number used once. Your application must generate and send a nonce with each <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>ACTION_PURCHASE_STATE_CHANGED</code> intent, so you can use this value to verify the integrity of transaction responses form Android Market.</td>
+ <td>A number used once. Your application must generate and send a nonce with each <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>PURCHASE_STATE_CHANGED</code> broadcast intent, so you can use this value to verify the integrity of transaction responses form Android Market.</td>
</tr>
<tr>
<td><code>NOTIFY_IDS</code></td>
- <td>Array of long values</td>
- <td>Any valid array of long values</td>
+ <td>Array of <code>long</code> values</td>
+ <td>Any valid array of <code>long</code> values</td>
<td>Required for <code>GET_PURCHASE_INFORMATION</code> and <code>CONFIRM_NOTIFICATIONS</code> requests.</td>
- <td>An array of notification identifiers. A notification ID is sent to your application in an <code>ACTION_NOTIFY</code> intent every time a purchase changes state. You use the notification to retrieve the details of the purchase state change.</td>
+ <td>An array of notification identifiers. A notification ID is sent to your application in an <code>IN_APP_NOTIFY</code> broadcast intent every time a purchase changes state. You use the notification to retrieve the details of the purchase state change.</td>
</tr>
<tr>
<td><code>DEVELOPER_PAYLOAD</code></td>
- <td>String</td>
- <td>Any valid String less than 256 characters long.</td>
+ <td><code>String</code></td>
+ <td>Any valid <code>String</code> less than 256 characters long.</td>
<td>No</td>
- <td>A developer-specified string that is associated with an order. This field is returned in the JSON string that contains transaction information for an order. You can use this field to send information with an order. For example, you can use this field to send index keys with an order, which is useful if you are using a database to store purchase information. We recommend that you do not use this field to send data or content.</td>
+ <td>A developer-specified string that can be specified when you make a <code>REQUEST_PURCHASE</code> request. This field is returned in the JSON string that contains transaction information for an order. You can use this key to send supplemental information with an order. For example, you can use this key to send index keys with an order, which is useful if you are using a database to store purchase information. We recommend that you do not use this key to send data or content.</td>
</tr>
</table>
@@ -231,34 +221,81 @@
<p>The following section describes the in-app billing broadcast intents that are sent by the Android Market application. These broadcast intents inform your application about in-app billing actions that have occurred. Your application must implement a {@link android.content.BroadcastReceiver} to receive these broadcast intents, such as the <code>BillingReceiver</code> that's shown in the in-app billing <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
-<h4>ACTION_RESPONSE_CODE</h4>
+<h4>com.android.vending.billing.RESPONSE_CODE</h4>
-<p>This broadcast intent contains an Android Market response code, and is sent after you make an in-app billing request. A server response code can indicate that a billing request was successfully sent to Android Market or it can indicate that some error occurred during a billing request. This intent is not used to report any purchase state changes (such as refund or purchase information). For more information about the response codes that are sent with this response, see <a href="#billing-codes">Android Market Response Codes for In-app Billing</a>.</p>
+<p>This broadcast intent contains an Android Market response code, and is sent after you make an in-app billing request. A server response code can indicate that a billing request was successfully sent to Android Market or it can indicate that some error occurred during a billing request. This intent is not used to report any purchase state changes (such as refund or purchase information). For more information about the response codes that are sent with this response, see <a href="#billing-codes">Android Market Response Codes for In-app Billing</a>. The sample application assigns this broadcast intent to a constant named <code>ACTION_RESPONSE_CODE</code>.</p>
<h5>Extras</h5>
<ul type="none">
- <li><code>INAPP_REQUEST_ID</code>—a long representing a request ID. A request ID identifies a specific billing request and is returned by Android Market at the time a request is made.</li>
- <li><code>INAPP_RESPONSE_CODE</code>—an int representing the Android Market server response code.</li>
+ <li><code>request_id</code>—a <code>long</code> representing a request ID. A request ID identifies a specific billing request and is returned by Android Market at the time a request is made.</li>
+ <li><code>response_code</code>—an <code>int</code> representing the Android Market server response code.</li>
</ul>
-<h4>ACTION_NOTIFY</h4>
+<h4>com.android.vending.billing.IN_APP_NOTIFY</h4>
-<p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>ACTION_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve the message details.</p>
+<p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>IN_APP_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve the message details. The sample application assigns this broadcast intent to a constant named <code>ACTION_NOTIFY</code>.</p>
<h5>Extras</h5>
<ul type="none">
- <li><code>NOTIFICATION_ID</code>—a string representing the notification ID for a given purchase state change. Android Market notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the <code>GET_PURCHASE_INFORMATION</code> request.</li>
+ <li><code>notification_id</code>—a <code>String</code> representing the notification ID for a given purchase state change. Android Market notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the <code>GET_PURCHASE_INFORMATION</code> request.</li>
</ul>
-<h4>ACTION_PURCHASE_STATE_CHANGED</h4>
+<h4>com.android.vending.billing.PURCHASE_STATE_CHANGED</h4>
-<p>This broadcast intent contains detailed information about one or more transactions. The transaction information is contained in a JSON string. The JSON string is signed and the signature is sent to your application along with the JSON string (unencrypted). To help ensure the security of your in-app billing messages, your application can verify the signature of this JSON string.</p>
+<p>This broadcast intent contains detailed information about one or more transactions. The transaction information is contained in a JSON string. The JSON string is signed and the signature is sent to your application along with the JSON string (unencrypted). To help ensure the security of your in-app billing messages, your application can verify the signature of this JSON string. The sample application assigns this broadcast intent to a constant named <code>ACTION_PURCHASE_STATE_CHANGED</code>.</p>
<h5>Extras</h5>
<ul type="none">
- <li><code>INAPP_SIGNED_DATA</code>—a string representing the signed JSON string.</li>
- <li><code>INAPP_SIGNATURE</code>—a string representing the signature.</li>
-</ul>
\ No newline at end of file
+ <li><code>inapp_signed_data</code>—a <code>String</code> representing the signed JSON string.</li>
+ <li><code>inapp_signature</code>—a <code>String</code> representing the signature.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Your application should map the broadcast intents and extras to constants that are unique to your application. See the <code>Consts.java</code> file in the sample application to see how this is done.</p>
+
+<p>The fields in the JSON string are described in the following table (see table 4):</p>
+
+<p class="table-caption"><strong>Table 4.</strong> Description of JSON fields that are returned with a <code>PURCHASE_STATE_CHANGED</code> intent.</p>
+
+<table>
+
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+<tr>
+ <td>nonce</td>
+ <td>A number used once. Your application generates the nonce and sends it with the <code>GET_PURCHASE_INFORMATION</code> request. Android Market sends the nonce back as part of the JSON string so you can verify the integrity of the message.</td>
+</tr>
+<tr>
+ <td>notificationId</td>
+ <td>A unique identifier that is sent with an <code>IN_APP_NOTIFY</code> broadcast intent. Each <code>notificationId</code> corresponds to a specify message that is waiting to be retrieved on the Android Market server. Your application sends back the <code>notificationId</code> with the <code>GET_PURCHASE_INFORMATION</code> message so Android Market can determine which messages you are retrieving.</td>
+</tr>
+<tr>
+ <td>orderId</td>
+ <td>A unique order identifier for the transaction. This corresponds to the Google Checkout Order ID.</td>
+</tr>
+<tr>
+ <td>packageName</td>
+ <td>The application package from which the purchase originated.</td>
+</tr>
+<tr>
+ <td>productId</td>
+ <td>The item's product identifier. Every item has a product ID, which you must specify in the application's product list on the Android Market publisher site.</td>
+</tr>
+<tr>
+ <td>purchaseTime</td>
+ <td>The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).</td>
+</tr>
+
+<tr>
+ <td>purchaseState</td>
+ <td>The purchase state of the order. Possible values are 0 (purchased), 1 (canceled), or 2 (refunded).</td>
+</tr>
+<tr>
+ <td>developerPayload</td>
+ <td>A developer-specified string that contains supplemental information about an order. You can specify a value for this field when you make a <code>REQUEST_PURCHASE</code> request.</td>
+</tr>
+</table>
diff --git a/docs/html/guide/market/billing/billing_testing.jd b/docs/html/guide/market/billing/billing_testing.jd
index 5ced9c7..742e7ef4d 100755
--- a/docs/html/guide/market/billing/billing_testing.jd
+++ b/docs/html/guide/market/billing/billing_testing.jd
@@ -3,12 +3,6 @@
parent.link=index.html
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
@@ -32,29 +26,23 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
-
<p>The Android Market publisher site provides several tools that help you test your in-app billing implementation before it is published. You can use these tools to create test accounts and purchase special reserved items that send static billing responses to your application.</p>
<p>To test in-app billing in an application you must install the application on an Android-powered device. You cannot use the Android emulator to test in-app billing. The device you use for testing must run a standard version of the Android 1.6 or later platform (API level 4 or higher), and have the most current version of the Android Market application installed. If a device is not running the most current Android Market application, your application won't be able to send in-app billing requests to Android Market. For general information about how to set up a device for use in developing Android applications, see <a
-href="{@docRoot}guide/developing/device.html">Developing on a Device</a>.</p>
+href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a>.</p>
<p>The following section shows you how to set up and use the in-app billing test tools.</p>
-<p class="note"><strong>Note</strong>: Debug log messages are turned off by default in the sample application. You can turn them on by setting the variable <code>DEBUG</code> to <code>true</code> in the <code>Consts.java</code> file.</p>
-
<h2 id="billing-testing-static">Testing in-app purchases with static responses</h2>
-<p>We recommend that you first test your in-app billing implementation using static responses from Android Market. This enables you to verify that your application is handling the primary Android Market responses correctly and that your application is able to verify the signature correctly.</p>
+<p>We recommend that you first test your in-app billing implementation using static responses from Android Market. This enables you to verify that your application is handling the primary Android Market responses correctly and that your application is able to verify signatures correctly.</p>
<p>To test your implementation with static responses, you make an in-app billing request using a special item that has a reserved product ID. Each reserved product ID returns a specific static response from Android Market. No money is transferred when you make in-app billing requests with the reserved product IDs. Also, you cannot specify the form of payment when you make a billing request with a reserved product ID. Figure 1 shows the checkout flow for the reserved item that has the product ID android.test.purchased.</p>
-<div style="margin:2em 1em 1em 1em;">
-<img src="{@docRoot}images/billing_test_flow.png" style="text-align:left;" />
-<div style="margin:.25em 1.25em;padding:0"><strong>Figure 1.</strong> Checkout flow for the special reserved item android.test.purchased.</div>
-</div>
+<img src="{@docRoot}images/billing_test_flow.png" height="381" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Checkout flow for the special reserved item android.test.purchased.
+</p>
<p>You do not need to list the reserved products in your application's product list. Android Market already knows about the reserved product IDs. Also, you do not need to upload your application to the publisher site to perform static response tests with the reserved product IDs. You can simply install your application on a device, log into the device, and make billing requests using the reserved product IDs.</p>
@@ -68,14 +56,14 @@
<p>When you make an in-app billing request with this product ID Android Market responds as though the purchase was canceled. This can occur when an error is encountered in the order process, such as an invalid credit card, or when you cancel a user's order before it is charged.</p>
</li>
<li><strong>android.test.refunded</strong>
- <p>When you make an in-app billing request with this product ID, Android Market responds as though the purchase was refunded. Refunds cannot be initiated through the in-app billing feature. Refunds must be initiated by you (the merchant). A refund message is sent to your app by Android Market only when Android Market gets notification from Google Checkout that a refund has been made.</p>
+ <p>When you make an in-app billing request with this product ID, Android Market responds as though the purchase was refunded. Refunds cannot be initiated through Android Market's in-app billing service. Refunds must be initiated by you (the merchant). After you process a refund request through your Google Checkout account, a refund message is sent to your application by Android Market. This occurs only when Android Market gets notification from Google Checkout that a refund has been made. For more information about refunds, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling IN_APP_NOTIFY messages</a> and <a href="http://www.google.com/support/androidmarket/bin/answer.py?answer=1153485">In-app Billing Pricing</a>.</p>
</li>
<li><strong>android.test.item_unavailable</strong>
- <p>When you make an in-app billing request with this product ID Android Market responds as though the item being purchased was not listed in your app's product list.</p>
+ <p>When you make an in-app billing request with this product ID, Android Market responds as though the item being purchased was not listed in your application's product list.</p>
</li>
</ul>
-<p>In some cases, the reserved items may return signed static responses, which lets you test signature verification in your application. To test signature verification with the special reserved product IDs, you may need to set up <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">trusted tester accounts</a> or upload your application as a unpublished draft application. The following table (Table 1) shows you the conditions under which static responses are signed.</p>
+<p>In some cases, the reserved items may return signed static responses, which lets you test signature verification in your application. To test signature verification with the special reserved product IDs, you may need to set up <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">test accounts</a> or upload your application as a unpublished draft application. Table 1 shows you the conditions under which static responses are signed.</p>
<p class="table-caption" id="static-responses-table"><strong>Table 1.</strong>
Conditions under which static responses are signed.</p>
@@ -119,7 +107,7 @@
<tr>
<td>Yes</td>
<td>No</td>
-<td>Trusted tester</td>
+<td>Test account</td>
<td>Signed</td>
</tr>
@@ -134,6 +122,22 @@
<p>To make an in-app billing request with a reserved product ID, you simply construct a normal <code>REQUEST_PURCHASE</code> request, but instead of using a real product ID from your application's product list you use one of the reserved product IDs.</p>
+<p>To test your application using the reserved product IDs, follow these steps:</p>
+
+<ol>
+ <li><strong>Install your application on an Android-powered device.</strong>
+ <p>You cannot use the emulator to test in-app billing; you must install your application on a device to test in-app billing.</p>
+ <p>To learn how to install an application on a device, see <a href="{@docRoot}guide/developing/building/building-cmdline.html#RunningOnDevice">Running on a device</a>.</p>
+ </li>
+ <li><strong>Sign in to your device with your developer account.</strong>
+ <p>You do not need to use a test account if you are testing only with the reserved product IDs.</p>
+ </li>
+ <li><strong>Verify that your device is running a supported version of the Android Market application or the MyApps application.</strong>
+ <p>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application. To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>.</p>
+ </li>
+ <li><strong>Run your application and purchase the reserved product IDs.</strong></li>
+</ol>
+
<p class="note"><strong>Note</strong>: Making in-app billing requests with the reserved product IDs overrides the usual Android Market production system. When you send an in-app billing request for a reserved product ID, the quality of service will not be comparable to the production environment.</p>
<h2 id="billing-testing-real">Testing In-app Purchases Using Your Own Product IDs</h2>
@@ -146,29 +150,35 @@
<p>Also, a test account can purchase an item in your product list only if the item is published. The application does not need to be published, but the item does need to be published.</p>
-<p>When you use a test account to purchase items, the account is billed through Google Checkout and your Google Checkout merchant account receives a payout for the purchase. Therefore, you need to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.</p>
+<p>When you use a test account to purchase items, the test account is billed through Google Checkout and your Google Checkout Merchant account receives a payout for the purchase. Therefore, you may want to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.</p>
<p>To test your in-app billing implementation with actual purchases, follow these steps:</p>
<ol>
- <li>Upload your application as a draft application to the publisher site. You do not need to publish your application to perform end-to-end testing with real product IDs.</li>
- <li>Add items to the application's product list. Make sure that you publish the items (the application can remain unpublished).
- <p>See <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-catalog">Creating a product list</a> to learn how to do this.</p>
+ <li><strong>Upload your application as a draft application to the publisher site.</strong>
+ <p>You do not need to publish your application to perform end-to-end testing with real product IDs. To learn how to upload an application to Android Market, see <a href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading applications</a>.</p>
</li>
- <li>Install your application on an Android-powered device.
- <p>See <a href="{@docRoot}guide/developing/device.html">Developing on a Device</a> for more information about how to do this.</p>
+ <li><strong>Add items to the application's product list.</strong>
+ <p>Make sure that you publish the items (the application can remain unpublished). See <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-catalog">Creating a product list</a> to learn how to do this.</p>
</li>
- <li>Sign in to the device using one of the <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">trusted tester accounts</a> that you registered on the Android Market site.
- <p>We recommend that you make the test account the primary account on the device. To sign in to a device, do the following:</p>
+ <li><strong>Install your application on an Android-powered device.</strong>
+ <p>You cannot use the emulator to test in-app billing; you must install your application on a device to test in-app billing.</p>
+ <p>To learn how to install an application on a device, see <a href="{@docRoot}guide/developing/building/building-cmdline.html#RunningOnDevice">Running on a device</a>.</p>
+ </li>
+ <li><strong>Make one of your test accounts the primary account on your device.</strong>
+ <p>To perform end-to-end testing of in-app billing, the primary account on your device must be one of the <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">test accounts</a> that you registered on the Android Market site. If the primary account on your device is not a test account, you must do a factory reset of the device and then sign in with one of your test accounts. To perform a factory reset, do the following:</p>
<ol>
- <li>Open Settings > Accounts & sync</li>
- <li>Select <strong>Add Account</strong> and choose to add a "Google" account.</li>
- <li>Select <strong>Next</strong> and then <strong>Sign in</strong>.</li>
- <li>Enter the username and password of the test account.</li>
- <li>Select <strong>Sign in</strong>. The system signs you in to the new account.</li>
+ <li>Open Settings on your device.</li>
+ <li>Touch <strong>Privacy</strong>.</li>
+ <li>Touch <strong>Factory data reset</strong>.</li>
+ <li>Touch <strong>Reset phone</strong>.</li>
+ <li>After the phone resets, be sure to sign in with one of your test accounts during the device setup process.</li>
</ol>
</li>
- <li>Make in-app purchases in your application.</li>
+ <li><strong>Verify that your device is running a supported version of the Android Market application or the MyApps application.</strong>
+ <p>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application. To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>.</p>
+ </li>
+ <li><strong>Make in-app purchases in your application.</strong></li>
</ol>
<p class="note"><strong>Note:</strong> The only way to change the primary account on a device is to do a factory reset, making sure you log on with your primary account first.</p>
diff --git a/docs/html/guide/market/billing/index.jd b/docs/html/guide/market/billing/index.jd
index 6985179..fb85fa6 100755
--- a/docs/html/guide/market/billing/index.jd
+++ b/docs/html/guide/market/billing/index.jd
@@ -1,12 +1,6 @@
page.title=In-app Billing
@jd:body
-<style type="text/css">
- #jd-content {
- background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
- }
-</style>
-
<div id="qv-wrapper">
<div id="qv">
@@ -29,26 +23,22 @@
</div>
</div>
-<div class="special" style="margin-right:345px">
- <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
+<p>Android Market In-app Billing is an Android Market service that lets you sell digital content in your applications. You can use the service to sell a wide range of content, including downloadable content such as media files or photos, and virtual content such as game levels or potions.</p>
-<p>In-app billing is an Android Market service that lets you sell digital content in your applications. You can use the service to sell a wide range of content, including downloadable content such as media files or photos, and virtual content such as game levels or potions.</p>
+<p>When you use Android Market's in-app billing service to sell an item, Android Market handles all checkout details so your application never has to directly process any financial transactions. Android Market uses the same checkout service that is used for application purchases, so your users experience a consistent and familiar purchase flow (see figure 1). Also, the transaction fee for in-app purchases is the same as the transaction fee for application purchases (30%).</p>
-<p>When you use the Android Market In-app Billing service to sell an item, Android Market handles all checkout details so your application never has to directly process any financial transactions. Android Market uses the same checkout service that is used for application purchases, so your users experience a consistent and familiar purchase flow (see figure 1). Also, the transaction fee for in-app purchases is the same as the transaction fee for application purchases (30%).</p>
-
-<p>Any application that you publish through Android Market can implement in-app billing. No special account or registration is required other than an Android Market publisher account and a Google Checkout merchant account. Also, because the service uses no dedicated framework APIs, you can add in-app billing to any application that uses a minimum API level of 4 or higher.</p>
+<p>Any application that you publish through Android Market can implement in-app billing. No special account or registration is required other than an Android Market publisher account and a Google Checkout Merchant account. Also, because the service uses no dedicated framework APIs, you can add in-app billing to any application that uses a minimum API level of 4 or higher.</p>
<p>To help you integrate in-app billing into your application, the Android SDK provides a sample application that demonstrates a simple implementation of in-app billing. The sample application contains examples of billing-related classes you can use to implement in-app billing in your application. It also contains examples of the database, user interface, and business logic you might use to implement in-app billing.</p>
<p class="caution"><strong>Important</strong>: Although the sample application is a working example of how you can implement in-app billing, we <em>strongly recommend</em> that you modify and obfuscate the sample code before you use it in a production application. For more information, see <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
-<div style="margin:2em 1em 1em 1em;">
-<img src="{@docRoot}images/billing_checkout_flow.png" style="text-align:left;" />
-<div style="margin:.25em 1.25em;padding:0"><strong>Figure 1.</strong> Applications initiate in-app billing requests through their own UI (first screen). Android Market responds to the request by providing the checkout user interface (middle screen). When checkout is complete, the application resumes.</div>
-</div>
+<img src="{@docRoot}images/billing_checkout_flow.png" height="382" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Applications initiate in-app billing requests through their own UI (first screen). Android Market responds to the request by providing the checkout user interface (middle screen). When checkout is complete, the application resumes.
+</p>
-<p>To learn more about the in-app billing service and start integrating in-app billing into your applications, read the following documents:</p>
+<p>To learn more about Android Market's in-app billing service and start integrating it into your applications, read the following documents:</p>
<dl>
<dt><strong><a href="{@docRoot}guide/market/billing/billing_overview.html">Overview of In-app Billing</a></strong></dt>
diff --git a/docs/html/guide/practices/design/accessibility.jd b/docs/html/guide/practices/design/accessibility.jd
new file mode 100644
index 0000000..a2b314e
--- /dev/null
+++ b/docs/html/guide/practices/design/accessibility.jd
@@ -0,0 +1,351 @@
+page.title=Designing for Accessibility
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+ <h2>Quickview</h2>
+ <ul>
+ <li>To make your application more accessible, you should make sure your UI is navigable
+using a directional controller and your widgets provide content descriptions</li>
+ <li>If you implement a custom view, you should ensure that it delivers the appropriate
+accessibility events during user interaction</li>
+ </ul>
+
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#Navigation">Allow Navigation with a Directional Controller</a>
+ <ol>
+ <li><a href="#FocusOrder">Controlling focus order</a></li>
+ <li><a href="#ClickingDpad">Clicking with a directional controller</a></li>
+ </ol>
+ </li>
+ <li><a href="#LabelInputs">Label Your Input Widgets</a></li>
+ <li><a href="#UiBestPractices">Follow Android UI Best Practices</a></li>
+ <li><a href="#CustomViews">Send Accessibility Events from Custom View Components</a></li>
+ <li><a href="#Test">Test Your Application’s Accessibility</a></li>
+ </ol>
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.view.accessibility.AccessibilityEvent}</li>
+ <li>{@link android.view.accessibility.AccessibilityEventSource}</li>
+ </ol>
+
+ <h2>Related samples</h2>
+ <ol>
+ <li><a
+href="{@docRoot}resources/samples/AccessibilityService/index.html">Accessibility Service</a></li>
+ </ol>
+
+</div>
+</div>
+
+
+
+<p>Many Android users have disabilities that require them to interact with their Android devices in
+different ways. These include users who have visual, physical or age-related disabilities that
+prevent them from fully using or seeing a touchscreen.</p>
+
+<p>Android provides an accessibility layer that helps these users navigate their Android-powered
+devices more easily. Android's accessibility services provide things like text-to-speech, haptic
+feedback, and trackball/d-pad navigation that augment the user experience.</p>
+
+<p>Your application should follow the guidelines in this document to ensure that it provides a
+good experience for users with disabilities. Following these two basic rules will solve most
+access-related problems:</p>
+
+<ul>
+<li>Make all of your user interface controls accessible with a trackball or directional
+controller (d-pad).</li>
+<li>Label your {@link android.widget.ImageButton}, {@link android.widget.EditText}, and other input
+widgets using the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
+>{@code android:contentDescription}</a> attribute.</li>
+</ul>
+
+
+
+<h2 id="Navigation">Allow Navigation with a Directional Controller</h2>
+
+<p>Many Android devices come with some sort of directional controller, such as:</p>
+<ul>
+<li>A clickable trackball that users can move in any direction</li>
+<li>A clickable d-pad that allows users to navigate in four directions.</li>
+<li>Arrow keys and an OK button that’s equivalent to clicking a trackball or d-pad.</li>
+</ul>
+
+<p>All of these directional controllers allow users to navigate the screen without using the
+touchscreen. On some devices, a user can also navigate to the top or bottom of a list by holding
+down the <em>alt</em> key while pressing a discrete key for up or down.</p>
+
+<p>A directional controller is the primary means of navigation for users with visual or some
+physical impairments (and also for users without impairments when using devices that don't
+have a touchscreen). You should verify that all UI controls in your application are
+accessible without using the touchscreen and that clicking with the center button (or OK button) has
+the same effect as touching the controls on the touchscreen.</p>
+
+<p>A UI control (also called a "widget") is accessible using directional controls when it's
+"focusable" property is "true." This means that users can focus on the widget using the directional
+controls and then interact with it. Widgets provided by the Android APIs are focusable by default
+and visually indicate focus by changing the widget visual appearance in some way.</p>
+
+<p>Android provides several APIs that let you control whether a widget is focusable and even
+request that a widget be given focus. Such methods include:</p>
+
+<ul>
+ <li>{@link android.view.View#setFocusable setFocusable()}</li>
+ <li>{@link android.view.View#isFocusable isFocusable()}</li>
+ <li>{@link android.view.View#requestFocus requestFocus()}</li>
+</ul>
+
+<p>When working with a view that is not focusable by default, you can make it focusable from the XML
+layout file by setting the <a href="{@docRoot}reference/android/view/View#attr_android:focusable"
+>{@code android:focusable}</a> attribute to {@code "true"}.</p>
+
+
+
+<h3 id="FocusOrder">Controlling focus order</h3>
+
+<p>When the user navigates in any direction using the directional controls, focus is passed from one
+view to another, as determined by the focus ordering. The ordering of the focus movement is based on
+an algorithm that finds the nearest neighbor in a given direction. In rare cases, the default
+algorithm may not match the order that you intended for your UI. In these situations, you can
+provide explicit overrides to the ordering using the following XML attributes in the layout
+file:</p>
+
+<dl>
+ <dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusDown"
+>{@code android:nextFocusDown}</a></dt>
+ <dd>Defines the next view to receive focus when the user navigates down.</dd>
+ <a><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusLeft"
+>{@code android:nextFocusLeft}</a></dt>
+ <dd>Defines the next view to receive focus when the user navigates left.</dd>
+ <dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusRight"
+>{@code android:nextFocusRight}</a></dt>
+ <dd>Defines the next view to receive focus when the user navigates right.</dd>
+ <dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusUp"
+>{@code android:nextFocusUp}</a></dt>
+ <dd>Defines the next view to receive focus when the user navigates up.</dd>
+</dl>
+
+<p>For example, here is an XML layout that contains a focusable {@link android.widget.TextView}.
+While the {@link android.widget.TextView} is located to the right of the {@link
+android.widget.EditText}, it can now be reached by pressing the down arrow when focus is on the
+{@link android.widget.EditText}: </p>
+
+<pre>
+<LinearLayout android:orientation="horizontal"
+ ... >
+ <EditText android:id="@+id/edit"
+ android:nextFocusDown=”@+id/text”
+ ... />
+ <TextView android:id="@+id/text"
+ android:focusable=”true”
+ android:text="Hello, I am a focusable TextView"
+ android:nextFocusUp=”@id/edit”
+ ... />
+</LinearLayout>
+</pre>
+
+<p>When modifying this ordering, be sure that the navigation works as expected in all directions
+from each widget and when navigating in reverse (to get back to where you came from).</p>
+
+<p>You can also modify the focus ordering at runtime, using methods in the {@link
+android.view.View} class, such as {@link android.view.View#setNextFocusDownId
+setNextFocusDownId()} and {@link android.view.View#setNextFocusRightId
+setNextFocusRightId()}.</p>
+
+
+<h3 id="ClickingDpad">Clicking with a directional controller</h3>
+
+<p>On most devices, clicking a view using a directional controller sends a {@link
+android.view.KeyEvent} with {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER} to the view currently
+in focus. Make sure this event has the same effect as touching the view on the touchscreen. All
+standard Android views already handle {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}
+appropriately.</p>
+
+<p>If possible, also treat the {@link android.view.KeyEvent#KEYCODE_ENTER} event the same as
+{@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}. That makes interaction much easier from a full
+keyboard.</p>
+
+
+
+
+<h2 id="LabelInputs">Label Your Input Widgets</h2>
+
+<p>Many input widgets rely on visual cues to inform the user of their meaning. For example, a
+notepad application might use an {@link android.widget.ImageButton} with a picture of a plus sign to
+indicate that the user can add a new note. Or, an {@link android.widget.EditText} may have
+a label near it that indicates its purpose. When a visually impaired user accesses your
+application, these visual cues are often useless.</p>
+
+<p>To provide textual information about these widgets (as an alternative to the visual cues), you
+should use the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
+>{@code android:contentDescription}</a> attribute. The text you provide in this attribute
+is not visible on the screen, but if a user has enabled accessibility speech tools then the
+description in this attribute is read aloud to the user.</p>
+
+<p>You should set the <a
+href="{@docRoot}reference/android/view/View#attr_android:contentDescription" >{@code
+android:contentDescription}</a> attribute on every {@link android.widget.ImageButton}, {@link
+android.widget.EditText}, {@link android.widget.CheckBox}, and on any other input widgets that might
+benefit users with extra information.</p>
+
+<p>For example, the following {@link android.widget.ImageButton} sets the content description for
+the plus button to the {@code add_note} string resource, which might be defined in English as
+“Add note":</p>
+
+<pre>
+<ImageButton
+ android:id=”@+id/add_entry_button”
+ android:src=”@drawable/plus”
+ android:contentDescription=”@string/add_note”/>
+</pre>
+
+<p>This way, when using speech accessibility tools, the user hears "Add note" when focused on
+this widget.</p>
+
+
+
+<h2 id="UiBestPractices">Follow Android UI Best Practices</h2>
+
+<p>You can make it easier for users to learn how to use your application by developing a user
+interface that complies with Android's standard interaction patterns, instead of creating your own
+or using interaction patterns from another platform. This consistency is especially important for
+many disabled users, as they may have less contextual information available to try to understand
+your application’s interface.</p>
+
+<p>Specifically, you should:</p>
+
+<ul>
+<li>Use the platform's built-in widgets and layouts whenever possible, as these views provide
+accessibility support by default.</li>
+<li>Use the <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> as an
+alternative to complex touchscreen tasks.</li>
+<li>Make sure the BACK button correctly moves the user back one logical step in the <a
+href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">task's back stack</a> or the
+activity's back stack of fragments (when <a
+href="{@docRoot}guide/topics/fundamentals/fragments.html#Transactions">performing fragment
+transactions</a>), as appropriate.</li>
+</ul>
+
+
+
+<h2 id="CustomViews">Send Accessibility Events from Custom View Components</h2>
+
+<p>If your application requires that you create a <a
+href="{@docRoot}guide/topics/ui/custom-components.html">custom view component</a>, you may need to
+do some additional work to ensure that your view is accessible. Specifically, you should make sure
+that your view implements the {@link android.view.accessibility.AccessibilityEventSource}
+interface and emits {@link android.view.accessibility.AccessibilityEvent}s at the proper times,
+and that each {@link android.view.accessibility.AccessibilityEvent} contains relevant information
+about the state of the view.</p>
+
+<p>Events are emitted whenever something notable happens in the user interface. Currently, there
+are five types of accessibility events that a view should send to the system as the user interacts
+with it:</p>
+
+<dl>
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED}</dt>
+<dd>Indicates that the user clicked on the view (for example, the user selects a button).</dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</dt>
+<dd>Indicates that the user performed a long press on the view. </dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED}</dt>
+<dd>Indicates that the user selected an item from within the view. This is usually used in the
+context of an {@link android.widget.AdapterView}.</dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED}</dt>
+<dd>Indicates that the user moved the focus to the view.</dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</dt>
+<dd>Indicates that the text or contents of the view changed.</dd>
+</dl>
+
+
+<p>The basic {@link android.view.View} class implements {@link
+android.view.accessibility.AccessibilityEventSource} and emits these events at the proper time in
+the standard cases. Your custom view should extend from {@link android.view.View} (or one of its
+subclasses) to take advantage of these default implementations.</p>
+
+<p>Depending on the specifics of your custom view, your view may need to emit one of these events at
+a different time than the default {@link android.view.View} implementation. To do so, simply call
+{@link android.view.accessibility.AccessibilityEventSource#sendAccessibilityEvent
+sendAccessibilityEvent()} with the specific event type at the correct time.</p>
+
+<p>For example, say you are implementing a custom slider bar that allows the user to select a
+numeric value by pressing the left or right arrows. This view should emit an event of type {@link
+android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} whenever the slider value
+changes:</p>
+
+<pre>
+@Override
+public boolean onKeyUp (int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+ mCurrentValue--;
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+ return true;
+ }
+ ...
+}
+</pre>
+
+<p>Each {@link android.view.accessibility.AccessibilityEvent} has a set of required properties that
+describe the current state of the view. These properties include things like the view’s class name,
+text and checked state. The specific properties required for each event type are described in the
+{@link android.view.accessibility.AccessibilityEvent} documentation. The {@link android.view.View}
+implementation will fill in default values for these properties. Most of these values, like the
+class name and event timestamp, will not need to be changed. However, depending on the specifics of
+your custom view, you may want to provide a different value for one or more of the properties. For
+example, your view may have additional state information that you want to add to the event text.</p>
+
+<p>The {@link android.view.View#dispatchPopulateAccessibilityEvent
+dispatchPopulateAccessibilityEvent()} method in {@link android.view.View} provides a hook for making
+changes to the {@link android.view.accessibility.AccessibilityEvent} object before it is
+emitted.</p>
+
+<p>In the above slider bar example, the view should add the current value of the slider bar to the
+text of the event:</p>
+
+<pre>
+@Override
+public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) {
+ super.dispatchPopulateAccessibilityEvent(event);
+ if (!isShown()) {
+ return false;
+ }
+ CharSequence text = String.valueOf(mCurrentValue);
+ if (text.length() > AccessibilityEvent.MAX_TEXT_LENGTH) {
+ text = text.subSequence(0, AccessiblityEvent.MAX_TEXT_LENGTH);
+ }
+ event.getText().add(text);
+ return true;
+}
+</pre>
+
+
+<h2 id="Test">Test Your Application’s Accessibility</h2>
+
+<p>You can simulate the experience for many users by enabling an accessibility service that speaks
+as you move around the screen. One such service is <a
+href="https://market.android.com/details?id=com.google.android.marvin.talkback">TalkBack</a>, by the
+<a href="http://code.google.com/p/eyes-free/">Eyes-Free Project</a>. It comes preinstalled on many
+Android-powered devices, but is also available for free from <a
+href="https://market.android.com/details?id=com.google.android.marvin.talkback">Android
+Market</a>.</p>
+
+<p>This service requires that you have a text-to-speech engine installed on your phone. You can
+verify if you have one installed in the <strong>Text-to-speech</strong> settings menu by selecting
+<strong>Listen to an example</strong>. If you do not hear anything spoken, install the required
+voice data by selecting <strong>Install voice data</strong>.</p>
+
+<p>Once text-to-speech is functioning correctly, you can enable TalkBack (or another accessibility
+service) in the <strong>Accessibility</strong> settings menu. Enable both
+<strong>Accessibility</strong> and <strong>TalkBack</strong>. As you navigate about the device, you
+should now hear spoken feedback.</p>
+
+<p>You can now attempt to use your application as a blind user would. As you move around using only
+the directional controller, make sure that the spoken feedback you hear makes sense and is
+sufficient to navigate the application without any visual cues.</p>
diff --git a/docs/html/images/billing_list_form.png b/docs/html/images/billing_list_form.png
index ee30de3..de7ea22 100755
--- a/docs/html/images/billing_list_form.png
+++ b/docs/html/images/billing_list_form.png
Binary files differ
diff --git a/docs/html/images/billing_product_list.png b/docs/html/images/billing_product_list.png
index 5b8d174..49a7e79 100755
--- a/docs/html/images/billing_product_list.png
+++ b/docs/html/images/billing_product_list.png
Binary files differ
diff --git a/docs/html/images/billing_product_list_entry.png b/docs/html/images/billing_product_list_entry.png
new file mode 100755
index 0000000..df3f9a8
--- /dev/null
+++ b/docs/html/images/billing_product_list_entry.png
Binary files differ
diff --git a/docs/html/images/billing_refund.png b/docs/html/images/billing_refund.png
new file mode 100755
index 0000000..09fc33c
--- /dev/null
+++ b/docs/html/images/billing_refund.png
Binary files differ
diff --git a/docs/html/images/billing_request_purchase.png b/docs/html/images/billing_request_purchase.png
index e8a1b30..c84016e 100755
--- a/docs/html/images/billing_request_purchase.png
+++ b/docs/html/images/billing_request_purchase.png
Binary files differ
diff --git a/docs/html/images/billing_restore_transactions.png b/docs/html/images/billing_restore_transactions.png
index 116aa0e..7911304 100755
--- a/docs/html/images/billing_restore_transactions.png
+++ b/docs/html/images/billing_restore_transactions.png
Binary files differ
diff --git a/docs/html/images/drm_arch.png b/docs/html/images/drm_arch.png
new file mode 100755
index 0000000..1696a97
--- /dev/null
+++ b/docs/html/images/drm_arch.png
Binary files differ
diff --git a/docs/html/sdk/android-3.0-highlights.jd b/docs/html/sdk/android-3.0-highlights.jd
index ebeb3789..d4fd002 100644
--- a/docs/html/sdk/android-3.0-highlights.jd
+++ b/docs/html/sdk/android-3.0-highlights.jd
@@ -121,7 +121,7 @@
<div style="padding-top:0em;">
<div style="margin-right:1em;float:right;;padding-top:0em;margin-left:1em;"><a href="images/3.0/browser_full.png" target="_android"><img src="images/3.0/browser.png" alt="" height="200" /></a><br>
-<a href="images/3.0/camera_full.png" target="_android"><img src="images/3.0/camera_full.png" alt="" height="200" /></a></div>
+<a href="images/3.0/camera_full.png" target="_android"><img src="images/3.0/camera.png" alt="" height="200" /></a></div>
<p>The Android 3.0 platform includes an updated set of standard applications that are designed for use on larger screen devices. The sections below highlight some of the new features. </p>
diff --git a/docs/html/sdk/images/3.0/copy.png b/docs/html/sdk/images/3.0/copy.png
index a15c1cd..d5a4c3e 100644
--- a/docs/html/sdk/images/3.0/copy.png
+++ b/docs/html/sdk/images/3.0/copy.png
Binary files differ
diff --git a/docs/html/sdk/oem-usb.jd b/docs/html/sdk/oem-usb.jd
index e64c8d2..882a433 100644
--- a/docs/html/sdk/oem-usb.jd
+++ b/docs/html/sdk/oem-usb.jd
@@ -33,14 +33,17 @@
<th>OEM</th>
<th>Driver URL</th></tr>
<tr><td>Acer</td> <td><a
-href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/
-mobile.html</a>
+href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/mobile.html</a>
</td></tr>
-
-<tr><td>Dell</td> <td>
+ <tr>
+ <td>Asus</td>
+ <td><a href="http://support.asus.com/download/">http://support.asus.com/download/</a></td>
+ </tr>
+ <tr><td>
+ Dell
+ </td> <td>
<a
-href="http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml">http://
-support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml</a> </td></tr>
+href="http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml">http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml</a> </td></tr>
<tr><td>Foxconn</td> <td><a
href="http://drivers.cmcs.com.tw/">http://drivers.cmcs.com.tw/</a></td>
@@ -56,17 +59,14 @@
<tr><td>
Garmin-Asus
</td> <td><a
-href="https://www.garminasus.com/en_US/support/pcsync/">https://www.garminasus.com/en_US/support/
-pcsync/</a></td>
+href="https://www.garminasus.com/en_US/support/pcsync/">https://www.garminasus.com/en_US/support/pcsync/</a></td>
</tr><tr><td>HTC</td> <td><a href="http://www.htc.com">http://www.htc.com </a> <br>Click on the
support tab to select your products/device. Different regions will have different links.</td>
</tr>
<tr><td>Huawei</td> <td><a
-href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0">http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&
-directoryId=20&treeId=0</a></td>
+href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0">http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0</a></td>
</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>
@@ -76,26 +76,19 @@
</td>
</tr>
<tr><td>LGE</td> <td><a
-href="http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp">http://
-www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp</a></td>
+href="http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp">http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp</a></td>
</tr><tr><td>Motorola</td> <td><a
-href="http://developer.motorola.com/docstools/USB_Drivers/">http://developer.motorola.com/docstools/
-USB_Drivers/</a></td>
+href="http://developer.motorola.com/docstools/USB_Drivers/">http://developer.motorola.com/docstools/USB_Drivers/</a></td>
</tr><tr><td>Pantech</td> <td><a
-href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/
-software/software.sky?fromUrl=index</a></td>
+href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/software/software.sky?fromUrl=index</a></td>
</tr><tr><td>Samsung</td> <td><a
-href="http://www.samsung.com/us/support/downloads">http://www.samsung.com/us/support/downloads</a></
-td>
+href="http://www.samsung.com/us/support/downloads">http://www.samsung.com/us/support/downloads</a></td>
</tr><tr><td>Sharp</td> <td><a
href="http://k-tai.sharp.co.jp/support/">http://k-tai.sharp.co.jp/support/</a></td>
</tr><tr><td>SK Telesys</td> <td><a
-href="http://www.sk-w.com/service/wDownload/wDownload.jsp">http://www.sk-w.com/service/wDownload/
-wDownload.jsp</a></td></tr><tr>
+href="http://www.sk-w.com/service/wDownload/wDownload.jsp">http://www.sk-w.com/service/wDownload/wDownload.jsp</a></td></tr><tr>
<td>Sony Ericsson</td> <td><a
-href="http://developer.sonyericsson.com/wportal/devworld/search-downloads/android">http://developer.
-sonyericsson.com/wportal/devworld/search-downloads/android</a></td></tr><tr>
+href="http://developer.sonyericsson.com/wportal/devworld/search-downloads/android">http://developer.sonyericsson.com/wportal/devworld/search-downloads/android</a></td></tr><tr>
<td>ZTE</td> <td><a
-href="http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp">http://www.zte.com.cn/cn/
-products/mobile/services_support/index.jsp</a></td></tr>
+href="http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp">http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp</a></td></tr>
</table>
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
index c0bff0e..3dee435 100644
--- a/drm/common/DrmSupportInfo.cpp
+++ b/drm/common/DrmSupportInfo.cpp
@@ -15,6 +15,7 @@
*/
#include <drm/DrmSupportInfo.h>
+#include <strings.h>
using namespace android;
@@ -152,4 +153,3 @@
mIndex++;
return value;
}
-
diff --git a/drm/java/android/drm/DrmConvertedStatus.java b/drm/java/android/drm/DrmConvertedStatus.java
old mode 100644
new mode 100755
index f200552..cecb135
--- a/drm/java/android/drm/DrmConvertedStatus.java
+++ b/drm/java/android/drm/DrmConvertedStatus.java
@@ -17,13 +17,11 @@
package android.drm;
/**
- * This is an entity class which wraps the status of the conversion, the converted
- * data/checksum data and the offset. Offset is going to be used in the case of close
- * session where the agent will inform where the header and body signature should be added
- *
- * As a result of {@link DrmManagerClient#convertData(int, byte [])} and
- * {@link DrmManagerClient#closeConvertSession(int)} an instance of DrmConvertedStatus
- * would be returned.
+ * An entity class that wraps converted data, conversion status, and the
+ * offset for appending the header and body signature to the converted data. An instance of this
+ * class is returned by the {@link DrmManagerClient#convertData convertData()} and
+ * {@link DrmManagerClient#closeConvertSession closeConvertSession()} methods. The offset is provided only when a
+ * conversion session is closed by calling {@link DrmManagerClient#closeConvertSession closeConvertSession()}.
*
*/
public class DrmConvertedStatus {
@@ -32,16 +30,19 @@
public static final int STATUS_INPUTDATA_ERROR = 2;
public static final int STATUS_ERROR = 3;
+ /** Status code for the conversion.*/
public final int statusCode;
+ /** Converted data.*/
public final byte[] convertedData;
+ /** Offset value for the body and header signature.*/
public final int offset;
/**
- * constructor to create DrmConvertedStatus object with given parameters
+ * Creates a <code>DrmConvertedStatus</code> object with the specified parameters.
*
- * @param _statusCode Status of the conversion
- * @param _convertedData Converted data/checksum data
- * @param _offset Offset value
+ * @param _statusCode Conversion status.
+ * @param _convertedData Converted data.
+ * @param _offset Offset value for appending the header and body signature.
*/
public DrmConvertedStatus(int _statusCode, byte[] _convertedData, int _offset) {
statusCode = _statusCode;
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
old mode 100644
new mode 100755
index 7cc9a87..2cb82e6
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -19,70 +19,69 @@
import java.util.HashMap;
/**
- * This is an entity class which would be passed to caller in
- * {@link DrmManagerClient.OnErrorListener#onError(DrmManagerClient, DrmErrorEvent)}
+ * An entity class that is passed to the
+ * {@link DrmManagerClient.OnErrorListener#onError onError()} callback.
*
*/
public class DrmErrorEvent extends DrmEvent {
/**
- * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights.
+ * Something went wrong installing the rights.
*/
public static final int TYPE_RIGHTS_NOT_INSTALLED = 2001;
/**
- * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights.
+ * The server rejected the renewal of rights.
*/
public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002;
/**
- * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent.
+ * Response from the server cannot be handled by the DRM plug-in (agent).
*/
public static final int TYPE_NOT_SUPPORTED = 2003;
/**
- * TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
- * Can in the future perhaps be used to trigger garbage collector.
+ * Memory allocation failed during renewal. Can in the future perhaps be used to trigger
+ * garbage collector.
*/
public static final int TYPE_OUT_OF_MEMORY = 2004;
/**
- * TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
- * can be made to renew rights.
+ * An Internet connection is not available and no attempt can be made to renew rights.
*/
public static final int TYPE_NO_INTERNET_CONNECTION = 2005;
/**
- * TYPE_PROCESS_DRM_INFO_FAILED, when failed to process DrmInfo.
+ * Failed to process {@link DrmInfo}. This error event is sent when a
+ * {@link DrmManagerClient#processDrmInfo processDrmInfo()} call fails.
*/
public static final int TYPE_PROCESS_DRM_INFO_FAILED = 2006;
/**
- * TYPE_REMOVE_ALL_RIGHTS_FAILED, when failed to remove all the rights objects
- * associated with all DRM schemes.
+ * Failed to remove all the rights objects associated with all DRM schemes.
*/
public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
/**
- * TYPE_ACQUIRE_DRM_INFO_FAILED, when failed to acquire DrmInfo.
+ * Failed to acquire {@link DrmInfo}. This error event is sent when an
+ * {@link DrmManagerClient#acquireDrmInfo acquireDrmInfo()} call fails.
*/
public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
/**
- * constructor to create DrmErrorEvent object with given parameters
+ * Creates a <code>DrmErrorEvent</code> object with the specified parameters.
*
- * @param uniqueId Unique session identifier
- * @param type Type of the event. It could be one of the types defined above
- * @param message Message description
+ * @param uniqueId Unique session identifier.
+ * @param type Type of the event. Could be any of the event types defined above.
+ * @param message Message description.
*/
public DrmErrorEvent(int uniqueId, int type, String message) {
super(uniqueId, type, message);
}
/**
- * constructor to create DrmErrorEvent object with given parameters
+ * Creates a <code>DrmErrorEvent</code> object with the specified parameters.
*
- * @param uniqueId Unique session identifier
- * @param type Type of the event. It could be one of the types defined above
- * @param message Message description
+ * @param uniqueId Unique session identifier.
+ * @param type Type of the event. Could be any of the event types defined above.
+ * @param message Message description.
* @param attributes Attributes for extensible information. Could be any
- * information provided by the plugin
+ * information provided by the plug-in.
*/
public DrmErrorEvent(int uniqueId, int type, String message,
HashMap<String, Object> attributes) {
super(uniqueId, type, message, attributes);
}
}
-
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
old mode 100644
new mode 100755
index eba458b..4053eb3
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -19,22 +19,26 @@
import java.util.HashMap;
/**
- * This is the base class which would be used to notify the caller
- * about any event occurred in DRM framework.
+ * A base class that is used to send asynchronous event information from the DRM framework.
*
*/
public class DrmEvent {
/**
- * Constant field signifies that all the rights information associated with
- * all DRM schemes are removed successfully
+ * All of the rights information associated with all DRM schemes have been successfully removed.
*/
public static final int TYPE_ALL_RIGHTS_REMOVED = 1001;
/**
- * Constant field signifies that given information is processed successfully
+ * The given DRM information has been successfully processed.
*/
public static final int TYPE_DRM_INFO_PROCESSED = 1002;
-
+ /**
+ * The key that is used in the <code>attributes</code> HashMap to pass the return status.
+ */
public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+ /**
+ * The key that is used in the <code>attributes</code> HashMap to pass the
+ * {@link DrmInfo} object.
+ */
public static final String DRM_INFO_OBJECT = "drm_info_object";
private final int mUniqueId;
@@ -44,12 +48,12 @@
private HashMap<String, Object> mAttributes = new HashMap<String, Object>();
/**
- * constructor for DrmEvent class
+ * Creates a <code>DrmEvent</code> object with the specified parameters.
*
- * @param uniqueId Unique session identifier
- * @param type Type of information
- * @param message Message description
- * @param attributes Attributes for extensible information
+ * @param uniqueId Unique session identifier.
+ * @param type Type of information.
+ * @param message Message description.
+ * @param attributes Attributes for extensible information.
*/
protected DrmEvent(int uniqueId, int type, String message,
HashMap<String, Object> attributes) {
@@ -66,11 +70,11 @@
}
/**
- * constructor for DrmEvent class
+ * Creates a <code>DrmEvent</code> object with the specified parameters.
*
- * @param uniqueId Unique session identifier
- * @param type Type of information
- * @param message Message description
+ * @param uniqueId Unique session identifier.
+ * @param type Type of information.
+ * @param message Message description.
*/
protected DrmEvent(int uniqueId, int type, String message) {
mUniqueId = uniqueId;
@@ -82,40 +86,39 @@
}
/**
- * Returns the Unique Id associated with this object
+ * Retrieves the unique session identifier associated with this object.
*
- * @return Unique Id
+ * @return The unique session identifier.
*/
public int getUniqueId() {
return mUniqueId;
}
/**
- * Returns the Type of information associated with this object
+ * Retrieves the type of information that is associated with this object.
*
- * @return Type of information
+ * @return The type of information.
*/
public int getType() {
return mType;
}
/**
- * Returns the message description associated with this object
+ * Retrieves the message description associated with this object.
*
- * @return message description
+ * @return The message description.
*/
public String getMessage() {
return mMessage;
}
/**
- * Returns the attribute corresponding to the specified key
+ * Retrieves the attribute associated with the specified key.
*
- * @return one of the attributes or null if no mapping for
- * the key is found
+ * @return One of the attributes or null if no mapping for
+ * the key is found.
*/
public Object getAttribute(String key) {
return mAttributes.get(key);
}
}
-
diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java
old mode 100644
new mode 100755
index 7d3fbf1..8812bfe
--- a/drm/java/android/drm/DrmInfo.java
+++ b/drm/java/android/drm/DrmInfo.java
@@ -21,14 +21,13 @@
import java.util.Iterator;
/**
- * This is an entity class in which necessary information required to transact
- * between device and online DRM server is described. DRM Framework achieves
- * server registration, license acquisition and any other server related transaction
- * by passing an instance of this class to {@link DrmManagerClient#processDrmInfo(DrmInfo)}.
- *
- * Caller can retrieve the {@link DrmInfo} instance by using
- * {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)}
- * by passing {@link DrmInfoRequest} instance.
+ * An entity class that describes the information required to send transactions
+ * between a device and an online DRM server. The DRM framework achieves
+ * server registration, license acquisition, and any other server-related transactions
+ * by passing an instance of this class to {@link DrmManagerClient#processDrmInfo}.
+ *<p>
+ * The caller can retrieve the {@link DrmInfo} instance by passing a {@link DrmInfoRequest}
+ * instance to {@link DrmManagerClient#acquireDrmInfo}.
*
*/
public class DrmInfo {
@@ -40,11 +39,11 @@
private final HashMap<String, Object> mAttributes = new HashMap<String, Object>();
/**
- * constructor to create DrmInfo object with given parameters
+ * Creates a <code>DrmInfo</code> object with the given parameters.
*
- * @param infoType Type of information
- * @param data Trigger data
- * @param mimeType MIME type
+ * @param infoType The type of information.
+ * @param data The trigger data.
+ * @param mimeType The MIME type.
*/
public DrmInfo(int infoType, byte[] data, String mimeType) {
mInfoType = infoType;
@@ -53,11 +52,11 @@
}
/**
- * constructor to create DrmInfo object with given parameters
+ * Creates a <code>DrmInfo</code> object with the given parameters.
*
- * @param infoType Type of information
- * @param path Trigger data
- * @param mimeType MIME type
+ * @param infoType The type of information.
+ * @param path The trigger data.
+ * @param mimeType The MIME type.
*/
public DrmInfo(int infoType, String path, String mimeType) {
mInfoType = infoType;
@@ -73,67 +72,70 @@
}
/**
- * Adds optional information as <key, value> pair to this object
+ * Adds optional information as key-value pairs to this object. To add a custom object
+ * to the <code>DrmInfo</code> object, you must override the {@link #toString} implementation.
*
- * @param key Key to add
- * @param value Value to add
- * To put custom object into DrmInfo, custom object has to
- * override toString() implementation.
+ * @param key Key to add.
+ * @param value Value to add.
+ *
*/
public void put(String key, Object value) {
mAttributes.put(key, value);
}
/**
- * Retrieves the value of given key, if not found returns null
+ * Retrieves the value of a given key.
*
- * @param key Key whose value to be retrieved
- * @return The value or null
+ * @param key The key whose value is being retrieved.
+ *
+ * @return The value of the key being retrieved. Returns null if the key cannot be found.
*/
public Object get(String key) {
return mAttributes.get(key);
}
/**
- * Returns Iterator object to walk through the keys associated with this instance
+ * Retrieves an iterator object that you can use to iterate over the keys associated with
+ * this <code>DrmInfo</code> object.
*
- * @return Iterator object
+ * @return The iterator object.
*/
public Iterator<String> keyIterator() {
return mAttributes.keySet().iterator();
}
/**
- * Returns Iterator object to walk through the values associated with this instance
+ * Retrieves an iterator object that you can use to iterate over the values associated with
+ * this <code>DrmInfo</code> object.
*
- * @return Iterator object
+ * @return The iterator object.
*/
public Iterator<Object> iterator() {
return mAttributes.values().iterator();
}
/**
- * Returns the trigger data associated with this object
+ * Retrieves the trigger data associated with this object.
*
- * @return Trigger data
+ * @return The trigger data.
*/
public byte[] getData() {
return mData;
}
/**
- * Returns the mimetype associated with this object
+ * Retrieves the MIME type associated with this object.
*
- * @return MIME type
+ * @return The MIME type.
*/
public String getMimeType() {
return mMimeType;
}
/**
- * Returns information type associated with this instance
+ * Retrieves the information type associated with this object.
*
- * @return Information type
+ * @return The information type.
*/
public int getInfoType() {
return mInfoType;
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
old mode 100644
new mode 100755
index 190199a..67aa0a9
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -19,58 +19,56 @@
import java.util.HashMap;
/**
- * This is an entity class which would be passed to caller in
- * {@link DrmManagerClient.OnInfoListener#onInfo(DrmManagerClient, DrmInfoEvent)}
+ * An entity class that is passed to the
+ * {@link DrmManagerClient.OnInfoListener#onInfo onInfo()} callback.
*
*/
public class DrmInfoEvent extends DrmEvent {
/**
- * TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been already done
- * by another account ID.
+ * The registration has already been done by another account ID.
*/
public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1;
/**
- * TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
+ * The rights need to be removed completely.
*/
public static final int TYPE_REMOVE_RIGHTS = 2;
/**
- * TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
+ * The rights have been successfully downloaded and installed.
*/
public static final int TYPE_RIGHTS_INSTALLED = 3;
/**
- * TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone,
- * wait before calling checkRights again.
+ * The rights object is being delivered to the device. You must wait before
+ * calling {@link DrmManagerClient#acquireRights acquireRights()} again.
*/
public static final int TYPE_WAIT_FOR_RIGHTS = 4;
/**
- * TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
- * already done for the given account.
+ * The registration has already been done for the given account.
*/
public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
/**
- * TYPE_RIGHTS_REMOVED, when the rights has been removed.
+ * The rights have been removed.
*/
public static final int TYPE_RIGHTS_REMOVED = 6;
/**
- * constructor to create DrmInfoEvent object with given parameters
+ * Creates a <code>DrmInfoEvent</code> object with the specified parameters.
*
- * @param uniqueId Unique session identifier
- * @param type Type of the event. It could be one of the types defined above
- * @param message Message description
+ * @param uniqueId Unique session identifier.
+ * @param type Type of the event. Could be any of the event types defined above.
+ * @param message Message description.
*/
public DrmInfoEvent(int uniqueId, int type, String message) {
super(uniqueId, type, message);
}
/**
- * constructor to create DrmInfoEvent object with given parameters
+ * Creates a <code>DrmInfoEvent</code> object with the specified parameters.
*
- * @param uniqueId Unique session identifier
- * @param type Type of the event. It could be one of the types defined above
- * @param message Message description
+ * @param uniqueId Unique session identifier.
+ * @param type Type of the event. Could be any of the event types defined above.
+ * @param message Message description.
* @param attributes Attributes for extensible information. Could be any
- * information provided by the plugin
+ * information provided by the plug-in.
*/
public DrmInfoEvent(int uniqueId, int type, String message,
HashMap<String, Object> attributes) {
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
old mode 100644
new mode 100755
index 366a342..2222ae8
--- a/drm/java/android/drm/DrmInfoRequest.java
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -20,30 +20,37 @@
import java.util.Iterator;
/**
- * This is an entity class used to pass required parameters to get
- * the necessary information to communicate with online DRM server
- *
- * An instance of this class is passed to {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)}
- * to get the instance of {@link DrmInfo}
+ * An entity class that is used to pass information to an online DRM server. An instance of this
+ * class is passed to the {@link DrmManagerClient#acquireDrmInfo acquireDrmInfo()} method to get an
+ * instance of a {@link DrmInfo}.
*
*/
public class DrmInfoRequest {
// Changes in following constants should be in sync with DrmInfoRequest.h
/**
- * Constants defines the type of {@link DrmInfoRequest}
+ * Acquires DRM server registration information.
*/
public static final int TYPE_REGISTRATION_INFO = 1;
+ /**
+ * Acquires information for unregistering the DRM server.
+ */
public static final int TYPE_UNREGISTRATION_INFO = 2;
+ /**
+ * Acquires rights information.
+ */
public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3;
+ /**
+ * Acquires the progress of the rights acquisition.
+ */
public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4;
/**
- * Key to pass the unique id for the account or the user
+ * Key that is used to pass the unique session ID for the account or the user.
*/
public static final String ACCOUNT_ID = "account_id";
/**
- * Key to pass the unique id used for subscription
+ * Key that is used to pass the unique session ID for the subscription.
*/
public static final String SUBSCRIPTION_ID = "subscription_id";
@@ -52,10 +59,10 @@
private final HashMap<String, Object> mRequestInformation = new HashMap<String, Object>();
/**
- * constructor to create DrmInfoRequest object with type and mimetype
+ * Creates a <code>DrmInfoRequest</code> object with type and MIME type.
*
- * @param infoType Type of information
- * @param mimeType MIME type
+ * @param infoType Type of information.
+ * @param mimeType MIME type.
*/
public DrmInfoRequest(int infoType, String mimeType) {
mInfoType = infoType;
@@ -63,56 +70,60 @@
}
/**
- * Returns the mimetype associated with this object
+ * Retrieves the MIME type associated with this object.
*
- * @return MIME type
+ * @return The MIME type.
*/
public String getMimeType() {
return mMimeType;
}
/**
- * Returns Information type associated with this instance
+ * Retrieves the information type associated with this object.
*
- * @return Information type
+ * @return The information type.
*/
public int getInfoType() {
return mInfoType;
}
/**
- * Adds optional information as <key, value> pair to this object.
+ * Adds optional information as key-value pairs to this object.
*
- * @param key Key to add
- * @param value Value to add
+ * @param key The key to add.
+ * @param value The value to add.
*/
public void put(String key, Object value) {
mRequestInformation.put(key, value);
}
/**
- * Retrieves the value of given key, if not found returns null
+ * Retrieves the value of a given key.
*
- * @param key Key whose value to be retrieved
- * @return The value or null
+ * @param key The key whose value is being retrieved.
+ *
+ * @return The value of the key that is being retrieved. Returns null if the key cannot be
+ * found.
*/
public Object get(String key) {
return mRequestInformation.get(key);
}
/**
- * Returns Iterator object to walk through the keys associated with this instance
+ * Retrieves an iterator object that you can use to iterate over the keys associated with
+ * this <code>DrmInfoRequest</code> object.
*
- * @return Iterator object
+ * @return The iterator object.
*/
public Iterator<String> keyIterator() {
return mRequestInformation.keySet().iterator();
}
/**
- * Returns Iterator object to walk through the values associated with this instance
+ * Retrieves an iterator object that you can use to iterate over the values associated with
+ * this <code>DrmInfoRequest</code> object.
*
- * @return Iterator object
+ * @return The iterator object.
*/
public Iterator<Object> iterator() {
return mRequestInformation.values().iterator();
diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java
old mode 100644
new mode 100755
index b37ea51..b04694b
--- a/drm/java/android/drm/DrmInfoStatus.java
+++ b/drm/java/android/drm/DrmInfoStatus.java
@@ -17,12 +17,12 @@
package android.drm;
/**
- * This is an entity class which wraps the result of communication between device
- * and online DRM server.
- *
- * As a result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} an instance of DrmInfoStatus
- * would be returned. This class holds {@link ProcessedData}, which could be used to instantiate
- * {@link DrmRights#DrmRights(ProcessedData, String)} in license acquisition.
+ * An entity class that wraps the result of communication between a device and an online DRM
+ * server. Specifically, when the {@link DrmManagerClient#processDrmInfo processDrmInfo()} method
+ * is called, an instance of <code>DrmInfoStatus</code> is returned.
+ *<p>
+ * This class contains the {@link ProcessedData} object, which can be used to instantiate a
+ * {@link DrmRights} object during license acquisition.
*
*/
public class DrmInfoStatus {
@@ -30,18 +30,30 @@
public static final int STATUS_OK = 1;
public static final int STATUS_ERROR = 2;
+ /**
+ * The status of the communication.
+ */
public final int statusCode;
+ /**
+ * The type of DRM information processed.
+ */
public final int infoType;
+ /**
+ * The MIME type of the content.
+ */
public final String mimeType;
+ /**
+ * The processed data.
+ */
public final ProcessedData data;
/**
- * constructor to create DrmInfoStatus object with given parameters
+ * Creates a <code>DrmInfoStatus</code> object with the specified parameters.
*
- * @param _statusCode Status of the communication
- * @param _infoType Type of the DRM information processed
- * @param _data The processed data
- * @param _mimeType MIME type
+ * @param _statusCode The status of the communication.
+ * @param _infoType The type of the DRM information processed.
+ * @param _data The processed data.
+ * @param _mimeType The MIME type.
*/
public DrmInfoStatus(int _statusCode, int _infoType, ProcessedData _data, String _mimeType) {
statusCode = _statusCode;
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
old mode 100644
new mode 100755
index f7479b5..f3a0343
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -35,18 +35,17 @@
import java.util.HashMap;
/**
- * Interface of DRM Framework.
- * Java application will instantiate this class
- * to access DRM agent through DRM Framework.
+ * The main programming interface for the DRM framework. An application must instantiate this class
+ * to access DRM agents through the DRM framework.
*
*/
public class DrmManagerClient {
/**
- * Constant field signifies the success or no error occurred
+ * Indicates that a request was successful or that no error occurred.
*/
public static final int ERROR_NONE = 0;
/**
- * Constant field signifies that error occurred and the reason is not known
+ * Indicates that an error occurred and the reason is not known.
*/
public static final int ERROR_UNKNOWN = -2000;
@@ -58,43 +57,45 @@
}
/**
- * Interface definition of a callback to be invoked to communicate
- * some info and/or warning about DrmManagerClient.
+ * Interface definition for a callback that receives status messages and warnings
+ * during registration and rights acquisition.
*/
public interface OnInfoListener {
/**
- * Called to indicate an info or a warning.
+ * Called when the DRM framework sends status or warning information during registration
+ * and rights acquisition.
*
- * @param client DrmManagerClient instance
- * @param event instance which wraps reason and necessary information
+ * @param client The <code>DrmManagerClient</code> instance.
+ * @param event The {@link DrmInfoEvent} instance that wraps the status information or
+ * warnings.
*/
public void onInfo(DrmManagerClient client, DrmInfoEvent event);
}
/**
- * Interface definition of a callback to be invoked to communicate
- * the result of time consuming APIs asynchronously
+ * Interface definition for a callback that receives information
+ * about DRM processing events.
*/
public interface OnEventListener {
/**
- * Called to indicate the result of asynchronous APIs.
+ * Called when the DRM framework sends information about a DRM processing request.
*
- * @param client DrmManagerClient instance
- * @param event instance which wraps type and message
+ * @param client The <code>DrmManagerClient</code> instance.
+ * @param event The {@link DrmEvent} instance that wraps the information being
+ * conveyed, such as the information type and message.
*/
public void onEvent(DrmManagerClient client, DrmEvent event);
}
/**
- * Interface definition of a callback to be invoked to communicate
- * the error occurred
+ * Interface definition for a callback that receives information about DRM framework errors.
*/
public interface OnErrorListener {
/**
- * Called to indicate the error occurred.
+ * Called when the DRM framework sends error information.
*
- * @param client DrmManagerClient instance
- * @param event instance which wraps error type and message
+ * @param client The <code>DrmManagerClient</code> instance.
+ * @param event The {@link DrmErrorEvent} instance that wraps the error type and message.
*/
public void onError(DrmManagerClient client, DrmErrorEvent event);
}
@@ -231,9 +232,9 @@
}
/**
- * To instantiate DrmManagerClient
+ * Creates a <code>DrmManagerClient</code>.
*
- * @param context context of the caller
+ * @param context Context of the caller.
*/
public DrmManagerClient(Context context) {
mContext = context;
@@ -257,10 +258,10 @@
}
/**
- * Register a callback to be invoked when the caller required to receive
- * supplementary information.
+ * Registers an {@link DrmManagerClient.OnInfoListener} callback, which is invoked when the
+ * DRM framework sends status or warning information during registration or rights acquisition.
*
- * @param infoListener
+ * @param infoListener Interface definition for the callback.
*/
public synchronized void setOnInfoListener(OnInfoListener infoListener) {
if (null != infoListener) {
@@ -269,10 +270,10 @@
}
/**
- * Register a callback to be invoked when the caller required to receive
- * the result of asynchronous APIs.
+ * Registers an {@link DrmManagerClient.OnEventListener} callback, which is invoked when the
+ * DRM framework sends information about DRM processing.
*
- * @param eventListener
+ * @param eventListener Interface definition for the callback.
*/
public synchronized void setOnEventListener(OnEventListener eventListener) {
if (null != eventListener) {
@@ -281,10 +282,10 @@
}
/**
- * Register a callback to be invoked when the caller required to receive
- * error result of asynchronous APIs.
+ * Registers an {@link DrmManagerClient.OnErrorListener} callback, which is invoked when
+ * the DRM framework sends error information.
*
- * @param errorListener
+ * @param errorListener Interface definition for the callback.
*/
public synchronized void setOnErrorListener(OnErrorListener errorListener) {
if (null != errorListener) {
@@ -293,9 +294,10 @@
}
/**
- * Retrieves informations about all the plug-ins registered with DrmFramework.
+ * Retrieves information about all the DRM plug-ins (agents) that are registered with
+ * the DRM framework.
*
- * @return Array of DrmEngine plug-in strings
+ * @return A <code>String</code> array of DRM plug-in descriptions.
*/
public String[] getAvailableDrmEngines() {
DrmSupportInfo[] supportInfos = _getAllSupportInfo(mUniqueId);
@@ -310,12 +312,13 @@
}
/**
- * Get constraints information evaluated from DRM content
+ * Retrieves constraint information for rights-protected content.
*
- * @param path Content path from where DRM constraints would be retrieved.
- * @param action Actions defined in {@link DrmStore.Action}
- * @return ContentValues instance in which constraints key-value pairs are embedded
- * or null in case of failure
+ * @param path Path to the content from which you are retrieving DRM constraints.
+ * @param action Action defined in {@link DrmStore.Action}.
+ *
+ * @return A {@link android.content.ContentValues} instance that contains
+ * key-value pairs representing the constraints. Null in case of failure.
*/
public ContentValues getConstraints(String path, int action) {
if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
@@ -325,11 +328,12 @@
}
/**
- * Get metadata information from DRM content
+ * Retrieves metadata information for rights-protected content.
*
- * @param path Content path from where DRM metadata would be retrieved.
- * @return ContentValues instance in which metadata key-value pairs are embedded
- * or null in case of failure
+ * @param path Path to the content from which you are retrieving metadata information.
+ *
+ * @return A {@link android.content.ContentValues} instance that contains
+ * key-value pairs representing the metadata. Null in case of failure.
*/
public ContentValues getMetadata(String path) {
if (null == path || path.equals("")) {
@@ -339,12 +343,13 @@
}
/**
- * Get constraints information evaluated from DRM content
+ * Retrieves constraint information for rights-protected content.
*
- * @param uri Content URI from where DRM constraints would be retrieved.
- * @param action Actions defined in {@link DrmStore.Action}
- * @return ContentValues instance in which constraints key-value pairs are embedded
- * or null in case of failure
+ * @param uri URI for the content from which you are retrieving DRM constraints.
+ * @param action Action defined in {@link DrmStore.Action}.
+ *
+ * @return A {@link android.content.ContentValues} instance that contains
+ * key-value pairs representing the constraints. Null in case of failure.
*/
public ContentValues getConstraints(Uri uri, int action) {
if (null == uri || Uri.EMPTY == uri) {
@@ -354,11 +359,12 @@
}
/**
- * Get metadata information from DRM content
+ * Retrieves metadata information for rights-protected content.
*
- * @param uri Content URI from where DRM metadata would be retrieved.
- * @return ContentValues instance in which metadata key-value pairs are embedded
- * or null in case of failure
+ * @param uri URI for the content from which you are retrieving metadata information.
+ *
+ * @return A {@link android.content.ContentValues} instance that contains
+ * key-value pairs representing the constraints. Null in case of failure.
*/
public ContentValues getMetadata(Uri uri) {
if (null == uri || Uri.EMPTY == uri) {
@@ -368,18 +374,19 @@
}
/**
- * Save DRM rights to specified rights path
- * and make association with content path.
+ * Saves rights to a specified path and associates that path with the content path.
+ *
+ * <p class="note"><strong>Note:</strong> For OMA or WM-DRM, <code>rightsPath</code> and
+ * <code>contentPath</code> can be null.</p>
*
- * <p class="note">In case of OMA or WM-DRM, rightsPath and contentPath could be null.</p>
+ * @param drmRights The {@link DrmRights} to be saved.
+ * @param rightsPath File path where rights will be saved.
+ * @param contentPath File path where content is saved.
*
- * @param drmRights DrmRights to be saved
- * @param rightsPath File path where rights to be saved
- * @param contentPath File path where content was saved
- * @return
- * ERROR_NONE for success
- * ERROR_UNKNOWN for failure
- * @throws IOException if failed to save rights information in the given path
+ * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
+ *
+ * @throws IOException If the call failed to save rights information at the given
+ * <code>rightsPath</code>.
*/
public int saveRights(
DrmRights drmRights, String rightsPath, String contentPath) throws IOException {
@@ -393,9 +400,10 @@
}
/**
- * Install new DRM Engine Plug-in at the runtime
+ * Installs a new DRM plug-in (agent) at runtime.
*
- * @param engineFilePath Path of the plug-in file to be installed
+ * @param engineFilePath File path to the plug-in file to be installed.
+ *
* {@hide}
*/
public void installDrmEngine(String engineFilePath) {
@@ -407,13 +415,12 @@
}
/**
- * Check whether the given mimetype or path can be handled.
+ * Checks whether the given MIME type or path can be handled.
*
- * @param path Path of the content to be handled
- * @param mimeType Mimetype of the object to be handled
- * @return
- * true - if the given mimeType or path can be handled
- * false - cannot be handled.
+ * @param path Path of the content to be handled.
+ * @param mimeType MIME type of the object to be handled.
+ *
+ * @return True if the given MIME type or path can be handled; false if they cannot be handled.
*/
public boolean canHandle(String path, String mimeType) {
if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
@@ -423,13 +430,12 @@
}
/**
- * Check whether the given mimetype or uri can be handled.
+ * Checks whether the given MIME type or URI can be handled.
*
- * @param uri Content URI of the data to be handled.
- * @param mimeType Mimetype of the object to be handled
- * @return
- * true - if the given mimeType or path can be handled
- * false - cannot be handled.
+ * @param uri URI for the content to be handled.
+ * @param mimeType MIME type of the object to be handled
+ *
+ * @return True if the given MIME type or URI can be handled; false if they cannot be handled.
*/
public boolean canHandle(Uri uri, String mimeType) {
if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
@@ -439,12 +445,10 @@
}
/**
- * Executes given drm information based on its type
+ * Processes the given DRM information based on the information type.
*
- * @param drmInfo Information needs to be processed
- * @return
- * ERROR_NONE for success
- * ERROR_UNKNOWN for failure
+ * @param drmInfo The {@link DrmInfo} to be processed.
+ * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
*/
public int processDrmInfo(DrmInfo drmInfo) {
if (null == drmInfo || !drmInfo.isValid()) {
@@ -459,10 +463,12 @@
}
/**
- * Retrieves necessary information for register, unregister or rights acquisition.
+ * Retrieves information for registering, unregistering, or acquiring rights.
*
- * @param drmInfoRequest Request information to retrieve drmInfo
- * @return DrmInfo Instance as a result of processing given input
+ * @param drmInfoRequest The {@link DrmInfoRequest} that specifies the type of DRM
+ * information being retrieved.
+ *
+ * @return A {@link DrmInfo} instance.
*/
public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
@@ -472,17 +478,18 @@
}
/**
- * Executes given DrmInfoRequest and returns the rights information asynchronously.
- * This is a utility API which consists of {@link #acquireDrmInfo(DrmInfoRequest)}
- * and {@link #processDrmInfo(DrmInfo)}.
- * It can be used if selected DRM agent can work with this combined sequences.
- * In case of some DRM schemes, such as OMA DRM, application needs to invoke
- * {@link #acquireDrmInfo(DrmInfoRequest)} and {@link #processDrmInfo(DrmInfo)}, separately.
+ * Processes a given {@link DrmInfoRequest} and returns the rights information asynchronously.
+ *<p>
+ * This is a utility method that consists of an
+ * {@link #acquireDrmInfo(DrmInfoRequest) acquireDrmInfo()} and a
+ * {@link #processDrmInfo(DrmInfo) processDrmInfo()} method call. This utility method can be
+ * used only if the selected DRM plug-in (agent) supports this sequence of calls. Some DRM
+ * agents, such as OMA, do not support this utility method, in which case an application must
+ * invoke {@link #acquireDrmInfo(DrmInfoRequest) acquireDrmInfo()} and
+ * {@link #processDrmInfo(DrmInfo) processDrmInfo()} separately.
*
- * @param drmInfoRequest Request information to retrieve drmInfo
- * @return
- * ERROR_NONE for success
- * ERROR_UNKNOWN for failure
+ * @param drmInfoRequest The {@link DrmInfoRequest} used to acquire the rights.
+ * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
*/
public int acquireRights(DrmInfoRequest drmInfoRequest) {
DrmInfo drmInfo = acquireDrmInfo(drmInfoRequest);
@@ -493,14 +500,14 @@
}
/**
- * Retrieves the type of the protected object (content, rights, etc..)
- * using specified path or mimetype. At least one parameter should be non null
- * to retrieve DRM object type
+ * Retrieves the type of rights-protected object (for example, content object, rights
+ * object, and so on) using the specified path or MIME type. At least one parameter must
+ * be specified to retrieve the DRM object type.
*
- * @param path Path of the content or null.
- * @param mimeType Mimetype of the content or null.
- * @return Type of the DRM content.
- * @see DrmStore.DrmObjectType
+ * @param path Path to the content or null.
+ * @param mimeType MIME type of the content or null.
+ *
+ * @return An <code>int</code> that corresponds to a {@link DrmStore.DrmObjectType}.
*/
public int getDrmObjectType(String path, String mimeType) {
if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
@@ -510,14 +517,14 @@
}
/**
- * Retrieves the type of the protected object (content, rights, etc..)
- * using specified uri or mimetype. At least one parameter should be non null
- * to retrieve DRM object type
+ * Retrieves the type of rights-protected object (for example, content object, rights
+ * object, and so on) using the specified URI or MIME type. At least one parameter must
+ * be specified to retrieve the DRM object type.
*
- * @param uri The content URI of the data
- * @param mimeType Mimetype of the content or null.
- * @return Type of the DRM content.
- * @see DrmStore.DrmObjectType
+ * @param uri URI for the content or null.
+ * @param mimeType MIME type of the content or null.
+ *
+ * @return An <code>int</code> that corresponds to a {@link DrmStore.DrmObjectType}.
*/
public int getDrmObjectType(Uri uri, String mimeType) {
if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
@@ -534,10 +541,11 @@
}
/**
- * Retrieves the mime type embedded inside the original content
+ * Retrieves the MIME type embedded in the original content.
*
- * @param path Path of the protected content
- * @return Mimetype of the original content, such as "video/mpeg"
+ * @param path Path to the rights-protected content.
+ *
+ * @return The MIME type of the original content, such as <code>video/mpeg</code>.
*/
public String getOriginalMimeType(String path) {
if (null == path || path.equals("")) {
@@ -547,10 +555,11 @@
}
/**
- * Retrieves the mime type embedded inside the original content
+ * Retrieves the MIME type embedded in the original content.
*
- * @param uri The content URI of the data
- * @return Mimetype of the original content, such as "video/mpeg"
+ * @param uri URI of the rights-protected content.
+ *
+ * @return MIME type of the original content, such as <code>video/mpeg</code>.
*/
public String getOriginalMimeType(Uri uri) {
if (null == uri || Uri.EMPTY == uri) {
@@ -560,22 +569,22 @@
}
/**
- * Check whether the given content has valid rights or not
+ * Checks whether the given content has valid rights.
*
- * @param path Path of the protected content
- * @return Status of the rights for the protected content
- * @see DrmStore.RightsStatus
+ * @param path Path to the rights-protected content.
+ *
+ * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
*/
public int checkRightsStatus(String path) {
return checkRightsStatus(path, DrmStore.Action.DEFAULT);
}
/**
- * Check whether the given content has valid rights or not
+ * Check whether the given content has valid rights.
*
- * @param uri The content URI of the data
- * @return Status of the rights for the protected content
- * @see DrmStore.RightsStatus
+ * @param uri URI of the rights-protected content.
+ *
+ * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
*/
public int checkRightsStatus(Uri uri) {
if (null == uri || Uri.EMPTY == uri) {
@@ -585,12 +594,13 @@
}
/**
- * Check whether the given content has valid rights or not for specified action.
+ * Checks whether the given rights-protected content has valid rights for the specified
+ * {@link DrmStore.Action}.
*
- * @param path Path of the protected content
- * @param action Action to perform
- * @return Status of the rights for the protected content
- * @see DrmStore.RightsStatus
+ * @param path Path to the rights-protected content.
+ * @param action The {@link DrmStore.Action} to perform.
+ *
+ * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
*/
public int checkRightsStatus(String path, int action) {
if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
@@ -600,12 +610,13 @@
}
/**
- * Check whether the given content has valid rights or not for specified action.
+ * Checks whether the given rights-protected content has valid rights for the specified
+ * {@link DrmStore.Action}.
*
- * @param uri The content URI of the data
- * @param action Action to perform
- * @return Status of the rights for the protected content
- * @see DrmStore.RightsStatus
+ * @param uri URI for the rights-protected content.
+ * @param action The {@link DrmStore.Action} to perform.
+ *
+ * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
*/
public int checkRightsStatus(Uri uri, int action) {
if (null == uri || Uri.EMPTY == uri) {
@@ -615,12 +626,11 @@
}
/**
- * Removes the rights associated with the given protected content
+ * Removes the rights associated with the given rights-protected content.
*
- * @param path Path of the protected content
- * @return
- * ERROR_NONE for success
- * ERROR_UNKNOWN for failure
+ * @param path Path to the rights-protected content.
+ *
+ * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
*/
public int removeRights(String path) {
if (null == path || path.equals("")) {
@@ -630,12 +640,11 @@
}
/**
- * Removes the rights associated with the given protected content
+ * Removes the rights associated with the given rights-protected content.
*
- * @param uri The content URI of the data
- * @return
- * ERROR_NONE for success
- * ERROR_UNKNOWN for failure
+ * @param uri URI for the rights-protected content.
+ *
+ * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
*/
public int removeRights(Uri uri) {
if (null == uri || Uri.EMPTY == uri) {
@@ -645,12 +654,10 @@
}
/**
- * Removes all the rights information of every plug-in associated with
- * DRM framework. Will be used in master reset
+ * Removes all the rights information of every DRM plug-in (agent) associated with
+ * the DRM framework. Will be used during a master reset.
*
- * @return
- * ERROR_NONE for success
- * ERROR_UNKNOWN for failure
+ * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
*/
public int removeAllRights() {
int result = ERROR_UNKNOWN;
@@ -662,13 +669,14 @@
}
/**
- * This API is for Forward Lock based DRM scheme.
- * Each time the application tries to download a new DRM file
- * which needs to be converted, then the application has to
- * begin with calling this API.
+ * Initiates a new conversion session. An application must initiate a conversion session
+ * with this method each time it downloads a rights-protected file that needs to be converted.
+ *<p>
+ * This method applies only to forward-locking (copy protection) DRM schemes.
*
- * @param mimeType Description/MIME type of the input data packet
- * @return convert ID which will be used for maintaining convert session.
+ * @param mimeType MIME type of the input data packet.
+ *
+ * @return A convert ID that is used used to maintain the conversion session.
*/
public int openConvertSession(String mimeType) {
if (null == mimeType || mimeType.equals("")) {
@@ -678,16 +686,17 @@
}
/**
- * Accepts and converts the input data which is part of DRM file.
- * The resultant converted data and the status is returned in the DrmConvertedInfo
- * object. This method will be called each time there are new block
- * of data received by the application.
+ * Converts the input data (content) that is part of a rights-protected file. The converted
+ * data and status is returned in a {@link DrmConvertedStatus} object. This method should be
+ * called each time there is a new block of data received by the application.
*
- * @param convertId Handle for the convert session
- * @param inputData Input Data which need to be converted
- * @return Return object contains the status of the data conversion,
- * the output converted data and offset. In this case the
- * application will ignore the offset information.
+ * @param convertId Handle for the conversion session.
+ * @param inputData Input data that needs to be converted.
+ *
+ * @return A {@link DrmConvertedStatus} object that contains the status of the data conversion,
+ * the converted data, and offset for the header and body signature. An application can
+ * ignore the offset because it is only relevant to the
+ * {@link #closeConvertSession closeConvertSession()} method.
*/
public DrmConvertedStatus convertData(int convertId, byte[] inputData) {
if (null == inputData || 0 >= inputData.length) {
@@ -697,16 +706,15 @@
}
/**
- * Informs the Drm Agent when there is no more data which need to be converted
- * or when an error occurs. Upon successful conversion of the complete data,
- * the agent will inform that where the header and body signature
- * should be added. This signature appending is needed to integrity
- * protect the converted file.
+ * Informs the DRM plug-in (agent) that there is no more data to convert or that an error
+ * has occurred. Upon successful conversion of the data, the DRM agent will provide an offset
+ * value indicating where the header and body signature should be added. Appending the
+ * signature is necessary to protect the integrity of the converted file.
*
- * @param convertId Handle for the convert session
- * @return Return object contains the status of the data conversion,
- * the header and body signature data. It also informs
- * the application on which offset these signature data should be appended.
+ * @param convertId Handle for the conversion session.
+ *
+ * @return A {@link DrmConvertedStatus} object that contains the status of the data conversion,
+ * the converted data, and the offset for the header and body signature.
*/
public DrmConvertedStatus closeConvertSession(int convertId) {
return _closeConvertSession(mUniqueId, convertId);
diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java
old mode 100644
new mode 100755
index 103af07..5907956
--- a/drm/java/android/drm/DrmRights.java
+++ b/drm/java/android/drm/DrmRights.java
@@ -20,14 +20,16 @@
import java.io.IOException;
/**
- * This is an entity class which wraps the license information which was
- * retrieved from the online DRM server.
- *
- * Caller can instantiate {@link DrmRights} by
- * invoking {@link DrmRights#DrmRights(ProcessedData, String)}
- * constructor by using the result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} interface.
- * Caller can also instantiate {@link DrmRights} using the file path
- * which contains rights information.
+ * An entity class that wraps the license information retrieved from the online DRM server.
+ *<p>
+ * A caller can instantiate a {@link DrmRights} object by first invoking the
+ * {@link DrmManagerClient#processDrmInfo(DrmInfo)} method and then using the resulting
+ * {@link ProcessedData} object to invoke the {@link DrmRights#DrmRights(ProcessedData, String)}
+ * constructor.
+ *<p>
+ * A caller can also instantiate a {@link DrmRights} object by using the
+ * {@link DrmRights#DrmRights(String, String)} constructor, which takes a path to a file
+ * containing rights information instead of a <code>ProcessedData</code>.
*
*/
public class DrmRights {
@@ -37,10 +39,10 @@
private String mSubscriptionId = "";
/**
- * constructor to create DrmRights object with given parameters
+ * Creates a <code>DrmRights</code> object with the given parameters.
*
- * @param rightsFilePath Path of the file containing rights data
- * @param mimeType MIME type
+ * @param rightsFilePath Path to the file containing rights information.
+ * @param mimeType MIME type.
*/
public DrmRights(String rightsFilePath, String mimeType) {
File file = new File(rightsFilePath);
@@ -48,11 +50,11 @@
}
/**
- * constructor to create DrmRights object with given parameters
+ * Creates a <code>DrmRights</code> object with the given parameters.
*
- * @param rightsFilePath Path of the file containing rights data
- * @param mimeType MIME type
- * @param accountId Account Id of the user
+ * @param rightsFilePath Path to the file containing rights information.
+ * @param mimeType MIME type.
+ * @param accountId Account ID of the user.
*/
public DrmRights(String rightsFilePath, String mimeType, String accountId) {
this(rightsFilePath, mimeType);
@@ -63,12 +65,12 @@
}
/**
- * constructor to create DrmRights object with given parameters
+ * Creates a <code>DrmRights</code> object with the given parameters.
*
- * @param rightsFilePath Path of the file containing rights data
- * @param mimeType MIME type
- * @param accountId Account Id of the user
- * @param subscriptionId Subscription Id of the user
+ * @param rightsFilePath Path to the file containing rights information.
+ * @param mimeType MIME type.
+ * @param accountId Account ID of the user.
+ * @param subscriptionId Subscription ID of the user.
*/
public DrmRights(
String rightsFilePath, String mimeType, String accountId, String subscriptionId) {
@@ -84,10 +86,10 @@
}
/**
- * constructor to create DrmRights object with given parameters
+ * Creates a <code>DrmRights</code> object with the given parameters.
*
- * @param rightsFile File containing rights data
- * @param mimeType MIME type
+ * @param rightsFile File containing rights information.
+ * @param mimeType MIME type.
*/
public DrmRights(File rightsFile, String mimeType) {
instantiate(rightsFile, mimeType);
@@ -104,16 +106,20 @@
}
/**
- * constructor to create DrmRights object with given parameters
- * The user can pass String or binary data<p>
- * Usage:<p>
- * i) String(e.g. data is instance of String):<br>
- * - new DrmRights(data.getBytes(), mimeType)<p>
- * ii) Binary data<br>
- * - new DrmRights(binaryData[], mimeType)<br>
+ * Creates a <code>DrmRights</code> object with the given parameters.
+ *<p>
+ * The application can pass the processed data as a <code>String</code> or as binary data.
+ *<p>
+ * The following code snippet shows how to pass the processed data as a <code>String</code>:
+ *<p>
+ * new DrmRights(data.getBytes(), mimeType)
+ *<p>
+ * The following code snippet shows how to pass the processed data as binary data:
+ *<p>
+ * new DrmRights(binaryData[], mimeType)
*
- * @param data Processed data
- * @param mimeType MIME type
+ * @param data A {@link ProcessedData} object.
+ * @param mimeType The MIME type.
*/
public DrmRights(ProcessedData data, String mimeType) {
mData = data.getData();
@@ -132,47 +138,45 @@
}
/**
- * Returns the rights data associated with this object
+ * Retrieves the rights data associated with this <code>DrmRights</code> object.
*
- * @return Rights data
+ * @return A <code>byte</code> array representing the rights data.
*/
public byte[] getData() {
return mData;
}
/**
- * Returns the mimetype associated with this object
+ * Retrieves the MIME type associated with this <code>DrmRights</code> object.
*
- * @return MIME type
+ * @return The MIME type.
*/
public String getMimeType() {
return mMimeType;
}
/**
- * Returns the account-id associated with this object
+ * Retrieves the account ID associated with this <code>DrmRights</code> object.
*
- * @return Account Id
+ * @return The account ID.
*/
public String getAccountId() {
return mAccountId;
}
/**
- * Returns the subscription-id associated with this object
+ * Retrieves the subscription ID associated with this <code>DrmRights</code> object.
*
- * @return Subscription Id
+ * @return The subscription ID.
*/
public String getSubscriptionId() {
return mSubscriptionId;
}
/**
- * Returns whether this instance is valid or not
+ * Determines whether this instance is valid or not.
*
- * @return
- * true if valid
- * false if invalid
+ * @return True if valid; false if invalid.
*/
/*package*/ boolean isValid() {
return (null != mMimeType && !mMimeType.equals("")
diff --git a/drm/java/android/drm/DrmStore.java b/drm/java/android/drm/DrmStore.java
old mode 100644
new mode 100755
index 44df90c..ae311de
--- a/drm/java/android/drm/DrmStore.java
+++ b/drm/java/android/drm/DrmStore.java
@@ -17,91 +17,97 @@
package android.drm;
/**
- * This class defines all the constants used by DRM framework
+ * Defines constants that are used by the DRM framework.
*
*/
public class DrmStore {
/**
- * Columns representing drm constraints
+ * Interface definition for the columns that represent DRM constraints.
*/
public interface ConstraintsColumns {
/**
- * The max repeat count
- * <P>Type: INTEGER</P>
+ * The maximum repeat count.
+ * <p>
+ * Type: INTEGER
*/
public static final String MAX_REPEAT_COUNT = "max_repeat_count";
/**
- * The remaining repeat count
- * <P>Type: INTEGER</P>
+ * The remaining repeat count.
+ * <p>
+ * Type: INTEGER
*/
public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
/**
- * The time before which the protected file can not be played/viewed
- * <P>Type: TEXT</P>
+ * The time before which the rights-protected file cannot be played/viewed.
+ * <p>
+ * Type: TEXT
*/
public static final String LICENSE_START_TIME = "license_start_time";
/**
- * The time after which the protected file can not be played/viewed
- * <P>Type: TEXT</P>
+ * The time after which the rights-protected file cannot be played/viewed.
+ * <p>
+ * Type: TEXT
*/
public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
/**
- * The available time for license
- * <P>Type: TEXT</P>
+ * The available time left before the license expires.
+ * <p>
+ * Type: TEXT
*/
public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
/**
- * The data stream for extended metadata
- * <P>Type: TEXT</P>
+ * The data stream for extended metadata.
+ * <p>
+ * Type: TEXT
*/
public static final String EXTENDED_METADATA = "extended_metadata";
}
/**
- * Defines constants related to DRM types
+ * Defines DRM object types.
*/
public static class DrmObjectType {
/**
- * Field specifies the unknown type
+ * An unknown object type.
*/
public static final int UNKNOWN = 0x00;
/**
- * Field specifies the protected content type
+ * A rights-protected file object type.
*/
public static final int CONTENT = 0x01;
/**
- * Field specifies the rights information
+ * A rights information object type.
*/
public static final int RIGHTS_OBJECT = 0x02;
/**
- * Field specifies the trigger information
+ * A trigger information object type.
*/
public static final int TRIGGER_OBJECT = 0x03;
}
/**
- * Defines constants related to playback
+ * Defines playback states for content.
*/
public static class Playback {
/**
- * Constant field signifies playback start
+ * Playback started.
*/
public static final int START = 0x00;
/**
- * Constant field signifies playback stop
+ * Playback stopped.
*/
public static final int STOP = 0x01;
/**
- * Constant field signifies playback paused
+ * Playback paused.
*/
public static final int PAUSE = 0x02;
/**
- * Constant field signifies playback resumed
+ * Playback resumed.
*/
public static final int RESUME = 0x03;
@@ -120,39 +126,39 @@
}
/**
- * Defines actions that can be performed on protected content
+ * Defines actions that can be performed on rights-protected content.
*/
public static class Action {
/**
- * Constant field signifies that the default action
+ * The default action.
*/
public static final int DEFAULT = 0x00;
/**
- * Constant field signifies that the content can be played
+ * The rights-protected content can be played.
*/
public static final int PLAY = 0x01;
/**
- * Constant field signifies that the content can be set as ring tone
+ * The rights-protected content can be set as a ringtone.
*/
public static final int RINGTONE = 0x02;
/**
- * Constant field signifies that the content can be transfered
+ * The rights-protected content can be transferred.
*/
public static final int TRANSFER = 0x03;
/**
- * Constant field signifies that the content can be set as output
+ * The rights-protected content can be set as output.
*/
public static final int OUTPUT = 0x04;
/**
- * Constant field signifies that preview is allowed
+ * The rights-protected content can be previewed.
*/
public static final int PREVIEW = 0x05;
/**
- * Constant field signifies that the content can be executed
+ * The rights-protected content can be executed.
*/
public static final int EXECUTE = 0x06;
/**
- * Constant field signifies that the content can displayed
+ * The rights-protected content can be displayed.
*/
public static final int DISPLAY = 0x07;
@@ -175,23 +181,23 @@
}
/**
- * Defines constants related to status of the rights
+ * Defines status notifications for digital rights.
*/
public static class RightsStatus {
/**
- * Constant field signifies that the rights are valid
+ * The digital rights are valid.
*/
public static final int RIGHTS_VALID = 0x00;
/**
- * Constant field signifies that the rights are invalid
+ * The digital rights are invalid.
*/
public static final int RIGHTS_INVALID = 0x01;
/**
- * Constant field signifies that the rights are expired for the content
+ * The digital rights have expired.
*/
public static final int RIGHTS_EXPIRED = 0x02;
/**
- * Constant field signifies that the rights are not acquired for the content
+ * The digital rights have not been acquired for the rights-protected content.
*/
public static final int RIGHTS_NOT_ACQUIRED = 0x03;
}
diff --git a/drm/java/android/drm/DrmSupportInfo.java b/drm/java/android/drm/DrmSupportInfo.java
old mode 100644
new mode 100755
index 0886af8..720c545
--- a/drm/java/android/drm/DrmSupportInfo.java
+++ b/drm/java/android/drm/DrmSupportInfo.java
@@ -20,11 +20,11 @@
import java.util.Iterator;
/**
- * This is an entity class which wraps the capability of each plug-in,
- * such as mimetype's and file suffixes it could handle.
- *
- * Plug-in developer could return the capability of the plugin by passing
- * {@link DrmSupportInfo} instance.
+ * An entity class that wraps the capability of each DRM plug-in (agent),
+ * such as the MIME type and file suffix the DRM plug-in can handle.
+ *<p>
+ * Plug-in developers can expose the capability of their plug-in by passing an instance of this
+ * class to an application.
*
*/
public class DrmSupportInfo {
@@ -33,47 +33,47 @@
private String mDescription = "";
/**
- * Add the mime-type to the support info such that respective plug-in is
- * capable of handling the given mime-type.
+ * Adds the specified MIME type to the list of MIME types this DRM plug-in supports.
*
- * @param mimeType MIME type
+ * @param mimeType MIME type that can be handles by this DRM plug-in.
*/
public void addMimeType(String mimeType) {
mMimeTypeList.add(mimeType);
}
/**
- * Add the file suffix to the support info such that respective plug-in is
- * capable of handling the given file suffix.
+ * Adds the specified file suffix to the list of file suffixes this DRM plug-in supports.
*
- * @param fileSuffix File suffix which can be handled
+ * @param fileSuffix File suffix that can be handled by this DRM plug-in.
*/
public void addFileSuffix(String fileSuffix) {
mFileSuffixList.add(fileSuffix);
}
/**
- * Returns the iterator to walk to through mime types of this object
+ * Retrieves an iterator object that you can use to iterate over the MIME types that
+ * this DRM plug-in supports.
*
- * @return Iterator object
+ * @return The iterator object
*/
public Iterator<String> getMimeTypeIterator() {
return mMimeTypeList.iterator();
}
/**
- * Returns the iterator to walk to through file suffixes of this object
+ * Retrieves an iterator object that you can use to iterate over the file suffixes that
+ * this DRM plug-in supports.
*
- * @return Iterator object
+ * @return The iterator object.
*/
public Iterator<String> getFileSuffixIterator() {
return mFileSuffixList.iterator();
}
/**
- * Set the unique description about the plugin
+ * Sets a description for the DRM plug-in (agent).
*
- * @param description Unique description
+ * @param description Unique description of plug-in.
*/
public void setDescription(String description) {
if (null != description) {
@@ -82,30 +82,28 @@
}
/**
- * Returns the unique description associated with the plugin
+ * Retrieves the DRM plug-in (agent) description.
*
- * @return Unique description
+ * @return The plug-in description.
*/
public String getDescriprition() {
return mDescription;
}
/**
- * Overridden hash code implementation
+ * Overridden hash code implementation.
*
- * @return Hash code value
+ * @return The hash code value.
*/
public int hashCode() {
return mFileSuffixList.hashCode() + mMimeTypeList.hashCode() + mDescription.hashCode();
}
/**
- * Overridden equals implementation
+ * Overridden <code>equals</code> implementation.
*
- * @param object The object to be compared
- * @return
- * true if equal
- * false if not equal
+ * @param object The object to be compared.
+ * @return True if equal; false if not equal.
*/
public boolean equals(Object object) {
boolean result = false;
@@ -119,12 +117,10 @@
}
/**
- * Returns whether given mime-type is supported or not
+ * Determines whether a given MIME type is supported.
*
- * @param mimeType MIME type
- * @return
- * true if mime type is supported
- * false if mime type is not supported
+ * @param mimeType MIME type.
+ * @return True if Mime type is supported; false if MIME type is not supported.
*/
/* package */ boolean isSupportedMimeType(String mimeType) {
if (null != mimeType && !mimeType.equals("")) {
@@ -139,12 +135,10 @@
}
/**
- * Returns whether given file suffix is supported or not
+ * Determines whether a given file suffix is supported.
*
- * @param fileSuffix File suffix
- * @return
- * true - if file suffix is supported
- * false - if file suffix is not supported
+ * @param fileSuffix File suffix.
+ * @return True if file suffix is supported; false if file suffix is not supported.
*/
/* package */ boolean isSupportedFileSuffix(String fileSuffix) {
return mFileSuffixList.contains(fileSuffix);
diff --git a/drm/java/android/drm/DrmUtils.java b/drm/java/android/drm/DrmUtils.java
old mode 100644
new mode 100755
index 8903485..dc5f1fa
--- a/drm/java/android/drm/DrmUtils.java
+++ b/drm/java/android/drm/DrmUtils.java
@@ -28,9 +28,11 @@
import java.util.Iterator;
/**
- * The utility class used in the DRM Framework. This inclueds APIs for file operations
- * and ExtendedMetadataParser for parsing extended metadata BLOB in DRM constraints.
- *
+ * A utility class that provides operations for parsing extended metadata embedded in
+ * DRM constraint information. If a DRM scheme has specific constraints beyond the standard
+ * constraints, the constraints will show up in the
+ * {@link DrmStore.ConstraintsColumns#EXTENDED_METADATA} key. You can use
+ * {@link DrmUtils.ExtendedMetadataParser} to iterate over those values.
*/
public class DrmUtils {
/* Should be used when we need to read from local file */
@@ -99,13 +101,10 @@
}
/**
- * Get an instance of ExtendedMetadataParser to be used for parsing
- * extended metadata BLOB in DRM constraints. <br>
+ * Gets an instance of {@link DrmUtils.ExtendedMetadataParser}, which can be used to parse
+ * extended metadata embedded in DRM constraint information.
*
- * extendedMetadata BLOB is retrieved by specifing
- * key DrmStore.ConstraintsColumns.EXTENDED_METADATA.
- *
- * @param extendedMetadata BLOB in which key-value pairs of extended metadata are embedded.
+ * @param extendedMetadata Object in which key-value pairs of extended metadata are embedded.
*
*/
public static ExtendedMetadataParser getExtendedMetadataParser(byte[] extendedMetadata) {
@@ -113,9 +112,10 @@
}
/**
- * Utility parser to parse the extended meta-data embedded inside DRM constraints<br><br>
- *
- * Usage example<br>
+ * Utility that parses extended metadata embedded in DRM constraint information.
+ *<p>
+ * Usage example:
+ *<p>
* byte[] extendedMetadata<br>
* =
* constraints.getAsByteArray(DrmStore.ConstraintsColumns.EXTENDED_METADATA);<br>
diff --git a/drm/java/android/drm/ProcessedData.java b/drm/java/android/drm/ProcessedData.java
old mode 100644
new mode 100755
index 579264f..06e03e7
--- a/drm/java/android/drm/ProcessedData.java
+++ b/drm/java/android/drm/ProcessedData.java
@@ -17,11 +17,11 @@
package android.drm;
/**
- * This is an entity class which wraps the result of transaction between
- * device and online DRM server by using {@link DrmManagerClient#processDrmInfo(DrmInfo)}
+ * An entity class that wraps the result of a
+ * {@link DrmManagerClient#processDrmInfo(DrmInfo) processDrmInfo()}
+ * transaction between a device and a DRM server.
*
- * In license acquisition scenario this class would hold the binary data
- * of rights information.
+ * In a license acquisition scenario this class holds the rights information in binary form.
*
*/
public class ProcessedData {
@@ -30,10 +30,10 @@
private String mSubscriptionId = "";
/**
- * constructor to create ProcessedData object with given parameters
+ * Creates a <code>ProcessedData</code> object with the given parameters.
*
- * @param data Rights data
- * @param accountId Account Id of the user
+ * @param data Rights data.
+ * @param accountId Account ID of the user.
*/
/* package */ ProcessedData(byte[] data, String accountId) {
mData = data;
@@ -41,11 +41,11 @@
}
/**
- * constructor to create ProcessedData object with given parameters
+ * Creates a <code>ProcessedData</code> object with the given parameters.
*
- * @param data Rights data
- * @param accountId Account Id of the user
- * @param subscriptionId Subscription Id of the user
+ * @param data Rights data.
+ * @param accountId Account ID of the user.
+ * @param subscriptionId Subscription ID of the user.
*/
/* package */ ProcessedData(byte[] data, String accountId, String subscriptionId) {
mData = data;
@@ -54,27 +54,27 @@
}
/**
- * Returns the processed data as a result.
+ * Retrieves the processed data.
*
- * @return Rights data associated
+ * @return The rights data.
*/
public byte[] getData() {
return mData;
}
/**
- * Returns the account-id associated with this object
+ * Retrieves the account ID associated with this object.
*
- * @return Account Id associated
+ * @return The account ID of the user.
*/
public String getAccountId() {
return mAccountId;
}
/**
- * Returns the subscription-id associated with this object
+ * Returns the subscription ID associated with this object.
*
- * @return Subscription Id associated
+ * @return The subscription ID of the user.
*/
public String getSubscriptionId() {
return mSubscriptionId;
diff --git a/drm/java/android/drm/package.html b/drm/java/android/drm/package.html
new file mode 100755
index 0000000..161d6e0
--- /dev/null
+++ b/drm/java/android/drm/package.html
@@ -0,0 +1,85 @@
+<HTML>
+<BODY>
+<p>Provides classes for managing DRM content and determining the capabilities of DRM plugins
+(agents). Common uses of the DRM API include:</p>
+<ul>
+ <li>Determining which DRM plug-ins (agents) are installed on a device.</li>
+ <li>Retrieving information about specific plug-ins, such as the MIME types and file suffixes
+ they support.</li>
+ <li>Registering a user or a device with an online DRM service.</li>
+ <li>Retrieving license constraints for rights-protected content.</li>
+ <li>Checking whether a user has the proper rights to play or use rights-protected
+ content.</li>
+ <li>Associating rights-protected content with its license so you can use the
+ {@link android.media.MediaPlayer} API to play the content.</li>
+</ul>
+
+<h2>DRM Overview</h2>
+
+<p>The Android platform provides an extensible DRM framework that lets applications manage
+rights-protected content according to the license constraints that are associated with the
+content. The DRM framework supports many DRM schemes; which DRM schemes a device supports
+is up to the device manufacturer.</p>
+
+<p>The Android DRM framework is implemented in two architectural layers (see figure below):</p>
+<ul>
+ <li>A DRM framework API, which is exposed to applications through the Android
+application framework and runs through the Dalvik VM for standard applications.</li>
+ <li>A native code DRM manager, which implements the DRM framework and exposes an
+interface for DRM plug-ins (agents) to handle rights management and decryption for various
+DRM schemes.</li>
+</ul>
+
+<img src="../../../images/drm_arch.png" alt="DRM architecture diagram" border="0"/>
+
+<p>For application developers, the DRM framework offers an abstract, unified API that
+simplifies the management of rights-protected content. The API hides the complexity of DRM
+operations and allows a consistent operation mode for both rights-protected and unprotected content
+across a variety of DRM schemes. For device manufacturers, content owners, and Internet digital
+media providers the DRM framework’s plugin architecture provides a means of adding support for a
+specific DRM scheme to the Android system.</p>
+
+<h2>Using the DRM API</h2>
+
+<p>In a typical DRM session, an Android application uses the DRM framework API to
+instantiate a {@link android.drm.DrmManagerClient}. The application calls various methods
+on the DRM client to query rights and perform other DRM-related tasks. Each
+{@link android.drm.DrmManagerClient} instance has its own unique ID, so the DRM manager is able to
+differentiate callers.</p>
+
+<p>Although each DRM plug-in may require a different sequence
+of API calls, the general call sequence for an application is as follows:</p>
+
+<ul>
+ <li>Register the device with an online DRM service.
+ <p>You can do this by first using the {@link android.drm.DrmManagerClient#acquireDrmInfo
+acquireDrmInfo()} method to acquire the registration information, and then using the {@link
+android.drm.DrmManagerClient#processDrmInfo processDrmInfo()} method to process the
+registration information.</p>
+ </li>
+ <li>Acquire the license that's associated with the rights-protected content.
+ <p>You can do this by first using the {@link android.drm.DrmManagerClient#acquireDrmInfo
+acquireDrmInfo()} method to acquire the license information, and then using the {@link
+android.drm.DrmManagerClient#processDrmInfo processDrmInfo()} method to process the
+license information. You can also use the {@link
+android.drm.DrmManagerClient#acquireRights acquireRights()} method.</p>
+ </li>
+ <li>Extract constraint information from the license.
+ <p>You can use the {@link android.drm.DrmManagerClient#getConstraints getConstraints()}
+ method to do this.</p>
+ </li>
+ <li>Associate the rights-protected content with its license.
+ <p>You can use the {@link android.drm.DrmManagerClient#saveRights saveRights()} method
+ to do this.</p>
+ </li>
+</ul>
+
+<p>After you make an association between the rights-protected content and its license,
+the DRM manager automatically handles rights management for that content. Specifically, the
+DRM manager will handle all further licensing checks when you attempt to play the content using
+the {@link android.media.MediaPlayer} API.</p>
+
+<p>To learn how to use the DRM API with a specific DRM plug-in, see the documentation provided
+by the plug-in developer.</p>
+</BODY>
+</HTML>
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
index 8b781326..b50199f 100644
--- a/drm/libdrmframework/DrmManagerClient.cpp
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -32,7 +32,6 @@
DrmManagerClientImpl::remove(mUniqueId);
mDrmManagerClientImpl->removeClient(mUniqueId);
mDrmManagerClientImpl->setOnInfoListener(mUniqueId, NULL);
- delete mDrmManagerClientImpl; mDrmManagerClientImpl = NULL;
}
status_t DrmManagerClient::setOnInfoListener(
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 965abe9..e493b18 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1330,6 +1330,29 @@
}
/**
+ * Draw the glyphs, with origin at (x,y), using the specified paint. The
+ * origin is interpreted based on the Align setting in the paint.
+ *
+ * @param glyphs The glyphs to be drawn
+ * @param x The x-coordinate of the origin of the text being drawn
+ * @param y The y-coordinate of the origin of the text being drawn
+ * @param paint The paint used for the text (e.g. color, size, style)
+ *
+ * @hide
+ *
+ * Used only for BiDi / RTL Tests
+ */
+ public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
+ Paint paint) {
+ if ((index | count | (index + count) |
+ (glyphs.length - index - count)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
+ paint.mNativePaint);
+ }
+
+ /**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
@@ -1722,7 +1745,9 @@
private static native void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int flags, int paint);
-
+ private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs,
+ int index, int count, float x,
+ float y, int flags, int paint);
private static native void native_drawTextRun(int nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, int flags, int paint);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 0a23bae..96eb936 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1455,6 +1455,43 @@
}
/**
+ * Return the glypth Ids for the characters in the string.
+ *
+ * @param text The text to measure
+ * @param start The index of the first char to to measure
+ * @param end The end of the text slice to measure
+ * @param contextStart the index of the first character to use for shaping context,
+ * must be <= start
+ * @param contextEnd the index past the last character to use for shaping context,
+ * must be >= end
+ * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+ * or {@link #DIRECTION_RTL}
+ * @param glyphs array to receive the glyph Ids of the characters.
+ * Must be at least a large as the text.
+ * @return the number of glyphs in the returned array
+ *
+ * @hide
+ *
+ * Used only for BiDi / RTL Tests
+ */
+ public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd,
+ int flags, char[] glyphs) {
+ if ((start | end | contextStart | contextEnd | (end - start)
+ | (start - contextStart) | (contextEnd - end) | (text.length() - end)
+ | (text.length() - contextEnd)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (end - start > glyphs.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+ throw new IllegalArgumentException("unknown flags value: " + flags);
+ }
+ return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
+ flags, glyphs);
+ }
+
+ /**
* Convenience overload that takes a char array instead of a
* String.
*
@@ -1859,6 +1896,10 @@
private static native int native_getTextWidths(int native_object,
String text, int start, int end, float[] widths);
+ private static native int native_getTextGlyphs(int native_object,
+ String text, int start, int end, int contextStart, int contextEnd,
+ int flags, char[] glyphs);
+
private static native float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
int flags, float[] advances, int advancesIndex);
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index b8327a8..cfae0c1 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -153,7 +153,6 @@
* the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
* generally be compared across SurfaceTexture instances, or across multiple program
* invocations. It is mostly useful for determining time offsets between subsequent frames.
- * @hide
*/
public long getTimestamp() {
return nativeGetTimestamp();
diff --git a/graphics/java/android/graphics/YuvImage.java b/graphics/java/android/graphics/YuvImage.java
index 9368da6..af3f276 100644
--- a/graphics/java/android/graphics/YuvImage.java
+++ b/graphics/java/android/graphics/YuvImage.java
@@ -36,7 +36,7 @@
private final static int WORKING_COMPRESS_STORAGE = 4096;
/**
- * The YUV format as defined in {@link PixelFormat}.
+ * The YUV format as defined in {@link ImageFormat}.
*/
private int mFormat;
@@ -67,7 +67,7 @@
*
* @param yuv The YUV data. In the case of more than one image plane, all the planes must be
* concatenated into a single byte array.
- * @param format The YUV data format as defined in {@link PixelFormat}.
+ * @param format The YUV data format as defined in {@link ImageFormat}.
* @param width The width of the YuvImage.
* @param height The height of the YuvImage.
* @param strides (Optional) Row bytes of each image plane. If yuv contains padding, the stride
@@ -152,7 +152,7 @@
}
/**
- * @return the YUV format as defined in {@link PixelFormat}.
+ * @return the YUV format as defined in {@link ImageFormat}.
*/
public int getYuvFormat() {
return mFormat;
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 2c09ddc..22fbdf9 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -88,6 +88,7 @@
* Create an empty drawable, setting initial target density based on
* the display metrics of the resources.
*/
+ @SuppressWarnings({"UnusedParameters"})
public BitmapDrawable(Resources res) {
mBitmapState = new BitmapState((Bitmap) null);
mBitmapState.mTargetDensity = mTargetDensity;
@@ -128,6 +129,7 @@
/**
* Create a drawable by opening a given file path and decoding the bitmap.
*/
+ @SuppressWarnings({"UnusedParameters"})
public BitmapDrawable(Resources res, String filepath) {
this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
mBitmapState.mTargetDensity = mTargetDensity;
@@ -152,6 +154,7 @@
/**
* Create a drawable by decoding a bitmap from the given input stream.
*/
+ @SuppressWarnings({"UnusedParameters"})
public BitmapDrawable(Resources res, java.io.InputStream is) {
this(new BitmapState(BitmapFactory.decodeStream(is)), null);
mBitmapState.mTargetDensity = mTargetDensity;
@@ -160,10 +163,16 @@
}
}
+ /**
+ * Returns the paint used to render this drawable.
+ */
public final Paint getPaint() {
return mBitmapState.mPaint;
}
-
+
+ /**
+ * Returns the bitmap used by this drawable to render. May be null.
+ */
public final Bitmap getBitmap() {
return mBitmap;
}
@@ -249,6 +258,12 @@
}
}
+ /**
+ * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects
+ * the edges of the bitmap only so it applies only when the drawable is rotated.
+ *
+ * @param aa True if the bitmap should be anti-aliased, false otherwise.
+ */
public void setAntiAlias(boolean aa) {
mBitmapState.mPaint.setAntiAlias(aa);
invalidateSelf();
@@ -266,26 +281,71 @@
invalidateSelf();
}
+ /**
+ * Indicates the repeat behavior of this drawable on the X axis.
+ *
+ * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
+ * {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+ */
public Shader.TileMode getTileModeX() {
return mBitmapState.mTileModeX;
}
+ /**
+ * Indicates the repeat behavior of this drawable on the Y axis.
+ *
+ * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
+ * {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+ */
public Shader.TileMode getTileModeY() {
return mBitmapState.mTileModeY;
}
+ /**
+ * Sets the repeat behavior of this drawable on the X axis. By default, the drawable
+ * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
+ * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
+ * is smaller than this drawable.
+ *
+ * @param mode The repeat mode for this drawable.
+ *
+ * @see #setTileModeY(android.graphics.Shader.TileMode)
+ * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
+ */
public void setTileModeX(Shader.TileMode mode) {
setTileModeXY(mode, mBitmapState.mTileModeY);
}
+ /**
+ * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
+ * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
+ * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
+ * is smaller than this drawable.
+ *
+ * @param mode The repeat mode for this drawable.
+ *
+ * @see #setTileModeX(android.graphics.Shader.TileMode)
+ * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
+ */
public final void setTileModeY(Shader.TileMode mode) {
setTileModeXY(mBitmapState.mTileModeX, mode);
}
+ /**
+ * Sets the repeat behavior of this drawable on both axis. By default, the drawable
+ * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
+ * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
+ * is smaller than this drawable.
+ *
+ * @param xmode The X repeat mode for this drawable.
+ * @param ymode The Y repeat mode for this drawable.
+ *
+ * @see #setTileModeX(android.graphics.Shader.TileMode)
+ * @see #setTileModeY(android.graphics.Shader.TileMode)
+ */
public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
final BitmapState state = mBitmapState;
- if (state.mPaint.getShader() == null ||
- state.mTileModeX != xmode || state.mTileModeY != ymode) {
+ if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
state.mTileModeX = xmode;
state.mTileModeY = ymode;
mRebuildShader = true;
@@ -316,10 +376,9 @@
if (tmx == null && tmy == null) {
state.mPaint.setShader(null);
} else {
- Shader s = new BitmapShader(bitmap,
+ state.mPaint.setShader(new BitmapShader(bitmap,
tmx == null ? Shader.TileMode.CLAMP : tmx,
- tmy == null ? Shader.TileMode.CLAMP : tmy);
- state.mPaint.setShader(s);
+ tmy == null ? Shader.TileMode.CLAMP : tmy));
}
mRebuildShader = false;
copyBounds(mDstRect);
@@ -335,7 +394,7 @@
canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
} else {
if (mApplyGravity) {
- mDstRect.set(getBounds());
+ copyBounds(mDstRect);
mApplyGravity = false;
}
canvas.drawRect(mDstRect, state.mPaint);
@@ -365,6 +424,7 @@
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mBitmapState = new BitmapState(mBitmapState);
+ mRebuildShader = true;
mMutated = true;
}
return this;
@@ -448,8 +508,8 @@
int mChangingConfigurations;
int mGravity = Gravity.FILL;
Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
- Shader.TileMode mTileModeX;
- Shader.TileMode mTileModeY;
+ Shader.TileMode mTileModeX = null;
+ Shader.TileMode mTileModeY = null;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
BitmapState(Bitmap bitmap) {
@@ -491,6 +551,6 @@
} else {
mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
}
- setBitmap(state.mBitmap);
+ setBitmap(state != null ? state.mBitmap : null);
}
}
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index 4c4a128..084f54a 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -19,7 +19,7 @@
libskia \
libutils \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_STATIC_LIBRARIES :=
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index f3c8f64..3c6dccc 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -219,12 +219,6 @@
// send command to camera driver
status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
- // return the total number of available video buffers.
- int32_t getNumberOfVideoBuffers() const;
-
- // return the individual video buffer corresponding to the given index.
- sp<IMemory> getVideoBuffer(int32_t index) const;
-
// tell camera hal to store meta data or real YUV in video buffers.
status_t storeMetaDataInBuffers(bool enabled);
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
index 86bd849..3f34120 100644
--- a/include/camera/CameraHardwareInterface.h
+++ b/include/camera/CameraHardwareInterface.h
@@ -28,16 +28,6 @@
namespace android {
-/**
- * The size of image for display.
- */
-typedef struct image_rect_struct
-{
- uint32_t width; /* Image width */
- uint32_t height; /* Image height */
-} image_rect_type;
-
-
typedef void (*notify_callback)(int32_t msgType,
int32_t ext1,
int32_t ext2,
@@ -90,9 +80,6 @@
/** Set the ANativeWindow to which preview frames are sent */
virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0;
- /** Return the IMemoryHeap for the raw image heap */
- virtual sp<IMemoryHeap> getRawHeap() const = 0;
-
/** Set the notification and data callbacks */
virtual void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
@@ -145,47 +132,6 @@
virtual bool previewEnabled() = 0;
/**
- * Retrieve the total number of available buffers from camera hal for passing
- * video frame data in a recording session. Must be called again if a new
- * recording session is started.
- *
- * This method should be called after startRecording(), since
- * the some camera hal may choose to allocate the video buffers only after
- * recording is started.
- *
- * Some camera hal may not implement this method, and 0 can be returned to
- * indicate that this feature is not available.
- *
- * @return the number of video buffers that camera hal makes available.
- * Zero (0) is returned to indicate that camera hal does not support
- * this feature.
- */
- virtual int32_t getNumberOfVideoBuffers() const { return 0; }
-
- /**
- * Retrieve the video buffer corresponding to the given index in a
- * recording session. Must be called again if a new recording session
- * is started.
- *
- * It allows a client to retrieve all video buffers that camera hal makes
- * available to passing video frame data by calling this method with all
- * valid index values. The valid index value ranges from 0 to n, where
- * n = getNumberOfVideoBuffers() - 1. With an index outside of the valid
- * range, 0 must be returned. This method should be called after
- * startRecording().
- *
- * The video buffers should NOT be modified/released by camera hal
- * until stopRecording() is called and all outstanding video buffers
- * previously sent out via CAMERA_MSG_VIDEO_FRAME have been released
- * via releaseVideoBuffer().
- *
- * @param index an index to retrieve the corresponding video buffer.
- *
- * @return the video buffer corresponding to the given index.
- */
- virtual sp<IMemory> getVideoBuffer(int32_t index) const { return 0; }
-
- /**
* Request the camera hal to store meta data or real YUV data in
* the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
* recording session. If it is not called, the default camera
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index 2344b3f..400d7f4 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -102,12 +102,6 @@
// send command to camera driver
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
- // return the total number of available video buffers
- virtual int32_t getNumberOfVideoBuffers() const = 0;
-
- // return the individual video buffer corresponding to the given index.
- virtual sp<IMemory> getVideoBuffer(int32_t index) const = 0;
-
// tell the camera hal to store meta data or real YUV data in video buffers.
virtual status_t storeMetaDataInBuffers(bool enabled) = 0;
};
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
index 5011137..b8fe46d 100644
--- a/include/drm/DrmManagerClient.h
+++ b/include/drm/DrmManagerClient.h
@@ -368,7 +368,7 @@
private:
int mUniqueId;
- DrmManagerClientImpl* mDrmManagerClientImpl;
+ sp<DrmManagerClientImpl> mDrmManagerClientImpl;
};
};
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 4a39fbf2..bb25bae3 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -99,34 +99,6 @@
virtual sp<MetaData> getFormat();
/**
- * Retrieve the total number of video buffers available from
- * this source.
- *
- * This method is useful if these video buffers are used
- * for passing video frame data to other media components,
- * such as OMX video encoders, in order to eliminate the
- * memcpy of the data.
- *
- * @return the total numbner of video buffers. Returns 0 to
- * indicate that this source does not make the video
- * buffer information availalble.
- */
- size_t getNumberOfVideoBuffers() const;
-
- /**
- * Retrieve the individual video buffer available from
- * this source.
- *
- * @param index the index corresponding to the video buffer.
- * Valid range of the index is [0, n], where n =
- * getNumberOfVideoBuffers() - 1.
- *
- * @return the video buffer corresponding to the given index.
- * If index is out of range, 0 should be returned.
- */
- sp<IMemory> getVideoBuffer(size_t index) const;
-
- /**
* Tell whether this camera source stores meta data or real YUV
* frame data in video buffers.
*
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 0a6e4fb..972e799 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -291,9 +291,6 @@
void* reserved_proc[2];
};
-// Backwards compatibility... please switch to ANativeWindow.
-typedef struct ANativeWindow android_native_window_t;
-
/*
* native_window_set_usage(..., usage)
* Sets the intended usage flags for the next buffers
diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk
index 2f16923..b17b3d2 100644
--- a/libs/camera/Android.mk
+++ b/libs/camera/Android.mk
@@ -13,7 +13,6 @@
libutils \
libbinder \
libhardware \
- libsurfaceflinger_client \
libui \
libgui
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index e288312..5eb48da 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -205,22 +205,6 @@
return c->startPreview();
}
-int32_t Camera::getNumberOfVideoBuffers() const
-{
- LOGV("getNumberOfVideoBuffers");
- sp <ICamera> c = mCamera;
- if (c == 0) return 0;
- return c->getNumberOfVideoBuffers();
-}
-
-sp<IMemory> Camera::getVideoBuffer(int32_t index) const
-{
- LOGV("getVideoBuffer: %d", index);
- sp <ICamera> c = mCamera;
- if (c == 0) return 0;
- return c->getVideoBuffer(index);
-}
-
status_t Camera::storeMetaDataInBuffers(bool enabled)
{
LOGV("storeMetaDataInBuffers: %s",
diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp
index 931b57d..5f6e5ef 100644
--- a/libs/camera/ICamera.cpp
+++ b/libs/camera/ICamera.cpp
@@ -46,8 +46,6 @@
STOP_RECORDING,
RECORDING_ENABLED,
RELEASE_RECORDING_FRAME,
- GET_NUM_VIDEO_BUFFERS,
- GET_VIDEO_BUFFER,
STORE_META_DATA_IN_BUFFERS,
};
@@ -149,27 +147,6 @@
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
}
- int32_t getNumberOfVideoBuffers() const
- {
- LOGV("getNumberOfVideoBuffers");
- Parcel data, reply;
- data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- remote()->transact(GET_NUM_VIDEO_BUFFERS, data, &reply);
- return reply.readInt32();
- }
-
- sp<IMemory> getVideoBuffer(int32_t index) const
- {
- LOGV("getVideoBuffer: %d", index);
- Parcel data, reply;
- data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeInt32(index);
- remote()->transact(GET_VIDEO_BUFFER, data, &reply);
- sp<IMemory> mem = interface_cast<IMemory>(
- reply.readStrongBinder());
- return mem;
- }
-
status_t storeMetaDataInBuffers(bool enabled)
{
LOGV("storeMetaDataInBuffers: %s", enabled? "true": "false");
@@ -355,19 +332,6 @@
releaseRecordingFrame(mem);
return NO_ERROR;
} break;
- case GET_NUM_VIDEO_BUFFERS: {
- LOGV("GET_NUM_VIDEO_BUFFERS");
- CHECK_INTERFACE(ICamera, data, reply);
- reply->writeInt32(getNumberOfVideoBuffers());
- return NO_ERROR;
- } break;
- case GET_VIDEO_BUFFER: {
- LOGV("GET_VIDEO_BUFFER");
- CHECK_INTERFACE(ICamera, data, reply);
- int32_t index = data.readInt32();
- reply->writeStrongBinder(getVideoBuffer(index)->asBinder());
- return NO_ERROR;
- } break;
case STORE_META_DATA_IN_BUFFERS: {
LOGV("STORE_META_DATA_IN_BUFFERS");
CHECK_INTERFACE(ICamera, data, reply);
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index d1a6af1..58bb0d3 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -10,7 +10,15 @@
SensorEventQueue.cpp \
SensorManager.cpp \
SurfaceTexture.cpp \
- SurfaceTextureClient.cpp
+ SurfaceTextureClient.cpp \
+ ISurfaceComposer.cpp \
+ ISurface.cpp \
+ ISurfaceComposerClient.cpp \
+ IGraphicBufferAlloc.cpp \
+ LayerState.cpp \
+ SharedBufferStack.cpp \
+ Surface.cpp \
+ SurfaceComposerClient.cpp \
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -21,7 +29,6 @@
libui \
libEGL \
libGLESv2 \
- libsurfaceflinger_client
LOCAL_MODULE:= libgui
diff --git a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
similarity index 100%
rename from libs/surfaceflinger_client/IGraphicBufferAlloc.cpp
rename to libs/gui/IGraphicBufferAlloc.cpp
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/gui/ISurface.cpp
similarity index 100%
rename from libs/surfaceflinger_client/ISurface.cpp
rename to libs/gui/ISurface.cpp
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
similarity index 100%
rename from libs/surfaceflinger_client/ISurfaceComposer.cpp
rename to libs/gui/ISurfaceComposer.cpp
diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
similarity index 100%
rename from libs/surfaceflinger_client/ISurfaceComposerClient.cpp
rename to libs/gui/ISurfaceComposerClient.cpp
diff --git a/libs/surfaceflinger_client/LayerState.cpp b/libs/gui/LayerState.cpp
similarity index 100%
rename from libs/surfaceflinger_client/LayerState.cpp
rename to libs/gui/LayerState.cpp
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp
similarity index 100%
rename from libs/surfaceflinger_client/SharedBufferStack.cpp
rename to libs/gui/SharedBufferStack.cpp
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/gui/Surface.cpp
similarity index 100%
rename from libs/surfaceflinger_client/Surface.cpp
rename to libs/gui/Surface.cpp
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
similarity index 100%
rename from libs/surfaceflinger_client/SurfaceComposerClient.cpp
rename to libs/gui/SurfaceComposerClient.cpp
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 7516299..ecd0995 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -9,6 +9,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
+ Surface_test.cpp \
SurfaceTextureClient_test.cpp \
SurfaceTexture_test.cpp \
@@ -20,7 +21,6 @@
libcutils \
libgui \
libstlport \
- libsurfaceflinger_client \
libui \
libutils \
diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
similarity index 100%
rename from libs/surfaceflinger_client/tests/Surface_test.cpp
rename to libs/gui/tests/Surface_test.cpp
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 14471bc..f74238e 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -26,7 +26,7 @@
// Turn on to enable memory usage summary on each frame
#define DEBUG_MEMORY_USAGE 0
-// Turn on to enable layers debugging when renderered as regions
+// Turn on to enable layers debugging when rendered as regions
#define DEBUG_LAYERS_AS_REGIONS 0
// Turn on to display debug info about vertex/fragment shaders
@@ -35,7 +35,7 @@
// Turn on to display info about layers
#define DEBUG_LAYERS 0
-// Turn on to display debug infor about 9patch objects
+// Turn on to display debug info about 9patch objects
#define DEBUG_PATCHES 0
// Turn on to display vertex and tex coords data about 9patch objects
// This flag requires DEBUG_PATCHES to be turned on
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index bf1182c..c7459d1 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -93,7 +93,9 @@
mPaints.clear();
for (size_t i = 0; i < mPaths.size(); i++) {
- delete mPaths.itemAt(i);
+ SkPath* path = mPaths.itemAt(i);
+ caches.pathCache.remove(path);
+ delete path;
}
mPaths.clear();
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 3a7aa96..f685d5f 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -42,7 +42,7 @@
class Font {
public:
enum Style {
- kFakeBold
+ kFakeBold = 1
};
~Font();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6c454a4..6fabbef 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -647,6 +647,9 @@
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
#if RENDER_LAYERS_AS_REGIONS
if (layer->region.isRect()) {
+ const android::Rect& bounds = layer->region.getBounds();
+ layer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
+ bounds.rightBottom().x, bounds.rightBottom().y);
composeLayerRect(layer, layer->regionRect);
layer->region.clear();
return;
@@ -1099,7 +1102,9 @@
setupDraw();
setupDrawWithTexture(true);
- setupDrawAlpha8Color(paint->getColor(), alpha);
+ if (paint) {
+ setupDrawAlpha8Color(paint->getColor(), alpha);
+ }
setupDrawColorFilter();
setupDrawShader();
setupDrawBlending(true, mode);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 2562306..f0bc36b 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -42,7 +42,7 @@
const char* gVS_Header_Uniforms =
"uniform mat4 transform;\n";
const char* gVS_Header_Uniforms_IsPoint =
- "uniform float pointSize;\n";
+ "uniform mediump float pointSize;\n";
const char* gVS_Header_Uniforms_HasGradient[3] = {
// Linear
"uniform mat4 screenSpace;\n",
@@ -53,7 +53,7 @@
};
const char* gVS_Header_Uniforms_HasBitmap =
"uniform mat4 textureTransform;\n"
- "uniform vec2 textureDimension;\n";
+ "uniform mediump vec2 textureDimension;\n";
const char* gVS_Header_Varyings_HasTexture =
"varying vec2 outTexCoords;\n";
const char* gVS_Header_Varyings_HasBitmap =
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 859e503..b5cc29c 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -89,8 +89,11 @@
join = SkPaint::kDefault_Join;
cap = SkPaint::kDefault_Cap;
style = SkPaint::kFill_Style;
- miter = 4.0f;
- strokeWidth = 1.0f;
+ float v = 4.0f;
+ miter = *(uint32_t*) &v;
+ v = 1.0f;
+ strokeWidth = *(uint32_t*) &v;
+ pathEffect = NULL;
}
ShapeCacheEntry(const ShapeCacheEntry& entry):
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 6e4edce..6c5a55b 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -522,7 +522,11 @@
if (drv->mFieldAddress) {
for (size_t ct=0; ct < drv->mFieldCount; ct++) {
if (drv->mFieldIsObject[ct]) {
- rsiClearObject((ObjectBase **)drv->mFieldAddress[ct]);
+ // The field address can be NULL if the script-side has
+ // optimized the corresponding global variable away.
+ if (drv->mFieldAddress[ct]) {
+ rsiClearObject((ObjectBase **)drv->mFieldAddress[ct]);
+ }
}
}
delete [] drv->mFieldAddress;
diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk
index 4a0faf0..267e3edf 100644
--- a/libs/surfaceflinger_client/Android.mk
+++ b/libs/surfaceflinger_client/Android.mk
@@ -1,22 +1,9 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- ISurfaceComposer.cpp \
- ISurface.cpp \
- ISurfaceComposerClient.cpp \
- IGraphicBufferAlloc.cpp \
- LayerState.cpp \
- SharedBufferStack.cpp \
- Surface.cpp \
- SurfaceComposerClient.cpp
+LOCAL_SRC_FILES:=
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libbinder \
- libhardware \
- libui
+LOCAL_SHARED_LIBRARIES :=
LOCAL_MODULE:= libsurfaceflinger_client
diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk
deleted file mode 100644
index 212b8e7..0000000
--- a/libs/surfaceflinger_client/tests/Android.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-ifneq ($(TARGET_SIMULATOR),true)
-
-# Build the unit tests.
-test_src_files := \
- Surface_test.cpp \
-
-shared_libraries := \
- libcutils \
- libutils \
- libbinder \
- libsurfaceflinger_client \
- libstlport \
-
-static_libraries := \
- libgtest \
- libgtest_main \
-
-c_includes := \
- bionic \
- bionic/libstdc++/include \
- external/gtest/include \
- external/stlport/stlport \
-
-module_tags := tests
-
-$(foreach file,$(test_src_files), \
- $(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
- $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
- $(eval LOCAL_C_INCLUDES := $(c_includes)) \
- $(eval LOCAL_SRC_FILES := $(file)) \
- $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
- $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
- $(eval include $(BUILD_EXECUTABLE)) \
-)
-
-# Build the manual test programs.
-include $(call all-subdir-makefiles)
-
-endif
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk
deleted file mode 100644
index d3dfe04..0000000
--- a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- SharedBufferStackTest.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libui \
- libsurfaceflinger_client
-
-LOCAL_MODULE:= test-sharedbufferstack
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
deleted file mode 100644
index 7ef5926..0000000
--- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef NDEBUG
-
-#include <assert.h>
-#include <cutils/memory.h>
-#include <cutils/log.h>
-#include <utils/Errors.h>
-#include <private/surfaceflinger/SharedBufferStack.h>
-
-using namespace android;
-
-void log(const char* prefix, int *b, size_t num);
-void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list);
-
-// ----------------------------------------------------------------------------
-
-int main(int argc, char** argv)
-{
- SharedClient client;
- sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0));
- SharedBufferServer& s(*ps);
- SharedBufferClient c(&client, 0, 4, 0);
-
- printf("basic test 0\n");
- int list0[4] = {0, 1, 2, 3};
- test0(s, c, 4, list0);
-
- printf("basic test 1\n");
- int list1[4] = {2, 1, 0, 3};
- test0(s, c, 4, list1);
-
- int b = c.dequeue();
- c.lock(b);
- c.queue(b);
- s.retireAndLock();
-
- printf("basic test 2\n");
- int list2[4] = {1, 2, 3, 0};
- test0(s, c, 4, list2);
-
-
- printf("resize test\n");
- class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
- SharedBufferServer& s;
- virtual status_t operator()(int bufferCount) const {
- return s.resize(bufferCount);
- }
- public:
- SetBufferCountIPC(SharedBufferServer& s) : s(s) { }
- } resize(s);
-
- c.setBufferCount(6, resize);
- int list3[6] = {3, 2, 1, 4, 5, 0};
- test0(s, c, 6, list3);
-
- c.setBufferCount(4, resize);
- int list4[4] = {1, 2, 3, 0};
- test0(s, c, 4, list4);
-
- return 0;
-}
-
-void log(const char* prefix, int *b, size_t num)
-{
- printf("%s: ", prefix);
- for (size_t i=0 ; i<num ; i++) {
- printf("%d ", b[i]);
- }
- printf("\n");
-}
-
-// ----------------------------------------------------------------------------
-
-void test0(
- SharedBufferServer& s,
- SharedBufferClient& c,
- size_t num,
- int* list)
-{
- status_t err;
- int b[num], u[num], r[num];
-
- for (size_t i=0 ; i<num ; i++) {
- b[i] = c.dequeue();
- assert(b[i]==list[i]);
- }
- log("DQ", b, num);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.lock(b[i]);
- assert(err==0);
- }
- log("LK", b, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.queue(b[i]);
- assert(err==0);
- }
- log(" Q", b, num-1);
-
-
- for (size_t i=0 ; i<num-1 ; i++) {
- r[i] = s.retireAndLock();
- assert(r[i]==list[i]);
- err = s.unlock(r[i]);
- assert(err == 0);
- }
- log("RT", r, num-1);
-
- err = c.lock(b[num-1]);
- assert(err == 0);
- log("LK", b+num-1, 1);
-
- err = c.queue(b[num-1]);
- assert(err == 0);
- log(" Q", b+num-1, 1);
-
- r[num-1] = s.retireAndLock();
- assert(r[num-1]==list[num-1]);
- err = s.unlock(r[num-1]);
- assert(err == 0);
- log("RT", r+num-1, 1);
-
- // ------------------------------------
- printf("\n");
-
- for (size_t i=0 ; i<num ; i++) {
- b[i] = c.dequeue();
- assert(b[i]==list[i]);
- }
- log("DQ", b, num);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.lock(b[i]);
- assert(err==0);
- }
- log("LK", b, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- u[i] = b[num-2-i];
- }
- u[num-1] = b[num-1];
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.queue(u[i]);
- assert(err==0);
- }
- log(" Q", u, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- r[i] = s.retireAndLock();
- assert(r[i]==u[i]);
- err = s.unlock(r[i]);
- assert(err == 0);
- }
- log("RT", r, num-1);
-
- err = c.lock(b[num-1]);
- assert(err == 0);
- log("LK", b+num-1, 1);
-
- err = c.queue(b[num-1]);
- assert(err == 0);
- log(" Q", b+num-1, 1);
-
- r[num-1] = s.retireAndLock();
- assert(r[num-1]==list[num-1]);
- err = s.unlock(r[num-1]);
- assert(err == 0);
- log("RT", r+num-1, 1);
-
- // ------------------------------------
- printf("\n");
-
- for (size_t i=0 ; i<num ; i++) {
- b[i] = c.dequeue();
- assert(b[i]==u[i]);
- }
- log("DQ", b, num);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.lock(b[i]);
- assert(err==0);
- }
- log("LK", b, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.queue(b[i]);
- assert(err==0);
- }
- log(" Q", b, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- r[i] = s.retireAndLock();
- assert(r[i]==u[i]);
- err = s.unlock(r[i]);
- assert(err == 0);
- }
- log("RT", r, num-1);
-
- err = c.lock(u[num-1]);
- assert(err == 0);
- log("LK", u+num-1, 1);
-
- err = c.queue(u[num-1]);
- assert(err == 0);
- log(" Q", u+num-1, 1);
-
- r[num-1] = s.retireAndLock();
- assert(r[num-1]==u[num-1]);
- err = s.unlock(r[num-1]);
- assert(err == 0);
- log("RT", r+num-1, 1);
-
- // ------------------------------------
- printf("\n");
-
- b[0] = c.dequeue();
- assert(b[0]==u[0]);
- log("DQ", b, 1);
-
- c.undoDequeue(b[0]);
- assert(err == 0);
- log("UDQ", b, 1);
-
- // ------------------------------------
- printf("\n");
-
- for (size_t i=0 ; i<num ; i++) {
- b[i] = c.dequeue();
- assert(b[i]==u[i]);
- }
- log("DQ", b, num);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.lock(b[i]);
- assert(err==0);
- }
- log("LK", b, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- err = c.queue(b[i]);
- assert(err==0);
- }
- log(" Q", b, num-1);
-
- for (size_t i=0 ; i<num-1 ; i++) {
- r[i] = s.retireAndLock();
- assert(r[i]==u[i]);
- err = s.unlock(r[i]);
- assert(err == 0);
- }
- log("RT", r, num-1);
-
- err = c.lock(u[num-1]);
- assert(err == 0);
- log("LK", u+num-1, 1);
-
- err = c.queue(u[num-1]);
- assert(err == 0);
- log(" Q", u+num-1, 1);
-
- r[num-1] = s.retireAndLock();
- assert(r[num-1]==u[num-1]);
- err = s.unlock(r[num-1]);
- assert(err == 0);
- log("RT", r+num-1, 1);
- printf("\n");
-}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9aa84a03..cc689bb 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -715,15 +715,13 @@
}
/**
- * Registers the current activity to be notified periodically by
- * the named provider. Periodically, the supplied LocationListener will
- * be called with the current Location or with status updates.
+ * Requests a single location update from the named provider.
*
* <p> It may take a while to receive the most recent location. If
* an immediate location is required, applications may use the
* {@link #getLastKnownLocation(String)} method.
*
- * <p> In case the provider is disabled by the user, updates will stop,
+ * <p> In case the provider is disabled by the user, the update will not be received,
* and the {@link LocationListener#onProviderDisabled(String)}
* method will be called. As soon as the provider is enabled again,
* the {@link LocationListener#onProviderEnabled(String)} method will
@@ -733,8 +731,8 @@
*
* @param provider the name of the provider with which to register
* @param listener a {#link LocationListener} whose
- * {@link LocationListener#onLocationChanged} method will be called for
- * each location update
+ * {@link LocationListener#onLocationChanged} method will be called when
+ * the location update is available
* @param looper a Looper object whose message queue will be used to
* implement the callback mechanism.
* If looper is null then the callbacks will be called on the main thread.
@@ -754,15 +752,13 @@
}
/**
- * Registers the current activity to be notified periodically based on
- * the specified criteria. Periodically, the supplied LocationListener will
- * be called with the current Location or with status updates.
+ * Requests a single location update based on the specified criteria.
*
* <p> It may take a while to receive the most recent location. If
* an immediate location is required, applications may use the
* {@link #getLastKnownLocation(String)} method.
*
- * <p> In case the provider is disabled by the user, updates will stop,
+ * <p> In case the provider is disabled by the user, the update will not be received,
* and the {@link LocationListener#onProviderDisabled(String)}
* method will be called. As soon as the provider is enabled again,
* the {@link LocationListener#onProviderEnabled(String)} method will
@@ -773,8 +769,8 @@
* @param criteria contains parameters for the location manager to choose the
* appropriate provider and parameters to compute the location
* @param listener a {#link LocationListener} whose
- * {@link LocationListener#onLocationChanged} method will be called for
- * each location update
+ * {@link LocationListener#onLocationChanged} method will be called when
+ * the location update is available
* @param looper a Looper object whose message queue will be used to
* implement the callback mechanism.
* If looper is null then the callbacks will be called on the current thread.
@@ -795,16 +791,20 @@
}
/**
- * Registers the current activity to be notified periodically by
- * the named provider. Periodically, the supplied PendingIntent will
- * be broadcast with the current Location or with status updates.
- *
- * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+ * Requests a single location update from the named provider.
*
* <p> It may take a while to receive the most recent location. If
* an immediate location is required, applications may use the
* {@link #getLastKnownLocation(String)} method.
*
+ * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+ *
+ * <p> In case the provider is disabled by the user, the update will not be received,
+ * and the {@link LocationListener#onProviderDisabled(String)}
+ * method will be called. As soon as the provider is enabled again,
+ * the {@link LocationListener#onProviderEnabled(String)} method will
+ * be called and location updates will start again.
+ *
* @param provider the name of the provider with which to register
* @param intent a {#link PendingIntent} to be sent for the location update
*
@@ -823,16 +823,20 @@
}
/**
- * Registers the current activity to be notified periodically based on
- * the specified criteria. Periodically, the supplied PendingIntent will
- * be broadcast with the current Location or with status updates.
- *
- * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+ * Requests a single location update based on the specified criteria.
*
* <p> It may take a while to receive the most recent location. If
* an immediate location is required, applications may use the
* {@link #getLastKnownLocation(String)} method.
*
+ * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+ *
+ * <p> In case the provider is disabled by the user, the update will not be received,
+ * and the {@link LocationListener#onProviderDisabled(String)}
+ * method will be called. As soon as the provider is enabled again,
+ * the {@link LocationListener#onProviderEnabled(String)} method will
+ * be called and location updates will start again.
+ *
* @param criteria contains parameters for the location manager to choose the
* appropriate provider and parameters to compute the location
* @param intent a {#link PendingIntent} to be sent for the location update
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index a027bc6..c41e0ad 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -185,6 +185,7 @@
addFileType("IMY", FILE_TYPE_IMY, "audio/imelody");
addFileType("RTX", FILE_TYPE_MID, "audio/midi");
addFileType("OTA", FILE_TYPE_MID, "audio/midi");
+ addFileType("MXMF", FILE_TYPE_MID, "audio/midi");
addFileType("MPEG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG);
addFileType("MPG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index fcbe59e..e2dee00 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1616,10 +1616,12 @@
/** MediaPlayer is temporarily pausing playback internally in order to
* buffer more data.
+ * @see android.media.MediaPlayer.OnInfoListener
*/
public static final int MEDIA_INFO_BUFFERING_START = 701;
/** MediaPlayer is resuming playback after filling buffers.
+ * @see android.media.MediaPlayer.OnInfoListener
*/
public static final int MEDIA_INFO_BUFFERING_END = 702;
@@ -1654,6 +1656,8 @@
* <ul>
* <li>{@link #MEDIA_INFO_UNKNOWN}
* <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
+ * <li>{@link #MEDIA_INFO_BUFFERING_START}
+ * <li>{@link #MEDIA_INFO_BUFFERING_END}
* <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
* <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
* <li>{@link #MEDIA_INFO_METADATA_UPDATE}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 6b9f2fb..02f3902 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -347,7 +347,6 @@
private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
private static class FileCacheEntry {
- Uri mTableUri;
long mRowId;
String mPath;
long mLastModified;
@@ -355,8 +354,7 @@
boolean mSeenInFileSystem;
boolean mLastModifiedChanged;
- FileCacheEntry(Uri tableUri, long rowId, String path, long lastModified, int format) {
- mTableUri = tableUri;
+ FileCacheEntry(long rowId, String path, long lastModified, int format) {
mRowId = rowId;
mPath = path;
mLastModified = lastModified;
@@ -367,7 +365,7 @@
@Override
public String toString() {
- return mPath + " mTableUri: " + mTableUri + " mRowId: " + mRowId;
+ return mPath + " mRowId: " + mRowId;
}
}
@@ -491,23 +489,10 @@
long delta = (entry != null) ? (lastModified - entry.mLastModified) : 0;
boolean wasModified = delta > 1 || delta < -1;
if (entry == null || wasModified) {
- Uri tableUri;
- if (isDirectory) {
- tableUri = mFilesUri;
- } else if (MediaFile.isVideoFileType(mFileType)) {
- tableUri = mVideoUri;
- } else if (MediaFile.isImageFileType(mFileType)) {
- tableUri = mImagesUri;
- } else if (MediaFile.isAudioFileType(mFileType)) {
- tableUri = mAudioUri;
- } else {
- tableUri = mFilesUri;
- }
if (wasModified) {
entry.mLastModified = lastModified;
- entry.mTableUri = tableUri;
} else {
- entry = new FileCacheEntry(tableUri, 0, path, lastModified,
+ entry = new FileCacheEntry(0, path, lastModified,
(isDirectory ? MtpConstants.FORMAT_ASSOCIATION : 0));
mFileCache.put(key, entry);
}
@@ -829,7 +814,14 @@
}
}
- Uri tableUri = entry.mTableUri;
+ Uri tableUri = mFilesUri;
+ if (MediaFile.isVideoFileType(mFileType)) {
+ tableUri = mVideoUri;
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ tableUri = mImagesUri;
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ tableUri = mAudioUri;
+ }
Uri result = null;
if (rowId == 0) {
if (mMtpObjectHandle != 0) {
@@ -1021,13 +1013,13 @@
// Only consider entries with absolute path names.
// This allows storing URIs in the database without the
// media scanner removing them.
- if (path.startsWith("/")) {
+ if (path != null && path.startsWith("/")) {
String key = path;
if (mCaseInsensitivePaths) {
key = path.toLowerCase();
}
- FileCacheEntry entry = new FileCacheEntry(mFilesUri, rowId, path,
+ FileCacheEntry entry = new FileCacheEntry(rowId, path,
lastModified, format);
mFileCache.put(key, entry);
}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 2a89a2a..4fd4147 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -22,7 +22,7 @@
libskia \
libui \
libcutils \
- libsurfaceflinger_client \
+ libgui \
libstagefright \
libcamera_client \
libsqlite \
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 283b4ea..69cfe8c 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -55,7 +55,7 @@
libbinder \
libstagefright \
libstagefright_omx \
- libsurfaceflinger_client \
+ libgui \
libvideoeditorplayer
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index a04fbd2..ca7441a 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -38,7 +38,7 @@
LOCAL_SHARED_LIBRARIES := \
libui libcutils libutils libbinder libsonivox libicuuc libexpat \
- libsurfaceflinger_client libcamera_client libstagefright_foundation \
+ libcamera_client libstagefright_foundation \
libgui
LOCAL_MODULE:= libmedia
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index e65f6d8..fadad285 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -31,8 +31,7 @@
libandroid_runtime \
libstagefright \
libstagefright_omx \
- libstagefright_foundation \
- libsurfaceflinger_client \
+ libstagefright_foundation \
libgui
LOCAL_STATIC_LIBRARIES := \
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e445b74..d2e8b46 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -70,7 +70,6 @@
libui \
libsonivox \
libvorbisidec \
- libsurfaceflinger_client \
libstagefright_yuv \
libcamera_client \
libdrmframework \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 07f250a..162d2e6 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -452,6 +452,10 @@
Mutex::Autolock autoLock(mLock);
if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
+ if (mSeeking) {
+ return mSeekTimeUs;
+ }
+
return 0;
}
@@ -477,6 +481,7 @@
Mutex::Autolock autoLock(mLock);
mSeeking = true;
+ mPositionTimeRealUs = mPositionTimeMediaUs = -1;
mReachedEOS = false;
mSeekTimeUs = time_us;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 7fdb1a1..7940de0 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define DEBUG_HDCP
+
//#define LOG_NDEBUG 0
#define LOG_TAG "AwesomePlayer"
#include <utils/Log.h>
@@ -50,6 +52,8 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <cutils/properties.h>
+
#define USE_SURFACE_ALLOC 1
#define FRAME_DROP_FREQ 0
@@ -571,7 +575,7 @@
int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
- if (videoLateByUs > 300000ll) {
+ if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
LOGV("video late by %lld ms.", videoLateByUs / 1000ll);
notifyListener_l(
@@ -1059,7 +1063,8 @@
}
else if (mSeeking != NO_SEEK) {
*positionUs = mSeekTimeUs;
- } else if (mVideoSource != NULL) {
+ } else if (mVideoSource != NULL
+ && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
Mutex::Autolock autoLock(mMiscStateLock);
*positionUs = mVideoTimeUs;
} else if (mAudioPlayer != NULL) {
@@ -1101,6 +1106,14 @@
play_l();
}
+ if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
+ // Video playback completed before, there's no pending
+ // video event right now. In order for this new seek
+ // to be honored, we need to post one.
+
+ postVideoEvent_l();
+ }
+
mSeeking = SEEK;
mSeekNotificationSent = false;
mSeekTimeUs = timeUs;
@@ -1202,9 +1215,42 @@
// (USE_SURFACE_ALLOC && (mSurface != 0) &&
// (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
// will be true, but that part is already handled by SurfaceFlinger.
+
+#ifdef DEBUG_HDCP
+ // For debugging, we allow a system property to control the protected usage.
+ // In case of uninitialized or unexpected property, we default to "DRM only".
+ bool setProtectionBit = false;
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.sys.hdcp_checking", value, NULL)) {
+ if (!strcmp(value, "never")) {
+ // nop
+ } else if (!strcmp(value, "always")) {
+ setProtectionBit = true;
+ } else if (!strcmp(value, "drm-only")) {
+ if (mDecryptHandle != NULL) {
+ setProtectionBit = true;
+ }
+ // property value is empty, or unexpected value
+ } else {
+ if (mDecryptHandle != NULL) {
+ setProtectionBit = true;
+ }
+ }
+ // can' read property value
+ } else {
+ if (mDecryptHandle != NULL) {
+ setProtectionBit = true;
+ }
+ }
+ // note that usage bit is already cleared, so no need to clear it in the "else" case
+ if (setProtectionBit) {
+ flags |= OMXCodec::kEnableGrallocUsageProtected;
+ }
+#else
if (mDecryptHandle != NULL) {
flags |= OMXCodec::kEnableGrallocUsageProtected;
}
+#endif
LOGV("initVideoDecoder flags=0x%x", flags);
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
@@ -1250,6 +1296,7 @@
mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
mWatchForAudioSeekComplete = true;
+ mWatchForAudioEOS = true;
} else if (!mSeekNotificationSent) {
// If we're playing video only, report seek complete now,
// otherwise audio player will notify us later.
@@ -1340,6 +1387,11 @@
}
finishSeekIfNecessary(-1);
+ if (mAudioPlayer != NULL
+ && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
+ startAudioPlayer_l();
+ }
+
mFlags |= VIDEO_AT_EOS;
postStreamDoneEvent_l(err);
return;
@@ -1710,12 +1762,7 @@
if (mDecryptHandle != NULL) {
CHECK(mDrmManagerClient);
- if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
- if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
- LOGD("Setting mCachedSource to NULL for WVM\n");
- mCachedSource.clear();
- }
- } else {
+ if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
}
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 8a24bc45..a1f04d3 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -740,28 +740,6 @@
mFrameAvailableCondition.signal();
}
-size_t CameraSource::getNumberOfVideoBuffers() const {
- LOGV("getNumberOfVideoBuffers");
- size_t nBuffers = 0;
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- if (mInitCheck == OK && mCamera != 0) {
- nBuffers = mCamera->getNumberOfVideoBuffers();
- }
- IPCThreadState::self()->restoreCallingIdentity(token);
- return nBuffers;
-}
-
-sp<IMemory> CameraSource::getVideoBuffer(size_t index) const {
- LOGV("getVideoBuffer: %d", index);
- sp<IMemory> buffer = 0;
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- if (mInitCheck == OK && mCamera != 0) {
- buffer = mCamera->getVideoBuffer(index);
- }
- IPCThreadState::self()->restoreCallingIdentity(token);
- return buffer;
-}
-
bool CameraSource::isMetaDataStoredInVideoBuffers() const {
LOGV("isMetaDataStoredInVideoBuffers");
return mIsMetaDataStoredInVideoBuffers;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index a6a34b3..904bd62 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1912,6 +1912,11 @@
}
void OMXCodec::on_message(const omx_message &msg) {
+ if (mState == ERROR) {
+ LOGW("Dropping OMX message - we're in ERROR state.");
+ return;
+ }
+
switch (msg.type) {
case omx_message::EVENT:
{
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 84f65ff..8b86e53 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -37,7 +37,7 @@
".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
- ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac"
+ ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
@@ -124,7 +124,8 @@
|| !strcasecmp(extension, ".xmf")
|| !strcasecmp(extension, ".rtttl")
|| !strcasecmp(extension, ".rtx")
- || !strcasecmp(extension, ".ota")) {
+ || !strcasecmp(extension, ".ota")
+ || !strcasecmp(extension, ".mxmf")) {
status_t status = HandleMIDI(path, &client);
if (status != OK) {
return status;
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index b7087f8..a5b316d 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -33,18 +33,30 @@
struct ALooper::LooperThread : public Thread {
LooperThread(ALooper *looper, bool canCallJava)
: Thread(canCallJava),
- mLooper(looper) {
+ mLooper(looper),
+ mThreadId(NULL) {
+ }
+
+ virtual status_t readyToRun() {
+ mThreadId = androidGetThreadId();
+
+ return Thread::readyToRun();
}
virtual bool threadLoop() {
return mLooper->loop();
}
+ bool isCurrentThread() const {
+ return mThreadId == androidGetThreadId();
+ }
+
protected:
virtual ~LooperThread() {}
private:
ALooper *mLooper;
+ android_thread_id_t mThreadId;
DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
};
@@ -136,7 +148,9 @@
mQueueChangedCondition.signal();
- if (!runningLocally) {
+ if (!runningLocally && !thread->isCurrentThread()) {
+ // If not running locally and this thread _is_ the looper thread,
+ // the loop() function will return and never be called again.
thread->requestExitAndWait();
}
@@ -197,6 +211,11 @@
gLooperRoster.deliverMessage(event.mMessage);
+ // NOTE: It's important to note that at this point our "ALooper" object
+ // may no longer exist (its final reference may have gone away while
+ // delivering the message). We have made sure, however, that loop()
+ // won't be called again.
+
return true;
}
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 6cbd599..cdce772 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "OMXNodeInstance"
#include <utils/Log.h>
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 0740515..c4e0cdc 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -20,6 +20,8 @@
#include "ARTSPConnection.h"
+#include <cutils/properties.h>
+
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -44,6 +46,7 @@
mConnectionID(0),
mNextCSeq(0),
mReceiveResponseEventPending(false) {
+ MakeUserAgent(&mUserAgent);
}
ARTSPConnection::~ARTSPConnection() {
@@ -378,6 +381,7 @@
reply->setString("original-request", request.c_str(), request.size());
addAuthentication(&request);
+ addUserAgent(&request);
// Find the boundary between headers and the body.
ssize_t i = request.find("\r\n\r\n");
@@ -979,4 +983,27 @@
#endif
}
+// static
+void ARTSPConnection::MakeUserAgent(AString *userAgent) {
+ userAgent->clear();
+ userAgent->setTo("User-Agent: stagefright/1.1 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ userAgent->append(value);
+ userAgent->append(")\r\n");
+}
+
+void ARTSPConnection::addUserAgent(AString *request) const {
+ // Find the boundary between headers and the body.
+ ssize_t i = request->find("\r\n\r\n");
+ CHECK_GE(i, 0);
+
+ request->insert(mUserAgent, i + 2);
+}
+
} // namespace android
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 0fecf3c..ac2e3ae 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -87,6 +87,8 @@
sp<AMessage> mObserveBinaryMessage;
+ AString mUserAgent;
+
void onConnect(const sp<AMessage> &msg);
void onDisconnect(const sp<AMessage> &msg);
void onCompleteConnection(const sp<AMessage> &msg);
@@ -106,6 +108,8 @@
bool parseAuthMethod(const sp<ARTSPResponse> &response);
void addAuthentication(AString *request);
+ void addUserAgent(AString *request) const;
+
status_t findPendingRequest(
const sp<ARTSPResponse> &response, ssize_t *index) const;
@@ -114,6 +118,8 @@
static bool ParseSingleUnsignedLong(
const char *from, unsigned long *x);
+ static void MakeUserAgent(AString *userAgent);
+
DISALLOW_EVIL_CONSTRUCTORS(ARTSPConnection);
};
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
index 432fb43..94ffb8e 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
@@ -51,10 +51,11 @@
import android.os.Debug;
import android.util.Log;
-
+import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner;
import com.android.mediaframeworktest.MediaFrameworkTest;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.mediaframeworktest.VideoEditorHelper;
+import com.android.mediaframeworktest.MediaTestUtil;
/**
* Junit / Instrumentation - performance measurement for media player and
@@ -63,7 +64,7 @@
public class VideoEditorStressTest
extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private final String TAG = "VideoEditorPerformance";
+ private final String TAG = "VideoEditorStressTest";
private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
@@ -86,12 +87,17 @@
private final String PROJECT_CLASS_NAME =
"android.media.videoeditor.VideoEditorImpl";
private VideoEditor mVideoEditor;
+ private MediaTestUtil mMediaTestUtil;
private VideoEditorHelper mVideoEditorHelper;
@Override
protected void setUp() throws Exception {
// setup for each test case.
super.setUp();
+ getActivity();
+ mMediaTestUtil = new MediaTestUtil(
+ "/sdcard/VideoEditorMediaServerMemoryLog.txt",
+ this.getName(), "mediaserver");
mVideoEditorHelper = new VideoEditorHelper();
// Create a random String which will be used as project path, where all
// project related files will be stored.
@@ -102,6 +108,12 @@
@Override
protected void tearDown() throws Exception {
+ final String[] loggingInfo = new String[1];
+ mMediaTestUtil.getMemorySummary();
+ loggingInfo[0] = "\n" +this.getName();
+ writeTimingInfo(loggingInfo);
+ loggingInfo[0] = " diff : " + (AfterNativeMemory - BeginNativeMemory);
+ writeTimingInfo(loggingInfo);
mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
// Clean the directory created as project path
mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
@@ -131,6 +143,7 @@
System.gc();
Thread.sleep(2500);
BeginNativeMemory = Debug.getNativeHeapAllocatedSize();
+ mMediaTestUtil.getStartMemoryLog();
}
private void getAfterMemory_updateLog(String[] loggingInfo, boolean when,
int iteration)
@@ -146,6 +159,7 @@
"\t " + (AfterNativeMemory - BeginNativeMemory);
}
writeTimingInfo(loggingInfo);
+ mMediaTestUtil.getMemoryLog();
}
/**
@@ -170,7 +184,6 @@
writeTestCaseHeader("testStressAddRemoveVideoItem");
int i = 0;
getBeginMemory();
-
for ( i = 0; i < 50; i++) {
if (i % 4 == 0) {
final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
@@ -203,7 +216,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for ( i = 0; i < 50; i++) {
if (i % 4 == 0) {
mVideoEditor.removeMediaItem("m1" + i);
@@ -273,7 +285,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for ( i = 0; i < 50; i++) {
if (i % 4 == 0) {
mVideoEditor.removeMediaItem("m1"+i);
@@ -387,7 +398,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for ( i = 0; i < 50; i++) {
if (i % 4 == 0) {
mVideoEditor.removeTransition("transCF" + i);
@@ -551,7 +561,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for ( i = 0; i < 50; i++) {
if (i % 5 == 0) {
mediaItem1.removeEffect("effect1"+i);
@@ -773,15 +782,14 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for ( i = 0; i < 50; i++) {
mVideoEditor.removeMediaItem("m3" + i);
if (i % 10 == 0) {
getAfterMemory_updateLog(loggingInfo, true, i);
}
}
- mVideoEditor.removeMediaItem("m2");
- mVideoEditor.removeMediaItem("m1");
+ mVideoEditor.removeMediaItem("m2");
+ mVideoEditor.removeMediaItem("m1");
getAfterMemory_updateLog(loggingInfo, true, i);
}
@@ -879,7 +887,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for( i=0; i<10; i++){
final VideoEditor mVideoEditor1b =
VideoEditorFactory.load(projectPath[i], true);
@@ -986,7 +993,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
mVideoEditor.removeMediaItem("m2");
mVideoEditor.removeMediaItem("m1");
@@ -1063,7 +1069,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
for ( i = 0; i < 10; i++) {
MediaImageItem m2 = (MediaImageItem)mVideoEditor.getMediaItem("m2"+i);
MediaVideoItem m1 = (MediaVideoItem)mVideoEditor.getMediaItem("m1"+i);
@@ -1129,7 +1134,6 @@
getAfterMemory_updateLog(loggingInfo, false, i);
/** Remove items and check for memory leak if any */
- getBeginMemory();
mVideoEditor.removeMediaItem("mediaItem1");
getAfterMemory_updateLog(loggingInfo, true, i);
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 44ec83f..9940442f 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -22,7 +22,6 @@
libbinder \
libui \
libgui \
- libsurfaceflinger_client \
libandroid_runtime
LOCAL_STATIC_LIBRARIES := \
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 953ee10..f1738c6 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -297,6 +297,14 @@
* may not be the window currently touched.
*/
AMOTION_EVENT_ACTION_SCROLL = 8,
+
+ /* The pointer is not down but has entered the boundaries of a window or view.
+ */
+ AMOTION_EVENT_ACTION_HOVER_ENTER = 9,
+
+ /* The pointer is not down but has exited the boundaries of a window or view.
+ */
+ AMOTION_EVENT_ACTION_HOVER_EXIT = 10,
};
/*
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index cf38bd1..ed1af49 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -57,7 +57,6 @@
// protected by NfcAdapterExtras.class, and final after first construction
private static INfcAdapterExtras sService;
- private static boolean sIsInitialized = false;
private static NfcAdapterExtras sSingleton;
private static NfcExecutionEnvironment sEmbeddedEe;
private static CardEmulationRoute sRouteOff;
@@ -74,14 +73,22 @@
*/
public static NfcAdapterExtras get(NfcAdapter adapter) {
synchronized(NfcAdapterExtras.class) {
- if (!sIsInitialized) {
- sIsInitialized = true;
- sService = adapter.getNfcAdapterExtrasInterface();
- sEmbeddedEe = new NfcExecutionEnvironment(sService);
- sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
- sRouteOnWhenScreenOn = new CardEmulationRoute(
- CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
- sSingleton = new NfcAdapterExtras();
+ if (sSingleton == null) {
+ try {
+ sService = adapter.getNfcAdapterExtrasInterface();
+ sEmbeddedEe = new NfcExecutionEnvironment(sService);
+ sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+ sRouteOnWhenScreenOn = new CardEmulationRoute(
+ CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
+ sSingleton = new NfcAdapterExtras();
+ } finally {
+ if (sSingleton == null) {
+ sService = null;
+ sEmbeddedEe = null;
+ sRouteOff = null;
+ sRouteOnWhenScreenOn = null;
+ }
+ }
}
return sSingleton;
}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 123306b6..7d72729 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -13,7 +13,7 @@
EGL/hooks.cpp \
EGL/Loader.cpp \
#
-LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite
+LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf
LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 75f7078..a53b375 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -72,25 +72,78 @@
// ----------------------------------------------------------------------------
-class egl_object_t {
- static SortedVector<egl_object_t*> sObjects;
- static Mutex sLock;
+class egl_object_t;
+struct egl_display_t;
+static egl_display_t* get_display(EGLDisplay dpy);
+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;
+ }
+};
+
+struct egl_display_t {
+ enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
+
+ struct strings_t {
+ char const * vendor;
+ char const * version;
+ char const * clientApi;
+ char const * extensions;
+ };
+
+ struct DisplayImpl {
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
+ state(NOT_INITIALIZED), numConfigs(0) { }
+ EGLDisplay dpy;
+ EGLConfig* config;
+ EGLint state;
+ EGLint numConfigs;
+ strings_t queryString;
+ };
+
+ uint32_t magic;
+ DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
+ EGLint numTotalConfigs;
+ egl_config_t* configs;
+ uint32_t refs;
+ Mutex lock;
+
+ SortedVector<egl_object_t*> objects;
+
+ egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { }
+ ~egl_display_t() { magic = 0; }
+ inline bool isReady() const { return (refs > 0); }
+ inline bool isValid() const { return magic == '_dpy'; }
+ inline bool isAlive() const { return isValid(); }
+};
+
+class egl_object_t {
+ egl_display_t *display;
volatile int32_t terminated;
mutable volatile int32_t count;
public:
- egl_object_t() : terminated(0), count(1) {
- Mutex::Autolock _l(sLock);
- sObjects.add(this);
+ egl_object_t(EGLDisplay dpy) : display(get_display(dpy)), terminated(0), count(1) {
+ Mutex::Autolock _l(display->lock);
+ display->objects.add(this);
}
inline bool isAlive() const { return !terminated; }
private:
bool get() {
- Mutex::Autolock _l(sLock);
- if (egl_object_t::sObjects.indexOf(this) >= 0) {
+ Mutex::Autolock _l(display->lock);
+ if (display->objects.indexOf(this) >= 0) {
android_atomic_inc(&count);
return true;
}
@@ -98,9 +151,9 @@
}
bool put() {
- Mutex::Autolock _l(sLock);
+ Mutex::Autolock _l(display->lock);
if (android_atomic_dec(&count) == 1) {
- sObjects.remove(this);
+ display->objects.remove(this);
return true;
}
return false;
@@ -147,65 +200,13 @@
};
};
-SortedVector<egl_object_t*> egl_object_t::sObjects;
-Mutex egl_object_t::sLock;
-
-
-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;
- }
-};
-
-struct egl_display_t {
- enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
-
- struct strings_t {
- char const * vendor;
- char const * version;
- char const * clientApi;
- char const * extensions;
- };
-
- struct DisplayImpl {
- DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
- state(NOT_INITIALIZED), numConfigs(0) { }
- EGLDisplay dpy;
- EGLConfig* config;
- EGLint state;
- EGLint numConfigs;
- strings_t queryString;
- };
-
- uint32_t magic;
- DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- egl_config_t* configs;
- uint32_t refs;
- Mutex lock;
-
- egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { }
- ~egl_display_t() { magic = 0; }
- inline bool isValid() const { return magic == '_dpy'; }
- inline bool isAlive() const { return isValid(); }
-};
-
struct egl_surface_t : public egl_object_t
{
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)
- : dpy(dpy), surface(surface), config(config), win(win), impl(impl), cnx(cnx) {
+ : egl_object_t(dpy), dpy(dpy), surface(surface), config(config), win(win), impl(impl), cnx(cnx) {
}
~egl_surface_t() {
}
@@ -223,8 +224,8 @@
egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
int impl, egl_connection_t const* cnx, int version)
- : dpy(dpy), context(context), config(config), read(0), draw(0), impl(impl),
- cnx(cnx), version(version), dbg(NULL)
+ : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
+ impl(impl), cnx(cnx), version(version), dbg(NULL)
{
}
~egl_context_t()
@@ -249,7 +250,7 @@
typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
egl_image_t(EGLDisplay dpy, EGLContext context)
- : dpy(dpy), context(context)
+ : egl_object_t(dpy), dpy(dpy), context(context)
{
memset(images, 0, sizeof(images));
}
@@ -263,7 +264,7 @@
typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync)
- : dpy(dpy), context(context), sync(sync)
+ : egl_object_t(dpy), dpy(dpy), context(context), sync(sync)
{
}
EGLDisplay dpy;
@@ -609,12 +610,22 @@
return egl_to_native_cast<egl_sync_t>(sync);
}
+static inline
+egl_display_t* validate_display(EGLDisplay dpy)
+{
+ egl_display_t * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
+ if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
+
+ return dp;
+}
+
static egl_connection_t* validate_display_config(
EGLDisplay dpy, EGLConfig config,
egl_display_t const*& dp)
{
- dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
+ 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);
@@ -628,9 +639,9 @@
static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
{
- if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isAlive())
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+ if (!dp->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (!get_context(ctx)->isAlive())
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
@@ -639,9 +650,9 @@
static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
{
- if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isAlive())
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+ if (!dp->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (!get_surface(surface)->isAlive())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@@ -961,8 +972,8 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
GLint numConfigs = dp->numTotalConfigs;
if (!configs) {
@@ -987,8 +998,8 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
if (num_config==0) {
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -1206,12 +1217,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t * const s = get_surface(surface);
EGLBoolean result = s->cnx->egl.eglDestroySurface(
@@ -1230,12 +1243,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
EGLBoolean result(EGL_TRUE);
@@ -1298,12 +1313,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
ContextRef _c(ctx);
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
EGLBoolean result = c->cnx->egl.eglDestroyContext(
dp->disp[c->impl].dpy, c->context);
@@ -1339,14 +1356,23 @@
{
clearError();
+ egl_display_t const * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ /* If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
+ EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
+ a valid but uninitialized display. */
+ if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
+ (draw != EGL_NO_SURFACE) ) {
+ if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+
// get a reference to the object passed in
ContextRef _c(ctx);
SurfaceRef _d(draw);
SurfaceRef _r(read);
- // validate the display and the context (if not EGL_NO_CONTEXT)
- egl_display_t const * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // validate the context (if not EGL_NO_CONTEXT)
if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
// EGL_NO_CONTEXT is valid
return EGL_FALSE;
@@ -1439,13 +1465,15 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
ContextRef _c(ctx);
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
EGLBoolean result(EGL_TRUE);
@@ -1681,12 +1709,14 @@
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(draw);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, draw))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
}
@@ -1696,12 +1726,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->egl.eglCopyBuffers(
dp->disp[s->impl].dpy, s->surface, target);
@@ -1711,7 +1743,9 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return (const char *) NULL;
+
switch (name) {
case EGL_VENDOR:
return gVendorString;
@@ -1735,12 +1769,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglSurfaceAttrib) {
return s->cnx->egl.eglSurfaceAttrib(
@@ -1754,12 +1790,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglBindTexImage) {
return s->cnx->egl.eglBindTexImage(
@@ -1773,12 +1811,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglReleaseTexImage) {
return s->cnx->egl.eglReleaseTexImage(
@@ -1791,8 +1831,8 @@
{
clearError();
- egl_display_t * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
EGLBoolean res = EGL_TRUE;
for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
@@ -1930,13 +1970,15 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglLockSurfaceKHR) {
@@ -1950,13 +1992,15 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(surface);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglUnlockSurfaceKHR) {
@@ -1971,12 +2015,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_NO_IMAGE_KHR;
+
if (ctx != EGL_NO_CONTEXT) {
ContextRef _c(ctx);
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
if (!validate_display_context(dpy, ctx))
return EGL_NO_IMAGE_KHR;
- egl_display_t const * const dp = get_display(dpy);
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(
@@ -1989,10 +2035,6 @@
return (EGLImageKHR)result;
} else {
// EGL_NO_CONTEXT is a valid parameter
- egl_display_t const * const dp = get_display(dpy);
- if (dp == 0) {
- return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
- }
/* 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
@@ -2044,35 +2086,33 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
- if (dp == 0) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- }
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
- ImageRef _i(img);
- if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ ImageRef _i(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;
- }
- }
- }
- }
- }
- if (!success)
- return 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;
+ }
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_FALSE;
- _i.terminate();
+ _i.terminate();
- return EGL_TRUE;
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
@@ -2084,12 +2124,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_NO_SYNC_KHR;
+
EGLContext ctx = eglGetCurrentContext();
ContextRef _c(ctx);
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
if (!validate_display_context(dpy, ctx))
return EGL_NO_SYNC_KHR;
- egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
EGLSyncKHR result = EGL_NO_SYNC_KHR;
if (c->cnx->egl.eglCreateSyncKHR) {
@@ -2106,10 +2148,8 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
- if (dp == 0) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- }
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
SyncRef _s(sync);
if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2136,10 +2176,8 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
- if (dp == 0) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- }
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
SyncRef _s(sync);
if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2165,10 +2203,8 @@
{
clearError();
- egl_display_t const * const dp = get_display(dpy);
- if (dp == 0) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- }
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
SyncRef _s(sync);
if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2199,12 +2235,14 @@
{
clearError();
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
SurfaceRef _s(draw);
if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (!validate_display_surface(dpy, draw))
return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
if (s->cnx->egl.eglSetSwapRectangleANDROID) {
return s->cnx->egl.eglSetSwapRectangleANDROID(
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index e593c327..fc40799 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -4,11 +4,11 @@
LOCAL_SRC_FILES := \
src/api.cpp \
+ src/caller.cpp \
src/dbgcontext.cpp \
src/debugger_message.pb.cpp \
src/egl.cpp \
src/server.cpp \
- src/texture.cpp \
src/vertex.cpp
LOCAL_C_INCLUDES := \
@@ -16,6 +16,7 @@
$(LOCAL_PATH)/../ \
external/stlport/stlport \
external/protobuf/src \
+ external \
bionic
#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
index 5b024ad..66c110f 100755
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py
@@ -31,11 +31,11 @@
externs = []
i = 0
# these have been hand written
- skipFunctions = ["glTexImage2D", "glTexSubImage2D", "glReadPixels",
-"glDrawArrays", "glDrawElements"]
+ skipFunctions = ["glReadPixels", "glDrawArrays", "glDrawElements"]
# these have an EXTEND_Debug_* macro for getting data
- extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource"]
+ extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource",
+"glTexImage2D", "glTexSubImage2D"]
# these also needs to be forwarded to DbgContext
contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
@@ -67,8 +67,7 @@
externs.append(extern)
print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
- print """ glesv2debugger::Message msg;
- const bool expectResponse = false;"""
+ print " glesv2debugger::Message msg;"
if parameterList == "void":
parameters = []
@@ -159,8 +158,8 @@
print getData
if functionName in extendFunctions:
print " EXTEND_Debug_%s;" % (functionName)
- print " int * ret = MessageLoop(caller, msg, expectResponse,"
- print " glesv2debugger::Message_Function_%s);" % (functionName)
+ print " int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\
+ % (functionName)
if returnType != "void":
if returnType == "GLboolean":
print " return static_cast<GLboolean>(reinterpret_cast<int>(ret));"
diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
new file mode 100755
index 0000000..eac2292
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
@@ -0,0 +1,200 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# 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.
+#
+
+import os
+import sys
+
+externs = []
+
+def generate_caller(lines):
+ i = 0
+ output = ""
+ skipFunctions = []
+
+ for line in lines:
+ if line.find("API_ENTRY(") >= 0: # a function prototype
+ returnType = line[0: line.find(" API_ENTRY(")]
+ functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
+ parameterList = line[line.find(")(") + 2: line.find(") {")]
+
+ #if line.find("*") >= 0:
+ # extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
+ # externs.append(extern)
+ # continue
+
+ if functionName in skipFunctions:
+ sys.stderr.write("!\n! skipping function '%s'\n!\n" % functionName)
+ continue
+ output += "\
+ case glesv2debugger::Message_Function_%s:\n" % functionName
+ parameters = parameterList.split(',')
+ paramIndex = 0
+ if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
+ # add function to list of functions that should be hand written, but generate code anyways
+ externs.append(functionName)
+ output += "\
+ ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\
+ break;\n" % (functionName)
+ continue
+ elif line.find(":out") >= 0 or line.find(":inout") >= 0:
+ externs.append(functionName)
+ output += "\
+ ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\
+ break; // annotated output pointers\n" % (functionName)
+ continue
+
+ if parameterList == "void":
+ parameters = []
+ arguments = ""
+ paramNames = []
+ inout = ""
+ getData = ""
+
+ callerMembers = ""
+
+ for parameter in parameters:
+ const = parameter.find("const")
+ parameter = parameter.replace("const", "")
+ parameter = parameter.strip()
+ paramType = parameter.split(' ')[0]
+ paramName = parameter.split(' ')[1]
+ annotation = ""
+ if parameter.find(":") >= 0: # has annotation
+ assert inout == "" # only one parameter should be annotated
+ sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType))
+ inout = paramType.split(":")[2]
+ annotation = paramType.split(":")[1]
+ paramType = paramType.split(":")[0]
+ count = 1
+ countArg = ""
+ if annotation.find("*") >= 0: # [1,n] * param
+ count = int(annotation.split("*")[0])
+ countArg = annotation.split("*")[1]
+ assert countArg in paramNames
+ elif annotation in paramNames:
+ count = 1
+ countArg = annotation
+ elif annotation == "GLstring":
+ annotation = "strlen(%s)" % (paramName)
+ else:
+ count = int(annotation)
+
+ paramType += "*"
+ arguments += "reinterpret_cast<%s>(const_cast<char *>(cmd.data().data()))" % (paramType)
+ elif paramType == "GLboolean":
+ arguments += "GLboolean(cmd.arg%d())" % (paramIndex)
+ else:
+ arguments += "static_cast<%s>(cmd.arg%d())" % (paramType, paramIndex)
+
+ if paramIndex < len(parameters) - 1:
+ arguments += ", "
+ if len(arguments) - arguments.rfind("\n") > 60 :
+ arguments += "\n\
+ "
+ if const >= 0:
+ paramType = "const " + paramType
+ paramNames.append(paramName)
+ paramIndex += 1
+
+ if returnType == "void":
+ output += "\
+ dbg->hooks->gl.%s(\n\
+ %s);\n\
+ break;\n" % (functionName, arguments)
+ else:
+ output += "\
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.%s(\n\
+ %s)));\n\
+ if (cmd.has_ret())\n\
+ ret = reinterpret_cast<int *>(msg.ret());\n\
+ break;\n" % (functionName, arguments)
+ return output
+
+if __name__ == "__main__":
+
+ lines = open("gl2_api_annotated.in").readlines()
+ output = generate_caller(lines)
+
+ out = open("src/caller.cpp", "w")
+ out.write("""\
+/*
+ ** 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.
+ */
+
+// auto generated by generate_caller_cpp.py
+// implement declarations in caller.h
+
+#include "header.h"
+
+namespace android {
+
+""")
+
+ for extern in externs:
+ out.write("\
+static const int * GenerateCall_%s(DbgContext * const dbg,\n\
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);\n" % (extern))
+ print("\
+static const int * GenerateCall_%s(DbgContext * const dbg,\n\
+ const glesv2debugger::Message & cmd,\n\
+ glesv2debugger::Message & msg, const int * const prevRet)\n\
+{ assert(0); return prevRet; }\n" % (extern))
+
+ out.write(
+"""
+#include "caller.h"
+
+const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ LOGD("GenerateCall function=%u", cmd.function());
+ const int * ret = prevRet; // only some functions have return value
+ gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
+ nsecs_t c0 = systemTime(timeMode);
+ switch (cmd.function()) {""")
+
+ out.write(output)
+
+ out.write("""\
+ default:
+ assert(0);
+ }
+ msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+ msg.set_context_id(reinterpret_cast<int>(dbg));
+ msg.set_function(cmd.function());
+ msg.set_type(glesv2debugger::Message_Type_AfterCall);
+ return ret;
+}
+
+}; // name space android {
+""")
+
+
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 48a29da..466c447 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -118,12 +118,23 @@
optional int32 arg6 = 18;
optional int32 arg7 = 19;
optional int32 arg8 = 20;
+
optional bytes data = 10; // variable length data used for GL call
+ enum DataType
+ {
+ ReferencedImage = 0; // for image sourced from ReadPixels
+ NonreferencedImage = 1; // for image sourced from ReadPixels
+ };
+ optional DataType data_type = 23; // most data types can be inferred from function
+ optional int32 pixel_format = 24; // used for image data if format and type
+ optional int32 pixel_type = 25; // cannot be determined from arg
+
optional float time = 11; // duration of previous GL call (ms)
enum Prop
{
Capture = 0; // arg0 = true | false
TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
+ ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
};
optional Prop prop = 21; // used with SETPROP, value in arg0
optional float clock = 22; // wall clock in seconds
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
index 7094ca7..130ca7e 100644
--- a/opengl/libs/GLES2_dbg/src/api.cpp
+++ b/opengl/libs/GLES2_dbg/src/api.cpp
@@ -25,7 +25,6 @@
void Debug_glActiveTexture(GLenum texture)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum texture;
@@ -38,14 +37,12 @@
msg.set_arg0(texture);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glActiveTexture);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glActiveTexture);
}
void Debug_glAttachShader(GLuint program, GLuint shader)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLuint shader;
@@ -61,14 +58,12 @@
msg.set_arg0(program);
msg.set_arg1(shader);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glAttachShader);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glAttachShader);
}
void Debug_glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLuint index;
@@ -89,14 +84,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBindAttribLocation);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindAttribLocation);
}
void Debug_glBindBuffer(GLenum target, GLuint buffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLuint buffer;
@@ -113,14 +106,12 @@
msg.set_arg0(target);
msg.set_arg1(buffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBindBuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindBuffer);
}
void Debug_glBindFramebuffer(GLenum target, GLuint framebuffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLuint framebuffer;
@@ -136,14 +127,12 @@
msg.set_arg0(target);
msg.set_arg1(framebuffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBindFramebuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindFramebuffer);
}
void Debug_glBindRenderbuffer(GLenum target, GLuint renderbuffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLuint renderbuffer;
@@ -159,14 +148,12 @@
msg.set_arg0(target);
msg.set_arg1(renderbuffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBindRenderbuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindRenderbuffer);
}
void Debug_glBindTexture(GLenum target, GLuint texture)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLuint texture;
@@ -182,14 +169,12 @@
msg.set_arg0(target);
msg.set_arg1(texture);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBindTexture);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindTexture);
}
void Debug_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLclampf red;
GLclampf green;
@@ -211,14 +196,12 @@
msg.set_arg2(ToInt(blue));
msg.set_arg3(ToInt(alpha));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBlendColor);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendColor);
}
void Debug_glBlendEquation( GLenum mode )
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum mode;
@@ -231,14 +214,12 @@
msg.set_arg0(mode);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBlendEquation);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquation);
}
void Debug_glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum modeRGB;
GLenum modeAlpha;
@@ -254,14 +235,12 @@
msg.set_arg0(modeRGB);
msg.set_arg1(modeAlpha);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBlendEquationSeparate);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquationSeparate);
}
void Debug_glBlendFunc(GLenum sfactor, GLenum dfactor)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum sfactor;
GLenum dfactor;
@@ -277,14 +256,12 @@
msg.set_arg0(sfactor);
msg.set_arg1(dfactor);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBlendFunc);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFunc);
}
void Debug_glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum srcRGB;
GLenum dstRGB;
@@ -306,14 +283,12 @@
msg.set_arg2(srcAlpha);
msg.set_arg3(dstAlpha);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBlendFuncSeparate);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFuncSeparate);
}
void Debug_glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLsizeiptr size;
@@ -338,14 +313,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBufferData);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferData);
}
void Debug_glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLintptr offset;
@@ -370,14 +343,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glBufferSubData);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferSubData);
}
GLenum Debug_glCheckFramebufferStatus(GLenum target)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
@@ -391,15 +362,13 @@
msg.set_arg0(target);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCheckFramebufferStatus);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCheckFramebufferStatus);
return reinterpret_cast<GLenum>(ret);
}
void Debug_glClear(GLbitfield mask)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLbitfield mask;
@@ -412,14 +381,12 @@
msg.set_arg0(mask);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glClear);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClear);
}
void Debug_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLclampf red;
GLclampf green;
@@ -441,14 +408,12 @@
msg.set_arg2(ToInt(blue));
msg.set_arg3(ToInt(alpha));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glClearColor);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearColor);
}
void Debug_glClearDepthf(GLclampf depth)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLclampf depth;
@@ -461,14 +426,12 @@
msg.set_arg0(ToInt(depth));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glClearDepthf);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearDepthf);
}
void Debug_glClearStencil(GLint s)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint s;
@@ -481,14 +444,12 @@
msg.set_arg0(s);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glClearStencil);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearStencil);
}
void Debug_glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLboolean red;
GLboolean green;
@@ -510,14 +471,12 @@
msg.set_arg2(blue);
msg.set_arg3(alpha);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glColorMask);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glColorMask);
}
void Debug_glCompileShader(GLuint shader)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
@@ -530,15 +489,13 @@
msg.set_arg0(shader);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCompileShader);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompileShader);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLint level;
@@ -573,15 +530,13 @@
msg.set_arg7(ToInt(data));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCompressedTexImage2D);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexImage2D);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLint level;
@@ -619,14 +574,12 @@
msg.set_arg8(ToInt(data));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCompressedTexSubImage2D);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexSubImage2D);
}
void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLint level;
@@ -661,14 +614,12 @@
msg.set_arg7(border);
EXTEND_Debug_glCopyTexImage2D;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCopyTexImage2D);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);
}
void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLint level;
@@ -703,14 +654,12 @@
msg.set_arg7(height);
EXTEND_Debug_glCopyTexSubImage2D;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCopyTexSubImage2D);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);
}
GLuint Debug_glCreateProgram(void)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
@@ -721,15 +670,13 @@
} caller;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCreateProgram);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateProgram);
return reinterpret_cast<GLuint>(ret);
}
GLuint Debug_glCreateShader(GLenum type)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum type;
@@ -743,15 +690,13 @@
msg.set_arg0(type);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCreateShader);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateShader);
return reinterpret_cast<GLuint>(ret);
}
void Debug_glCullFace(GLenum mode)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum mode;
@@ -764,14 +709,12 @@
msg.set_arg0(mode);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glCullFace);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCullFace);
}
void Debug_glDeleteBuffers(GLsizei n, const GLuint* buffers)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
const GLuint* buffers;
@@ -790,14 +733,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDeleteBuffers);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteBuffers);
}
void Debug_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
const GLuint* framebuffers;
@@ -815,14 +756,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDeleteFramebuffers);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteFramebuffers);
}
void Debug_glDeleteProgram(GLuint program)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
@@ -835,14 +774,12 @@
msg.set_arg0(program);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDeleteProgram);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteProgram);
}
void Debug_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
const GLuint* renderbuffers;
@@ -860,14 +797,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDeleteRenderbuffers);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteRenderbuffers);
}
void Debug_glDeleteShader(GLuint shader)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
@@ -880,14 +815,12 @@
msg.set_arg0(shader);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDeleteShader);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteShader);
}
void Debug_glDeleteTextures(GLsizei n, const GLuint* textures)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
const GLuint* textures;
@@ -905,14 +838,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDeleteTextures);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteTextures);
}
void Debug_glDepthFunc(GLenum func)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum func;
@@ -925,14 +856,12 @@
msg.set_arg0(func);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDepthFunc);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthFunc);
}
void Debug_glDepthMask(GLboolean flag)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLboolean flag;
@@ -945,14 +874,12 @@
msg.set_arg0(flag);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDepthMask);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthMask);
}
void Debug_glDepthRangef(GLclampf zNear, GLclampf zFar)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLclampf zNear;
GLclampf zFar;
@@ -968,14 +895,12 @@
msg.set_arg0(ToInt(zNear));
msg.set_arg1(ToInt(zFar));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDepthRangef);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthRangef);
}
void Debug_glDetachShader(GLuint program, GLuint shader)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLuint shader;
@@ -991,14 +916,12 @@
msg.set_arg0(program);
msg.set_arg1(shader);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDetachShader);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDetachShader);
}
void Debug_glDisable(GLenum cap)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum cap;
@@ -1011,14 +934,12 @@
msg.set_arg0(cap);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDisable);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisable);
}
void Debug_glDisableVertexAttribArray(GLuint index)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint index;
@@ -1032,14 +953,12 @@
msg.set_arg0(index);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glDisableVertexAttribArray);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisableVertexAttribArray);
}
void Debug_glEnable(GLenum cap)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum cap;
@@ -1052,14 +971,12 @@
msg.set_arg0(cap);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glEnable);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnable);
}
void Debug_glEnableVertexAttribArray(GLuint index)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint index;
@@ -1073,14 +990,12 @@
msg.set_arg0(index);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glEnableVertexAttribArray);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnableVertexAttribArray);
}
void Debug_glFinish(void)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
@@ -1090,14 +1005,12 @@
} caller;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glFinish);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFinish);
}
void Debug_glFlush(void)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
@@ -1107,14 +1020,12 @@
} caller;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glFlush);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFlush);
}
void Debug_glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum attachment;
@@ -1136,14 +1047,12 @@
msg.set_arg2(renderbuffertarget);
msg.set_arg3(renderbuffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glFramebufferRenderbuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferRenderbuffer);
}
void Debug_glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum attachment;
@@ -1168,14 +1077,12 @@
msg.set_arg3(texture);
msg.set_arg4(level);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glFramebufferTexture2D);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferTexture2D);
}
void Debug_glFrontFace(GLenum mode)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum mode;
@@ -1188,14 +1095,12 @@
msg.set_arg0(mode);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glFrontFace);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFrontFace);
}
void Debug_glGenBuffers(GLsizei n, GLuint* buffers)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
GLuint* buffers;
@@ -1215,14 +1120,12 @@
msg.set_arg1(ToInt(buffers));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGenBuffers);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenBuffers);
}
void Debug_glGenerateMipmap(GLenum target)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
@@ -1235,14 +1138,12 @@
msg.set_arg0(target);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGenerateMipmap);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenerateMipmap);
}
void Debug_glGenFramebuffers(GLsizei n, GLuint* framebuffers)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
GLuint* framebuffers;
@@ -1262,14 +1163,12 @@
msg.set_arg1(ToInt(framebuffers));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGenFramebuffers);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenFramebuffers);
}
void Debug_glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
GLuint* renderbuffers;
@@ -1289,14 +1188,12 @@
msg.set_arg1(ToInt(renderbuffers));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGenRenderbuffers);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenRenderbuffers);
}
void Debug_glGenTextures(GLsizei n, GLuint* textures)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
GLuint* textures;
@@ -1316,15 +1213,13 @@
msg.set_arg1(ToInt(textures));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGenTextures);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenTextures);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLuint index;
@@ -1357,15 +1252,13 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetActiveAttrib);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveAttrib);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLuint index;
@@ -1398,15 +1291,13 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetActiveUniform);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveUniform);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLsizei maxcount;
@@ -1429,14 +1320,12 @@
msg.set_arg3(ToInt(shaders));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetAttachedShaders);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttachedShaders);
}
int Debug_glGetAttribLocation(GLuint program, const GLchar* name)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
const GLchar* name;
@@ -1455,8 +1344,7 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetAttribLocation);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttribLocation);
return reinterpret_cast<int>(ret);
}
@@ -1464,7 +1352,6 @@
void Debug_glGetBooleanv(GLenum pname, GLboolean* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum pname;
GLboolean* params;
@@ -1481,15 +1368,13 @@
msg.set_arg1(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetBooleanv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBooleanv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -1509,14 +1394,12 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetBufferParameteriv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBufferParameteriv);
}
GLenum Debug_glGetError(void)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
@@ -1527,8 +1410,7 @@
} caller;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetError);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetError);
return reinterpret_cast<GLenum>(ret);
}
@@ -1536,7 +1418,6 @@
void Debug_glGetFloatv(GLenum pname, GLfloat* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum pname;
GLfloat* params;
@@ -1553,15 +1434,13 @@
msg.set_arg1(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetFloatv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFloatv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum attachment;
@@ -1584,15 +1463,13 @@
msg.set_arg3(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetIntegerv(GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum pname;
GLint* params;
@@ -1609,14 +1486,12 @@
msg.set_arg1(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetIntegerv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetIntegerv);
}
void Debug_glGetProgramiv(GLuint program, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLenum pname;
@@ -1639,15 +1514,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetProgramiv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramiv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLsizei bufsize;
@@ -1673,15 +1546,13 @@
msg.set_arg3(ToInt(infolog));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetProgramInfoLog);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramInfoLog);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -1701,14 +1572,12 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetRenderbufferParameteriv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetRenderbufferParameteriv);
}
void Debug_glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
GLenum pname;
@@ -1731,15 +1600,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetShaderiv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderiv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
GLsizei bufsize;
@@ -1765,15 +1632,13 @@
msg.set_arg3(ToInt(infolog));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetShaderInfoLog);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderInfoLog);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum shadertype;
GLenum precisiontype;
@@ -1796,15 +1661,13 @@
msg.set_arg3(ToInt(precision));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetShaderPrecisionFormat);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderPrecisionFormat);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
GLsizei bufsize;
@@ -1830,15 +1693,13 @@
msg.set_arg3(ToInt(source));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetShaderSource);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderSource);
}
// FIXME: this function has pointers, it should be hand written
const GLubyte* Debug_glGetString(GLenum name)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum name;
@@ -1853,8 +1714,7 @@
msg.set_arg0(name);
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetString);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetString);
return reinterpret_cast<const GLubyte*>(ret);
}
@@ -1862,7 +1722,6 @@
void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -1882,15 +1741,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetTexParameterfv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameterfv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -1910,15 +1767,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetTexParameteriv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameteriv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLint location;
@@ -1938,15 +1793,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetUniformfv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformfv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
GLint location;
@@ -1966,14 +1819,12 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetUniformiv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformiv);
}
int Debug_glGetUniformLocation(GLuint program, const GLchar* name)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
const GLchar* name;
@@ -1992,8 +1843,7 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetUniformLocation);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformLocation);
return reinterpret_cast<int>(ret);
}
@@ -2001,7 +1851,6 @@
void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint index;
GLenum pname;
@@ -2021,15 +1870,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetVertexAttribfv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribfv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint index;
GLenum pname;
@@ -2049,15 +1896,13 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetVertexAttribiv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribiv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint index;
GLenum pname;
@@ -2077,14 +1922,12 @@
msg.set_arg2(ToInt(pointer));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glGetVertexAttribPointerv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribPointerv);
}
void Debug_glHint(GLenum target, GLenum mode)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum mode;
@@ -2100,14 +1943,12 @@
msg.set_arg0(target);
msg.set_arg1(mode);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glHint);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glHint);
}
GLboolean Debug_glIsBuffer(GLuint buffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint buffer;
@@ -2121,15 +1962,13 @@
msg.set_arg0(buffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsBuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsBuffer);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
GLboolean Debug_glIsEnabled(GLenum cap)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum cap;
@@ -2143,15 +1982,13 @@
msg.set_arg0(cap);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsEnabled);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsEnabled);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
GLboolean Debug_glIsFramebuffer(GLuint framebuffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint framebuffer;
@@ -2165,15 +2002,13 @@
msg.set_arg0(framebuffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsFramebuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsFramebuffer);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
GLboolean Debug_glIsProgram(GLuint program)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
@@ -2187,15 +2022,13 @@
msg.set_arg0(program);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsProgram);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsProgram);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
GLboolean Debug_glIsRenderbuffer(GLuint renderbuffer)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint renderbuffer;
@@ -2209,15 +2042,13 @@
msg.set_arg0(renderbuffer);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsRenderbuffer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsRenderbuffer);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
GLboolean Debug_glIsShader(GLuint shader)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
@@ -2231,15 +2062,13 @@
msg.set_arg0(shader);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsShader);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsShader);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
GLboolean Debug_glIsTexture(GLuint texture)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint texture;
@@ -2253,15 +2082,13 @@
msg.set_arg0(texture);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glIsTexture);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsTexture);
return static_cast<GLboolean>(reinterpret_cast<int>(ret));
}
void Debug_glLineWidth(GLfloat width)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLfloat width;
@@ -2274,14 +2101,12 @@
msg.set_arg0(ToInt(width));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glLineWidth);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLineWidth);
}
void Debug_glLinkProgram(GLuint program)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
@@ -2294,14 +2119,12 @@
msg.set_arg0(program);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glLinkProgram);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLinkProgram);
}
void Debug_glPixelStorei(GLenum pname, GLint param)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum pname;
GLint param;
@@ -2317,14 +2140,12 @@
msg.set_arg0(pname);
msg.set_arg1(param);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glPixelStorei);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPixelStorei);
}
void Debug_glPolygonOffset(GLfloat factor, GLfloat units)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLfloat factor;
GLfloat units;
@@ -2340,14 +2161,12 @@
msg.set_arg0(ToInt(factor));
msg.set_arg1(ToInt(units));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glPolygonOffset);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);
}
void Debug_glReleaseShaderCompiler(void)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
@@ -2357,14 +2176,12 @@
} caller;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glReleaseShaderCompiler);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReleaseShaderCompiler);
}
void Debug_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum internalformat;
@@ -2386,14 +2203,12 @@
msg.set_arg2(width);
msg.set_arg3(height);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glRenderbufferStorage);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glRenderbufferStorage);
}
void Debug_glSampleCoverage(GLclampf value, GLboolean invert)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLclampf value;
GLboolean invert;
@@ -2409,14 +2224,12 @@
msg.set_arg0(ToInt(value));
msg.set_arg1(invert);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glSampleCoverage);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glSampleCoverage);
}
void Debug_glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint x;
GLint y;
@@ -2438,15 +2251,13 @@
msg.set_arg2(width);
msg.set_arg3(height);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glScissor);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glScissor);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLsizei n;
const GLuint* shaders;
@@ -2472,14 +2283,12 @@
msg.set_arg4(length);
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glShaderBinary);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderBinary);
}
void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint shader;
GLsizei count;
@@ -2503,14 +2312,12 @@
// FIXME: check for pointer usage
EXTEND_Debug_glShaderSource;
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glShaderSource);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);
}
void Debug_glStencilFunc(GLenum func, GLint ref, GLuint mask)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum func;
GLint ref;
@@ -2529,14 +2336,12 @@
msg.set_arg1(ref);
msg.set_arg2(mask);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glStencilFunc);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFunc);
}
void Debug_glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum face;
GLenum func;
@@ -2558,14 +2363,12 @@
msg.set_arg2(ref);
msg.set_arg3(mask);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glStencilFuncSeparate);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFuncSeparate);
}
void Debug_glStencilMask(GLuint mask)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint mask;
@@ -2578,14 +2381,12 @@
msg.set_arg0(mask);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glStencilMask);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMask);
}
void Debug_glStencilMaskSeparate(GLenum face, GLuint mask)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum face;
GLuint mask;
@@ -2601,14 +2402,12 @@
msg.set_arg0(face);
msg.set_arg1(mask);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glStencilMaskSeparate);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMaskSeparate);
}
void Debug_glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum fail;
GLenum zfail;
@@ -2627,14 +2426,12 @@
msg.set_arg1(zfail);
msg.set_arg2(zpass);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glStencilOp);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOp);
}
void Debug_glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum face;
GLenum fail;
@@ -2656,14 +2453,56 @@
msg.set_arg2(zfail);
msg.set_arg3(zpass);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glStencilOpSeparate);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOpSeparate);
+}
+
+void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ glesv2debugger::Message msg;
+ struct : public FunctionCall {
+ GLenum target;
+ GLint level;
+ GLint internalformat;
+ GLsizei width;
+ GLsizei height;
+ GLint border;
+ GLenum format;
+ GLenum type;
+ const GLvoid* pixels;
+
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+ return 0;
+ }
+ } caller;
+ caller.target = target;
+ caller.level = level;
+ caller.internalformat = internalformat;
+ caller.width = width;
+ caller.height = height;
+ caller.border = border;
+ caller.format = format;
+ caller.type = type;
+ caller.pixels = pixels;
+
+ msg.set_arg0(target);
+ msg.set_arg1(level);
+ msg.set_arg2(internalformat);
+ msg.set_arg3(width);
+ msg.set_arg4(height);
+ msg.set_arg5(border);
+ msg.set_arg6(format);
+ msg.set_arg7(type);
+ msg.set_arg8(ToInt(pixels));
+
+ // FIXME: check for pointer usage
+ EXTEND_Debug_glTexImage2D;
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);
}
void Debug_glTexParameterf(GLenum target, GLenum pname, GLfloat param)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -2682,15 +2521,13 @@
msg.set_arg1(pname);
msg.set_arg2(ToInt(param));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glTexParameterf);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterf);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -2710,14 +2547,12 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glTexParameterfv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterfv);
}
void Debug_glTexParameteri(GLenum target, GLenum pname, GLint param)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -2736,15 +2571,13 @@
msg.set_arg1(pname);
msg.set_arg2(param);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glTexParameteri);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteri);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLenum target;
GLenum pname;
@@ -2764,14 +2597,56 @@
msg.set_arg2(ToInt(params));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glTexParameteriv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteriv);
+}
+
+void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ glesv2debugger::Message msg;
+ struct : public FunctionCall {
+ GLenum target;
+ GLint level;
+ GLint xoffset;
+ GLint yoffset;
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+ const GLvoid* pixels;
+
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+ return 0;
+ }
+ } caller;
+ caller.target = target;
+ caller.level = level;
+ caller.xoffset = xoffset;
+ caller.yoffset = yoffset;
+ caller.width = width;
+ caller.height = height;
+ caller.format = format;
+ caller.type = type;
+ caller.pixels = pixels;
+
+ msg.set_arg0(target);
+ msg.set_arg1(level);
+ msg.set_arg2(xoffset);
+ msg.set_arg3(yoffset);
+ msg.set_arg4(width);
+ msg.set_arg5(height);
+ msg.set_arg6(format);
+ msg.set_arg7(type);
+ msg.set_arg8(ToInt(pixels));
+
+ // FIXME: check for pointer usage
+ EXTEND_Debug_glTexSubImage2D;
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);
}
void Debug_glUniform1f(GLint location, GLfloat x)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLfloat x;
@@ -2787,14 +2662,12 @@
msg.set_arg0(location);
msg.set_arg1(ToInt(x));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform1f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1f);
}
void Debug_glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -2815,14 +2688,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform1fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1fv);
}
void Debug_glUniform1i(GLint location, GLint x)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLint x;
@@ -2838,14 +2709,12 @@
msg.set_arg0(location);
msg.set_arg1(x);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform1i);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1i);
}
void Debug_glUniform1iv(GLint location, GLsizei count, const GLint* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -2866,14 +2735,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform1iv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1iv);
}
void Debug_glUniform2f(GLint location, GLfloat x, GLfloat y)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLfloat x;
@@ -2892,14 +2759,12 @@
msg.set_arg1(ToInt(x));
msg.set_arg2(ToInt(y));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform2f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2f);
}
void Debug_glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -2920,14 +2785,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform2fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2fv);
}
void Debug_glUniform2i(GLint location, GLint x, GLint y)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLint x;
@@ -2946,14 +2809,12 @@
msg.set_arg1(x);
msg.set_arg2(y);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform2i);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2i);
}
void Debug_glUniform2iv(GLint location, GLsizei count, const GLint* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -2974,14 +2835,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform2iv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2iv);
}
void Debug_glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLfloat x;
@@ -3003,14 +2862,12 @@
msg.set_arg2(ToInt(y));
msg.set_arg3(ToInt(z));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform3f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3f);
}
void Debug_glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3031,14 +2888,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform3fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3fv);
}
void Debug_glUniform3i(GLint location, GLint x, GLint y, GLint z)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLint x;
@@ -3060,14 +2915,12 @@
msg.set_arg2(y);
msg.set_arg3(z);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform3i);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3i);
}
void Debug_glUniform3iv(GLint location, GLsizei count, const GLint* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3088,14 +2941,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform3iv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3iv);
}
void Debug_glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLfloat x;
@@ -3120,14 +2971,12 @@
msg.set_arg3(ToInt(z));
msg.set_arg4(ToInt(w));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform4f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4f);
}
void Debug_glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3148,14 +2997,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform4fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4fv);
}
void Debug_glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLint x;
@@ -3180,14 +3027,12 @@
msg.set_arg3(z);
msg.set_arg4(w);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform4i);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4i);
}
void Debug_glUniform4iv(GLint location, GLsizei count, const GLint* v)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3208,14 +3053,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniform4iv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4iv);
}
void Debug_glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3239,14 +3082,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 4*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniformMatrix2fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix2fv);
}
void Debug_glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3270,14 +3111,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 9*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniformMatrix3fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix3fv);
}
void Debug_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint location;
GLsizei count;
@@ -3301,14 +3140,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 16*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUniformMatrix4fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix4fv);
}
void Debug_glUseProgram(GLuint program)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
@@ -3322,14 +3159,12 @@
msg.set_arg0(program);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glUseProgram);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUseProgram);
}
void Debug_glValidateProgram(GLuint program)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint program;
@@ -3342,14 +3177,12 @@
msg.set_arg0(program);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glValidateProgram);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glValidateProgram);
}
void Debug_glVertexAttrib1f(GLuint indx, GLfloat x)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
GLfloat x;
@@ -3365,14 +3198,12 @@
msg.set_arg0(indx);
msg.set_arg1(ToInt(x));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib1f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1f);
}
void Debug_glVertexAttrib1fv(GLuint indx, const GLfloat* values)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
const GLfloat* values;
@@ -3390,14 +3221,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 1 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib1fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1fv);
}
void Debug_glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
GLfloat x;
@@ -3416,14 +3245,12 @@
msg.set_arg1(ToInt(x));
msg.set_arg2(ToInt(y));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib2f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2f);
}
void Debug_glVertexAttrib2fv(GLuint indx, const GLfloat* values)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
const GLfloat* values;
@@ -3441,14 +3268,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 2 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib2fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2fv);
}
void Debug_glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
GLfloat x;
@@ -3470,14 +3295,12 @@
msg.set_arg2(ToInt(y));
msg.set_arg3(ToInt(z));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib3f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3f);
}
void Debug_glVertexAttrib3fv(GLuint indx, const GLfloat* values)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
const GLfloat* values;
@@ -3495,14 +3318,12 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 3 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib3fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3fv);
}
void Debug_glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
GLfloat x;
@@ -3527,14 +3348,12 @@
msg.set_arg3(ToInt(z));
msg.set_arg4(ToInt(w));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib4f);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4f);
}
void Debug_glVertexAttrib4fv(GLuint indx, const GLfloat* values)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
const GLfloat* values;
@@ -3552,15 +3371,13 @@
// FIXME: check for pointer usage
msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 4 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttrib4fv);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4fv);
}
// FIXME: this function has pointers, it should be hand written
void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLuint indx;
GLint size;
@@ -3590,14 +3407,12 @@
msg.set_arg5(ToInt(ptr));
// FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glVertexAttribPointer);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttribPointer);
}
void Debug_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
GLint x;
GLint y;
@@ -3619,8 +3434,7 @@
msg.set_arg2(width);
msg.set_arg3(height);
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glViewport);
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glViewport);
}
// FIXME: the following functions should be written by hand
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
index be94dfc..b9fc341 100644
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -15,11 +15,18 @@
*/
#define EXTEND_Debug_glCopyTexImage2D \
- void * pixels = malloc(width * height * 4); \
- getGLTraceThreadSpecific()->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); \
- msg.set_data(pixels, width * height * 4); \
- free(pixels);
-
+ DbgContext * const dbg = getDbgContextThreadSpecific(); \
+ GLint readFormat, readType; \
+ dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); \
+ dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); \
+ unsigned readSize = GetBytesPerPixel(readFormat, readType) * width * height; \
+ void * readData = dbg->GetReadPixelsBuffer(readSize); \
+ dbg->hooks->gl.glReadPixels(x, y, width, height, readFormat, readType, readData); \
+ dbg->CompressReadPixelBuffer(msg.mutable_data()); \
+ msg.set_data_type(msg.ReferencedImage); \
+ msg.set_pixel_format(readFormat); \
+ msg.set_pixel_type(readType);
+
#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
#define EXTEND_Debug_glShaderSource \
@@ -28,4 +35,14 @@
if (!length || length[i] < 0) \
data->append(string[i]); \
else \
- data->append(string[i], length[i]);
\ No newline at end of file
+ data->append(string[i], length[i]);
+
+#define EXTEND_Debug_glTexImage2D \
+ if (pixels) { \
+ DbgContext * const dbg = getDbgContextThreadSpecific(); \
+ const unsigned size = GetBytesPerPixel(format, type) * width * height; \
+ assert(0 < size); \
+ dbg->Compress(pixels, size, msg.mutable_data()); \
+ }
+
+#define EXTEND_Debug_glTexSubImage2D EXTEND_Debug_glTexImage2D
diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp
new file mode 100644
index 0000000..9992f05
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/caller.cpp
@@ -0,0 +1,779 @@
+/*
+ ** 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.
+ */
+
+// auto generated by generate_caller_cpp.py
+// implement declarations in caller.h
+
+#include "header.h"
+
+namespace android {
+
+static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glDrawElements(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGenBuffers(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGenTextures(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetFloatv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetString(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glReadPixels(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glShaderBinary(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glShaderSource(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glTexImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
+
+#include "caller.h"
+
+const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ LOGD("GenerateCall function=%u", cmd.function());
+ const int * ret = prevRet; // only some functions have return value
+ gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
+ nsecs_t c0 = systemTime(timeMode);
+ switch (cmd.function()) { case glesv2debugger::Message_Function_glActiveTexture:
+ dbg->hooks->gl.glActiveTexture(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glAttachShader:
+ dbg->hooks->gl.glAttachShader(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBindAttribLocation:
+ dbg->hooks->gl.glBindAttribLocation(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()),
+ reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glBindBuffer:
+ dbg->hooks->gl.glBindBuffer(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBindFramebuffer:
+ dbg->hooks->gl.glBindFramebuffer(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBindRenderbuffer:
+ dbg->hooks->gl.glBindRenderbuffer(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBindTexture:
+ dbg->hooks->gl.glBindTexture(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBlendColor:
+ dbg->hooks->gl.glBlendColor(
+ static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()),
+ static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBlendEquation:
+ dbg->hooks->gl.glBlendEquation(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glBlendEquationSeparate:
+ dbg->hooks->gl.glBlendEquationSeparate(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBlendFunc:
+ dbg->hooks->gl.glBlendFunc(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBlendFuncSeparate:
+ dbg->hooks->gl.glBlendFuncSeparate(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glBufferData:
+ dbg->hooks->gl.glBufferData(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLsizeiptr>(cmd.arg1()),
+ reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data())),
+ static_cast<GLenum>(cmd.arg3()));
+ break;
+ case glesv2debugger::Message_Function_glBufferSubData:
+ dbg->hooks->gl.glBufferSubData(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLintptr>(cmd.arg1()),
+ static_cast<GLsizeiptr>(cmd.arg2()), reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glCheckFramebufferStatus:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glCheckFramebufferStatus(
+ static_cast<GLenum>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glClear:
+ dbg->hooks->gl.glClear(
+ static_cast<GLbitfield>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glClearColor:
+ dbg->hooks->gl.glClearColor(
+ static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()),
+ static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glClearDepthf:
+ dbg->hooks->gl.glClearDepthf(
+ static_cast<GLclampf>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glClearStencil:
+ dbg->hooks->gl.glClearStencil(
+ static_cast<GLint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glColorMask:
+ dbg->hooks->gl.glColorMask(
+ GLboolean(cmd.arg0()), GLboolean(cmd.arg1()), GLboolean(cmd.arg2()),
+ GLboolean(cmd.arg3()));
+ break;
+ case glesv2debugger::Message_Function_glCompileShader:
+ dbg->hooks->gl.glCompileShader(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glCompressedTexImage2D:
+ ret = GenerateCall_glCompressedTexImage2D(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glCompressedTexSubImage2D:
+ ret = GenerateCall_glCompressedTexSubImage2D(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glCopyTexImage2D:
+ dbg->hooks->gl.glCopyTexImage2D(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLenum>(cmd.arg2()), static_cast<GLint>(cmd.arg3()),
+ static_cast<GLint>(cmd.arg4()), static_cast<GLsizei>(cmd.arg5()),
+ static_cast<GLsizei>(cmd.arg6()), static_cast<GLint>(cmd.arg7())
+ );
+ break;
+ case glesv2debugger::Message_Function_glCopyTexSubImage2D:
+ dbg->hooks->gl.glCopyTexSubImage2D(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()),
+ static_cast<GLint>(cmd.arg4()), static_cast<GLint>(cmd.arg5()),
+ static_cast<GLsizei>(cmd.arg6()), static_cast<GLsizei>(cmd.arg7())
+ );
+ break;
+ case glesv2debugger::Message_Function_glCreateProgram:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateProgram(
+ )));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glCreateShader:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateShader(
+ static_cast<GLenum>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glCullFace:
+ dbg->hooks->gl.glCullFace(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDeleteBuffers:
+ dbg->hooks->gl.glDeleteBuffers(
+ static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glDeleteFramebuffers:
+ dbg->hooks->gl.glDeleteFramebuffers(
+ static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glDeleteProgram:
+ dbg->hooks->gl.glDeleteProgram(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDeleteRenderbuffers:
+ dbg->hooks->gl.glDeleteRenderbuffers(
+ static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glDeleteShader:
+ dbg->hooks->gl.glDeleteShader(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDeleteTextures:
+ dbg->hooks->gl.glDeleteTextures(
+ static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glDepthFunc:
+ dbg->hooks->gl.glDepthFunc(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDepthMask:
+ dbg->hooks->gl.glDepthMask(
+ GLboolean(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDepthRangef:
+ dbg->hooks->gl.glDepthRangef(
+ static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glDetachShader:
+ dbg->hooks->gl.glDetachShader(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glDisable:
+ dbg->hooks->gl.glDisable(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDisableVertexAttribArray:
+ dbg->hooks->gl.glDisableVertexAttribArray(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glDrawArrays:
+ dbg->hooks->gl.glDrawArrays(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLsizei>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glDrawElements:
+ ret = GenerateCall_glDrawElements(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glEnable:
+ dbg->hooks->gl.glEnable(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glEnableVertexAttribArray:
+ dbg->hooks->gl.glEnableVertexAttribArray(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glFinish:
+ dbg->hooks->gl.glFinish(
+ );
+ break;
+ case glesv2debugger::Message_Function_glFlush:
+ dbg->hooks->gl.glFlush(
+ );
+ break;
+ case glesv2debugger::Message_Function_glFramebufferRenderbuffer:
+ dbg->hooks->gl.glFramebufferRenderbuffer(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glFramebufferTexture2D:
+ dbg->hooks->gl.glFramebufferTexture2D(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3()),
+ static_cast<GLint>(cmd.arg4()));
+ break;
+ case glesv2debugger::Message_Function_glFrontFace:
+ dbg->hooks->gl.glFrontFace(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glGenBuffers:
+ ret = GenerateCall_glGenBuffers(dbg, cmd, msg, prevRet);
+ break; // annotated output pointers
+ case glesv2debugger::Message_Function_glGenerateMipmap:
+ dbg->hooks->gl.glGenerateMipmap(
+ static_cast<GLenum>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glGenFramebuffers:
+ ret = GenerateCall_glGenFramebuffers(dbg, cmd, msg, prevRet);
+ break; // annotated output pointers
+ case glesv2debugger::Message_Function_glGenRenderbuffers:
+ ret = GenerateCall_glGenRenderbuffers(dbg, cmd, msg, prevRet);
+ break; // annotated output pointers
+ case glesv2debugger::Message_Function_glGenTextures:
+ ret = GenerateCall_glGenTextures(dbg, cmd, msg, prevRet);
+ break; // annotated output pointers
+ case glesv2debugger::Message_Function_glGetActiveAttrib:
+ ret = GenerateCall_glGetActiveAttrib(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetActiveUniform:
+ ret = GenerateCall_glGetActiveUniform(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetAttachedShaders:
+ ret = GenerateCall_glGetAttachedShaders(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetAttribLocation:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetAttribLocation(
+ static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
+ )));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glGetBooleanv:
+ ret = GenerateCall_glGetBooleanv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetBufferParameteriv:
+ ret = GenerateCall_glGetBufferParameteriv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetError:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetError(
+ )));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glGetFloatv:
+ ret = GenerateCall_glGetFloatv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv:
+ ret = GenerateCall_glGetFramebufferAttachmentParameteriv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetIntegerv:
+ ret = GenerateCall_glGetIntegerv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetProgramiv:
+ ret = GenerateCall_glGetProgramiv(dbg, cmd, msg, prevRet);
+ break; // annotated output pointers
+ case glesv2debugger::Message_Function_glGetProgramInfoLog:
+ ret = GenerateCall_glGetProgramInfoLog(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetRenderbufferParameteriv:
+ ret = GenerateCall_glGetRenderbufferParameteriv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetShaderiv:
+ ret = GenerateCall_glGetShaderiv(dbg, cmd, msg, prevRet);
+ break; // annotated output pointers
+ case glesv2debugger::Message_Function_glGetShaderInfoLog:
+ ret = GenerateCall_glGetShaderInfoLog(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetShaderPrecisionFormat:
+ ret = GenerateCall_glGetShaderPrecisionFormat(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetShaderSource:
+ ret = GenerateCall_glGetShaderSource(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetString:
+ ret = GenerateCall_glGetString(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetTexParameterfv:
+ ret = GenerateCall_glGetTexParameterfv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetTexParameteriv:
+ ret = GenerateCall_glGetTexParameteriv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetUniformfv:
+ ret = GenerateCall_glGetUniformfv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetUniformiv:
+ ret = GenerateCall_glGetUniformiv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetUniformLocation:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetUniformLocation(
+ static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
+ )));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glGetVertexAttribfv:
+ ret = GenerateCall_glGetVertexAttribfv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetVertexAttribiv:
+ ret = GenerateCall_glGetVertexAttribiv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glGetVertexAttribPointerv:
+ ret = GenerateCall_glGetVertexAttribPointerv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glHint:
+ dbg->hooks->gl.glHint(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glIsBuffer:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsBuffer(
+ static_cast<GLuint>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glIsEnabled:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsEnabled(
+ static_cast<GLenum>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glIsFramebuffer:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsFramebuffer(
+ static_cast<GLuint>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glIsProgram:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsProgram(
+ static_cast<GLuint>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glIsRenderbuffer:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsRenderbuffer(
+ static_cast<GLuint>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glIsShader:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsShader(
+ static_cast<GLuint>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glIsTexture:
+ msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsTexture(
+ static_cast<GLuint>(cmd.arg0()))));
+ if (cmd.has_ret())
+ ret = reinterpret_cast<int *>(msg.ret());
+ break;
+ case glesv2debugger::Message_Function_glLineWidth:
+ dbg->hooks->gl.glLineWidth(
+ static_cast<GLfloat>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glLinkProgram:
+ dbg->hooks->gl.glLinkProgram(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glPixelStorei:
+ dbg->hooks->gl.glPixelStorei(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glPolygonOffset:
+ dbg->hooks->gl.glPolygonOffset(
+ static_cast<GLfloat>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glReadPixels:
+ ret = GenerateCall_glReadPixels(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glReleaseShaderCompiler:
+ dbg->hooks->gl.glReleaseShaderCompiler(
+ );
+ break;
+ case glesv2debugger::Message_Function_glRenderbufferStorage:
+ dbg->hooks->gl.glRenderbufferStorage(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glSampleCoverage:
+ dbg->hooks->gl.glSampleCoverage(
+ static_cast<GLclampf>(cmd.arg0()), GLboolean(cmd.arg1()));
+ break;
+ case glesv2debugger::Message_Function_glScissor:
+ dbg->hooks->gl.glScissor(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glShaderBinary:
+ ret = GenerateCall_glShaderBinary(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glShaderSource:
+ ret = GenerateCall_glShaderSource(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glStencilFunc:
+ dbg->hooks->gl.glStencilFunc(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLuint>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glStencilFuncSeparate:
+ dbg->hooks->gl.glStencilFuncSeparate(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLint>(cmd.arg2()), static_cast<GLuint>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glStencilMask:
+ dbg->hooks->gl.glStencilMask(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glStencilMaskSeparate:
+ dbg->hooks->gl.glStencilMaskSeparate(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glStencilOp:
+ dbg->hooks->gl.glStencilOp(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLenum>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glStencilOpSeparate:
+ dbg->hooks->gl.glStencilOpSeparate(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glTexImage2D:
+ ret = GenerateCall_glTexImage2D(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glTexParameterf:
+ dbg->hooks->gl.glTexParameterf(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glTexParameterfv:
+ ret = GenerateCall_glTexParameterfv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glTexParameteri:
+ dbg->hooks->gl.glTexParameteri(
+ static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
+ static_cast<GLint>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glTexParameteriv:
+ ret = GenerateCall_glTexParameteriv(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glTexSubImage2D:
+ ret = GenerateCall_glTexSubImage2D(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glUniform1f:
+ dbg->hooks->gl.glUniform1f(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform1fv:
+ dbg->hooks->gl.glUniform1fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform1i:
+ dbg->hooks->gl.glUniform1i(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform1iv:
+ dbg->hooks->gl.glUniform1iv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform2f:
+ dbg->hooks->gl.glUniform2f(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glUniform2fv:
+ dbg->hooks->gl.glUniform2fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform2i:
+ dbg->hooks->gl.glUniform2i(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLint>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glUniform2iv:
+ dbg->hooks->gl.glUniform2iv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform3f:
+ dbg->hooks->gl.glUniform3f(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform3fv:
+ dbg->hooks->gl.glUniform3fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform3i:
+ dbg->hooks->gl.glUniform3i(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform3iv:
+ dbg->hooks->gl.glUniform3iv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform4f:
+ dbg->hooks->gl.glUniform4f(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()),
+ static_cast<GLfloat>(cmd.arg4()));
+ break;
+ case glesv2debugger::Message_Function_glUniform4fv:
+ dbg->hooks->gl.glUniform4fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniform4i:
+ dbg->hooks->gl.glUniform4i(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()),
+ static_cast<GLint>(cmd.arg4()));
+ break;
+ case glesv2debugger::Message_Function_glUniform4iv:
+ dbg->hooks->gl.glUniform4iv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniformMatrix2fv:
+ dbg->hooks->gl.glUniformMatrix2fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniformMatrix3fv:
+ dbg->hooks->gl.glUniformMatrix3fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUniformMatrix4fv:
+ dbg->hooks->gl.glUniformMatrix4fv(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
+ GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glUseProgram:
+ dbg->hooks->gl.glUseProgram(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glValidateProgram:
+ dbg->hooks->gl.glValidateProgram(
+ static_cast<GLuint>(cmd.arg0()));
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib1f:
+ dbg->hooks->gl.glVertexAttrib1f(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
+ );
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib1fv:
+ dbg->hooks->gl.glVertexAttrib1fv(
+ static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib2f:
+ dbg->hooks->gl.glVertexAttrib2f(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()));
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib2fv:
+ dbg->hooks->gl.glVertexAttrib2fv(
+ static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib3f:
+ dbg->hooks->gl.glVertexAttrib3f(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3())
+ );
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib3fv:
+ dbg->hooks->gl.glVertexAttrib3fv(
+ static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib4f:
+ dbg->hooks->gl.glVertexAttrib4f(
+ static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
+ static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()),
+ static_cast<GLfloat>(cmd.arg4()));
+ break;
+ case glesv2debugger::Message_Function_glVertexAttrib4fv:
+ dbg->hooks->gl.glVertexAttrib4fv(
+ static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
+ );
+ break;
+ case glesv2debugger::Message_Function_glVertexAttribPointer:
+ ret = GenerateCall_glVertexAttribPointer(dbg, cmd, msg, prevRet);
+ break;
+ case glesv2debugger::Message_Function_glViewport:
+ dbg->hooks->gl.glViewport(
+ static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
+ static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
+ );
+ break;
+ default:
+ assert(0);
+ }
+ msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+ msg.set_context_id(reinterpret_cast<int>(dbg));
+ msg.set_function(cmd.function());
+ msg.set_type(glesv2debugger::Message_Type_AfterCall);
+ return ret;
+}
+
+}; // name space android {
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
index 01bc4ea..5447757 100644
--- a/opengl/libs/GLES2_dbg/src/caller.h
+++ b/opengl/libs/GLES2_dbg/src/caller.h
@@ -1,7 +1,7 @@
/*
** Copyright 2011, The Android Open Source Project
**
- ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** 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
**
@@ -14,6 +14,307 @@
** limitations under the License.
*/
-#include "src/header.h"
+static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+static const int * GenerateCall_glDrawElements(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGenBuffers(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGenTextures(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetFloatv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetString(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glReadPixels(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glShaderBinary(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glShaderSource(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ const char * string = cmd.data().data();
+ dbg->hooks->gl.glShaderSource(cmd.arg0(), 1, &string, NULL);
+ return prevRet;
+}
+
+static const int * GenerateCall_glTexImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
+
+static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg,
+ const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet)
+{
+ assert(0);
+ return prevRet;
+}
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index 5c418258..cc7336c 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -13,26 +13,38 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-
+
#include "header.h"
+extern "C"
+{
+#include "liblzf/lzf.h"
+}
+
namespace android
{
DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
const unsigned MAX_VERTEX_ATTRIBS)
- : version(version), hooks(hooks)
+ : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
+ , version(version), hooks(hooks)
, MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
, vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
, hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
+ , program(0), maxAttrib(0)
{
+ lzf_ref[0] = lzf_ref[1] = NULL;
for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
vertexAttribs[i] = VertexAttrib();
+ memset(&expectResponse, 0, sizeof(expectResponse));
}
DbgContext::~DbgContext()
{
delete vertexAttribs;
+ free(lzf_buf);
+ free(lzf_ref[0]);
+ free(lzf_ref[1]);
}
DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
@@ -49,6 +61,39 @@
delete dbg;
}
+unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
+{
+ switch (type) {
+ case GL_UNSIGNED_SHORT_5_6_5:
+ return 2;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ return 2;
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ return 2;
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ assert(0);
+ }
+
+ switch (format) {
+ case GL_ALPHA:
+ return 1;
+ case GL_LUMINANCE:
+ return 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ return 2;
+ case GL_RGB:
+ return 3;
+ case GL_RGBA:
+ return 4;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
void DbgContext::Fetch(const unsigned index, std::string * const data) const
{
// VBO data is already on client, just send user pointer data
@@ -63,11 +108,61 @@
}
}
+void DbgContext::Compress(const void * in_data, unsigned int in_len,
+ std::string * const outStr)
+{
+ if (!lzf_buf)
+ lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ const uint32_t totalDecompSize = in_len;
+ outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
+ for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
+ uint32_t chunkSize = LZF_CHUNK_SIZE;
+ if (i + LZF_CHUNK_SIZE > in_len)
+ chunkSize = in_len - i;
+ const uint32_t compSize = lzf_compress((const char *)in_data + i, chunkSize,
+ lzf_buf, LZF_CHUNK_SIZE);
+ outStr->append((const char *)&chunkSize, sizeof(chunkSize));
+ outStr->append((const char *)&compSize, sizeof(compSize));
+ if (compSize > 0)
+ outStr->append(lzf_buf, compSize);
+ else // compressed chunk bigger than LZF_CHUNK_SIZE (and uncompressed)
+ outStr->append((const char *)in_data + i, chunkSize);
+ }
+}
+
+void * DbgContext::GetReadPixelsBuffer(const unsigned size)
+{
+ if (lzf_refBufSize < size + 8) {
+ lzf_refBufSize = size + 8;
+ lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
+ memset(lzf_ref[0], 0, lzf_refBufSize);
+ lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
+ memset(lzf_ref[1], 0, lzf_refBufSize);
+ }
+ if (lzf_refSize != size) // need to clear unused ref to maintain consistency
+ { // since ref and src are swapped each time
+ memset((char *)lzf_ref[0] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
+ memset((char *)lzf_ref[1] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
+ }
+ lzf_refSize = size;
+ lzf_readIndex ^= 1;
+ return lzf_ref[lzf_readIndex];
+}
+
+void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
+{
+ unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
+ unsigned * const src = lzf_ref[lzf_readIndex];
+ for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
+ ref[i] ^= src[i];
+ Compress(ref, lzf_refSize, outStr);
+}
+
void DbgContext::glUseProgram(GLuint program)
{
while (GLenum error = hooks->gl.glGetError())
LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
-
+
this->program = program;
GLint activeAttributes = 0;
@@ -107,7 +202,7 @@
maxAttrib = slot;
}
delete name;
-
+
while (GLenum error = hooks->gl.glGetError())
LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
}
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 1f404c2..046c954 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -450,7 +450,7 @@
const Message_Type Message::Type_MAX;
const int Message::Type_ARRAYSIZE;
#endif // _MSC_VER
-bool Message_Prop_IsValid(int value) {
+bool Message_DataType_IsValid(int value) {
switch(value) {
case 0:
case 1:
@@ -461,8 +461,27 @@
}
#ifndef _MSC_VER
+const Message_DataType Message::ReferencedImage;
+const Message_DataType Message::NonreferencedImage;
+const Message_DataType Message::DataType_MIN;
+const Message_DataType Message::DataType_MAX;
+const int Message::DataType_ARRAYSIZE;
+#endif // _MSC_VER
+bool Message_Prop_IsValid(int value) {
+ switch(value) {
+ case 0:
+ case 1:
+ case 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
const Message_Prop Message::Capture;
const Message_Prop Message::TimeMode;
+const Message_Prop Message::ExpectResponse;
const Message_Prop Message::Prop_MIN;
const Message_Prop Message::Prop_MAX;
const int Message::Prop_ARRAYSIZE;
@@ -484,6 +503,9 @@
const int Message::kArg7FieldNumber;
const int Message::kArg8FieldNumber;
const int Message::kDataFieldNumber;
+const int Message::kDataTypeFieldNumber;
+const int Message::kPixelFormatFieldNumber;
+const int Message::kPixelTypeFieldNumber;
const int Message::kTimeFieldNumber;
const int Message::kPropFieldNumber;
const int Message::kClockFieldNumber;
@@ -520,6 +542,9 @@
arg7_ = 0;
arg8_ = 0;
data_ = const_cast< ::std::string*>(&_default_data_);
+ data_type_ = 0;
+ pixel_format_ = 0;
+ pixel_type_ = 0;
time_ = 0;
prop_ = 0;
clock_ = 0;
@@ -576,9 +601,12 @@
data_->clear();
}
}
- time_ = 0;
+ data_type_ = 0;
}
if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+ pixel_format_ = 0;
+ pixel_type_ = 0;
+ time_ = 0;
prop_ = 0;
clock_ = 0;
}
@@ -762,7 +790,7 @@
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &time_)));
- _set_bit(15);
+ _set_bit(18);
} else {
goto handle_uninterpreted;
}
@@ -877,6 +905,57 @@
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &clock_)));
+ _set_bit(20);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(184)) goto parse_data_type;
+ break;
+ }
+
+ // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+ case 23: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_data_type:
+ int value;
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+ input, &value)));
+ if (::com::android::glesv2debugger::Message_DataType_IsValid(value)) {
+ set_data_type(static_cast< ::com::android::glesv2debugger::Message_DataType >(value));
+ }
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(192)) goto parse_pixel_format;
+ break;
+ }
+
+ // optional int32 pixel_format = 24;
+ case 24: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_pixel_format:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &pixel_format_)));
+ _set_bit(16);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(200)) goto parse_pixel_type;
+ break;
+ }
+
+ // optional int32 pixel_type = 25;
+ case 25: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_pixel_type:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &pixel_type_)));
_set_bit(17);
} else {
goto handle_uninterpreted;
@@ -956,7 +1035,7 @@
}
// optional float time = 11;
- if (_has_bit(15)) {
+ if (_has_bit(18)) {
::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
}
@@ -986,16 +1065,32 @@
}
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
- if (_has_bit(16)) {
+ if (_has_bit(19)) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
21, this->prop(), output);
}
// optional float clock = 22;
- if (_has_bit(17)) {
+ if (_has_bit(20)) {
::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
}
+ // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+ if (_has_bit(15)) {
+ ::google::protobuf::internal::WireFormatLite::WriteEnum(
+ 23, this->data_type(), output);
+ }
+
+ // optional int32 pixel_format = 24;
+ if (_has_bit(16)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(24, this->pixel_format(), output);
+ }
+
+ // optional int32 pixel_type = 25;
+ if (_has_bit(17)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
+ }
+
}
int Message::ByteSize() const {
@@ -1105,13 +1200,33 @@
this->data());
}
+ // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+ if (has_data_type()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::EnumSize(this->data_type());
+ }
+
+ }
+ if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+ // optional int32 pixel_format = 24;
+ if (has_pixel_format()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->pixel_format());
+ }
+
+ // optional int32 pixel_type = 25;
+ if (has_pixel_type()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->pixel_type());
+ }
+
// optional float time = 11;
if (has_time()) {
total_size += 1 + 4;
}
- }
- if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
if (has_prop()) {
total_size += 2 +
@@ -1186,14 +1301,23 @@
set_data(from.data());
}
if (from._has_bit(15)) {
- set_time(from.time());
+ set_data_type(from.data_type());
}
}
if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
if (from._has_bit(16)) {
- set_prop(from.prop());
+ set_pixel_format(from.pixel_format());
}
if (from._has_bit(17)) {
+ set_pixel_type(from.pixel_type());
+ }
+ if (from._has_bit(18)) {
+ set_time(from.time());
+ }
+ if (from._has_bit(19)) {
+ set_prop(from.prop());
+ }
+ if (from._has_bit(20)) {
set_clock(from.clock());
}
}
@@ -1228,6 +1352,9 @@
std::swap(arg7_, other->arg7_);
std::swap(arg8_, other->arg8_);
std::swap(data_, other->data_);
+ std::swap(data_type_, other->data_type_);
+ std::swap(pixel_format_, other->pixel_format_);
+ std::swap(pixel_type_, other->pixel_type_);
std::swap(time_, other->time_);
std::swap(prop_, other->prop_);
std::swap(clock_, other->clock_);
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index 59e7bab..b2ec5a0 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -243,13 +243,23 @@
const Message_Type Message_Type_Type_MAX = Message_Type_Response;
const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
+enum Message_DataType {
+ Message_DataType_ReferencedImage = 0,
+ Message_DataType_NonreferencedImage = 1
+};
+bool Message_DataType_IsValid(int value);
+const Message_DataType Message_DataType_DataType_MIN = Message_DataType_ReferencedImage;
+const Message_DataType Message_DataType_DataType_MAX = Message_DataType_NonreferencedImage;
+const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
+
enum Message_Prop {
Message_Prop_Capture = 0,
- Message_Prop_TimeMode = 1
+ Message_Prop_TimeMode = 1,
+ Message_Prop_ExpectResponse = 2
};
bool Message_Prop_IsValid(int value);
const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_TimeMode;
+const Message_Prop Message_Prop_Prop_MAX = Message_Prop_ExpectResponse;
const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
// ===================================================================
@@ -511,9 +521,23 @@
static const int Type_ARRAYSIZE =
Message_Type_Type_ARRAYSIZE;
+ typedef Message_DataType DataType;
+ static const DataType ReferencedImage = Message_DataType_ReferencedImage;
+ static const DataType NonreferencedImage = Message_DataType_NonreferencedImage;
+ static inline bool DataType_IsValid(int value) {
+ return Message_DataType_IsValid(value);
+ }
+ static const DataType DataType_MIN =
+ Message_DataType_DataType_MIN;
+ static const DataType DataType_MAX =
+ Message_DataType_DataType_MAX;
+ static const int DataType_ARRAYSIZE =
+ Message_DataType_DataType_ARRAYSIZE;
+
typedef Message_Prop Prop;
static const Prop Capture = Message_Prop_Capture;
static const Prop TimeMode = Message_Prop_TimeMode;
+ static const Prop ExpectResponse = Message_Prop_ExpectResponse;
static inline bool Prop_IsValid(int value) {
return Message_Prop_IsValid(value);
}
@@ -634,6 +658,27 @@
inline void set_data(const void* value, size_t size);
inline ::std::string* mutable_data();
+ // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+ inline bool has_data_type() const;
+ inline void clear_data_type();
+ static const int kDataTypeFieldNumber = 23;
+ inline ::com::android::glesv2debugger::Message_DataType data_type() const;
+ inline void set_data_type(::com::android::glesv2debugger::Message_DataType value);
+
+ // optional int32 pixel_format = 24;
+ inline bool has_pixel_format() const;
+ inline void clear_pixel_format();
+ static const int kPixelFormatFieldNumber = 24;
+ inline ::google::protobuf::int32 pixel_format() const;
+ inline void set_pixel_format(::google::protobuf::int32 value);
+
+ // optional int32 pixel_type = 25;
+ inline bool has_pixel_type() const;
+ inline void clear_pixel_type();
+ static const int kPixelTypeFieldNumber = 25;
+ inline ::google::protobuf::int32 pixel_type() const;
+ inline void set_pixel_type(::google::protobuf::int32 value);
+
// optional float time = 11;
inline bool has_time() const;
inline void clear_time();
@@ -675,6 +720,9 @@
::google::protobuf::int32 arg8_;
::std::string* data_;
static const ::std::string _default_data_;
+ int data_type_;
+ ::google::protobuf::int32 pixel_format_;
+ ::google::protobuf::int32 pixel_type_;
float time_;
int prop_;
float clock_;
@@ -682,7 +730,7 @@
friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
- ::google::protobuf::uint32 _has_bits_[(18 + 31) / 32];
+ ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
inline bool _has_bit(int index) const {
@@ -973,52 +1021,101 @@
return data_;
}
+// optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+inline bool Message::has_data_type() const {
+ return _has_bit(15);
+}
+inline void Message::clear_data_type() {
+ data_type_ = 0;
+ _clear_bit(15);
+}
+inline ::com::android::glesv2debugger::Message_DataType Message::data_type() const {
+ return static_cast< ::com::android::glesv2debugger::Message_DataType >(data_type_);
+}
+inline void Message::set_data_type(::com::android::glesv2debugger::Message_DataType value) {
+ GOOGLE_DCHECK(::com::android::glesv2debugger::Message_DataType_IsValid(value));
+ _set_bit(15);
+ data_type_ = value;
+}
+
+// optional int32 pixel_format = 24;
+inline bool Message::has_pixel_format() const {
+ return _has_bit(16);
+}
+inline void Message::clear_pixel_format() {
+ pixel_format_ = 0;
+ _clear_bit(16);
+}
+inline ::google::protobuf::int32 Message::pixel_format() const {
+ return pixel_format_;
+}
+inline void Message::set_pixel_format(::google::protobuf::int32 value) {
+ _set_bit(16);
+ pixel_format_ = value;
+}
+
+// optional int32 pixel_type = 25;
+inline bool Message::has_pixel_type() const {
+ return _has_bit(17);
+}
+inline void Message::clear_pixel_type() {
+ pixel_type_ = 0;
+ _clear_bit(17);
+}
+inline ::google::protobuf::int32 Message::pixel_type() const {
+ return pixel_type_;
+}
+inline void Message::set_pixel_type(::google::protobuf::int32 value) {
+ _set_bit(17);
+ pixel_type_ = value;
+}
+
// optional float time = 11;
inline bool Message::has_time() const {
- return _has_bit(15);
+ return _has_bit(18);
}
inline void Message::clear_time() {
time_ = 0;
- _clear_bit(15);
+ _clear_bit(18);
}
inline float Message::time() const {
return time_;
}
inline void Message::set_time(float value) {
- _set_bit(15);
+ _set_bit(18);
time_ = value;
}
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
inline bool Message::has_prop() const {
- return _has_bit(16);
+ return _has_bit(19);
}
inline void Message::clear_prop() {
prop_ = 0;
- _clear_bit(16);
+ _clear_bit(19);
}
inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
}
inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
- _set_bit(16);
+ _set_bit(19);
prop_ = value;
}
// optional float clock = 22;
inline bool Message::has_clock() const {
- return _has_bit(17);
+ return _has_bit(20);
}
inline void Message::clear_clock() {
clock_ = 0;
- _clear_bit(17);
+ _clear_bit(20);
}
inline float Message::clock() const {
return clock_;
}
inline void Message::set_clock(float value) {
- _set_bit(17);
+ _set_bit(20);
clock_ = value;
}
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
index 27c7f7e..3a20e21 100644
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -19,11 +19,10 @@
EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
glesv2debugger::Message msg;
- const bool expectResponse = false;
struct : public FunctionCall {
EGLDisplay dpy;
EGLSurface draw;
-
+
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
msg.set_time(-1);
return reinterpret_cast<const int *>(true);
@@ -31,11 +30,10 @@
} caller;
caller.dpy = dpy;
caller.draw = draw;
-
+
msg.set_arg0(reinterpret_cast<int>(dpy));
msg.set_arg1(reinterpret_cast<int>(draw));
-
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_eglSwapBuffers);
+
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);
return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
}
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index b79cc0f..9218da5 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -56,11 +56,40 @@
namespace android
{
+struct GLFunctionBitfield {
+ unsigned char field [24]; // 8 * 24 = 192
+
+ void Bit(const glesv2debugger::Message_Function function, bool bit) {
+ const unsigned byte = function / 8, mask = 1 << (function % 8);
+ if (bit)
+ field[byte] |= mask;
+ else
+ field[byte] &= ~mask;
+ }
+
+ bool Bit(const glesv2debugger::Message_Function function) const {
+ const unsigned byte = function / 8, mask = 1 << (function % 8);
+ return field[byte] & mask;
+ }
+};
+
struct DbgContext {
+private:
+ static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
+ char * lzf_buf; // malloc / free; for lzf chunk compression
+
+ // used as buffer and reference frame for ReadPixels; malloc/free
+ unsigned * lzf_ref [2];
+ unsigned lzf_readIndex; // 0 or 1
+ unsigned lzf_refSize, lzf_refBufSize; // bytes
+
+public:
const unsigned version; // 0 is GLES1, 1 is GLES2
const gl_hooks_t * const hooks;
const unsigned MAX_VERTEX_ATTRIBS;
-
+
+ GLFunctionBitfield expectResponse;
+
struct VertexAttrib {
GLenum type; // element data type
unsigned size; // number of data per element
@@ -89,15 +118,23 @@
GLuint program;
unsigned maxAttrib; // number of slots used by program
- DbgContext(const unsigned version, const gl_hooks_t * const hooks, const unsigned MAX_VERTEX_ATTRIBS);
+ DbgContext(const unsigned version, const gl_hooks_t * const hooks,
+ const unsigned MAX_VERTEX_ATTRIBS);
~DbgContext();
void Fetch(const unsigned index, std::string * const data) const;
+ void Compress(const void * in_data, unsigned in_len, std::string * const outStr);
+ void * GetReadPixelsBuffer(const unsigned size);
+ bool IsReadPixelBuffer(const void * const ptr) {
+ return ptr == lzf_ref[lzf_readIndex];
+ }
+ void CompressReadPixelBuffer(std::string * const outStr);
void glUseProgram(GLuint program);
void glEnableVertexAttribArray(GLuint index);
void glDisableVertexAttribArray(GLuint index);
- void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+ void glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
+ GLboolean normalized, GLsizei stride, const GLvoid* ptr);
void glBindBuffer(GLenum target, GLuint buffer);
void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
@@ -109,7 +146,8 @@
#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific();
struct FunctionCall {
- virtual const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) = 0;
+ virtual const int * operator()(gl_hooks_t::gl_t const * const _c,
+ glesv2debugger::Message & msg) = 0;
virtual ~FunctionCall() {}
};
@@ -123,9 +161,11 @@
// every Debug_gl* function calls this to send message to client and possibly receive commands
int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
- const bool expectResponse, const glesv2debugger::Message_Function function);
+ const glesv2debugger::Message_Function function);
void Receive(glesv2debugger::Message & cmd);
float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd);
-void SetProp(const glesv2debugger::Message & cmd);
+void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd);
+const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
+ glesv2debugger::Message & msg, const int * const prevRet);
}; // namespace android {
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index 03c3dae..7039c84 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -153,10 +153,9 @@
assert(msg.has_context_id() && msg.context_id() != 0);
static std::string str;
msg.SerializeToString(&str);
- unsigned len = str.length();
- len = htonl(len);
+ uint32_t len = htonl(str.length());
int sent = -1;
- sent = send(clientSock, (const char *)&len, sizeof(len), 0);
+ sent = send(clientSock, &len, sizeof(len), 0);
if (sent != sizeof(len)) {
LOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock);
Die("Failed to send message length");
@@ -182,12 +181,11 @@
} else
Receive(cmd);
- //LOGD("Message sent tid=%lu len=%d", pthread_self(), str.length());
pthread_mutex_unlock(&mutex);
return t;
}
-void SetProp(const glesv2debugger::Message & cmd)
+void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
{
switch (cmd.prop()) {
case glesv2debugger::Message_Prop_Capture:
@@ -198,19 +196,24 @@
LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
timeMode = cmd.arg0();
break;
+ case glesv2debugger::Message_Prop_ExpectResponse:
+ LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
+ dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
+ break;
default:
assert(0);
}
}
int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
- const bool expectResponse, const glesv2debugger::Message_Function function)
+ const glesv2debugger::Message_Function function)
{
DbgContext * const dbg = getDbgContextThreadSpecific();
const int * ret = 0;
glesv2debugger::Message cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
+ const bool expectResponse = dbg->expectResponse.Bit(function);
msg.set_expect_response(expectResponse);
msg.set_function(function);
if (!expectResponse)
@@ -237,11 +240,15 @@
case glesv2debugger::Message_Function_SKIP:
return const_cast<int *>(ret);
case glesv2debugger::Message_Function_SETPROP:
- SetProp(cmd);
+ SetProp(dbg, cmd);
Receive(cmd);
break;
default:
- assert(0); //GenerateCall(msg, cmd);
+ ret = GenerateCall(dbg, cmd, msg, ret);
+ msg.set_expect_response(expectResponse);
+ if (!expectResponse)
+ cmd.set_function(cmd.SKIP);
+ Send(msg, cmd);
break;
}
}
diff --git a/opengl/libs/GLES2_dbg/src/texture.cpp b/opengl/libs/GLES2_dbg/src/texture.cpp
deleted file mode 100644
index 3aa0aab..0000000
--- a/opengl/libs/GLES2_dbg/src/texture.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- ** 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.
- */
-
-#include "header.h"
-
-namespace android
-{
-unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
-{
- switch (type) {
- case GL_UNSIGNED_SHORT_5_6_5:
- return 2;
- case GL_UNSIGNED_SHORT_4_4_4_4:
- return 2;
- case GL_UNSIGNED_SHORT_5_5_5_1:
- return 2;
- case GL_UNSIGNED_BYTE:
- break;
- default:
- assert(0);
- }
-
- switch (format) {
- case GL_ALPHA:
- return 1;
- case GL_LUMINANCE:
- return 1;
- break;
- case GL_LUMINANCE_ALPHA:
- return 2;
- case GL_RGB:
- return 3;
- case GL_RGBA:
- return 4;
- default:
- assert(0);
- return 0;
- }
-}
-
-#define USE_RLE 0
-#if USE_RLE
-export template<typename T>
-void * RLEEncode(const void * pixels, unsigned count, unsigned * encodedSize)
-{
- // first is a byte indicating data size [1,2,4] bytes
- // then an unsigned indicating decompressed size
- // then a byte of header: MSB == 1 indicates run, else literal
- // LSB7 is run or literal length (actual length - 1)
-
- const T * data = (T *)pixels;
- unsigned bufferSize = sizeof(T) * count / 2 + 8;
- unsigned char * buffer = (unsigned char *)malloc(bufferSize);
- buffer[0] = sizeof(T);
- unsigned bufferWritten = 1; // number of bytes written
- *(unsigned *)(buffer + bufferWritten) = count;
- bufferWritten += sizeof(count);
- while (count) {
- unsigned char run = 1;
- bool repeat = true;
- for (run = 1; run < count; run++)
- if (data[0] != data[run]) {
- repeat = false;
- break;
- } else if (run > 126)
- break;
- if (!repeat) {
- // find literal length
- for (run = 1; run < count; run++)
- if (data[run - 1] == data[run])
- break;
- else if (run > 126)
- break;
- unsigned bytesToWrite = 1 + sizeof(T) * run;
- if (bufferWritten + bytesToWrite > bufferSize) {
- bufferSize += sizeof(T) * run + 256;
- buffer = (unsigned char *)realloc(buffer, bufferSize);
- }
- buffer[bufferWritten++] = run - 1;
- for (unsigned i = 0; i < run; i++) {
- *(T *)(buffer + bufferWritten) = *data;
- bufferWritten += sizeof(T);
- data++;
- }
- count -= run;
- } else {
- unsigned bytesToWrite = 1 + sizeof(T);
- if (bufferWritten + bytesToWrite > bufferSize) {
- bufferSize += 256;
- buffer = (unsigned char *)realloc(buffer, bufferSize);
- }
- buffer[bufferWritten++] = (run - 1) | 0x80;
- *(T *)(buffer + bufferWritten) = data[0];
- bufferWritten += sizeof(T);
- data += run;
- count -= run;
- }
- }
- if (encodedSize)
- *encodedSize = bufferWritten;
- return buffer;
-}
-
-void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize)
-{
- switch (bytesPerPixel) {
- case 4:
- return RLEEncode<int>(pixels, count, encodedSize);
- case 2:
- return RLEEncode<short>(pixels, count, encodedSize);
- case 1:
- return RLEEncode<char>(pixels, count, encodedSize);
- default:
- assert(0);
- return NULL;
- }
-}
-#endif
-}; // namespace android
-
-void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
- glesv2debugger::Message msg;
- const bool expectResponse = false;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLint internalformat;
- GLsizei width;
- GLsizei height;
- GLint border;
- GLenum format;
- GLenum type;
- const GLvoid* pixels;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.internalformat = internalformat;
- caller.width = width;
- caller.height = height;
- caller.border = border;
- caller.format = format;
- caller.type = type;
- caller.pixels = pixels;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(internalformat);
- msg.set_arg3(width);
- msg.set_arg4(height);
- msg.set_arg5(border);
- msg.set_arg6(format);
- msg.set_arg7(type);
- msg.set_arg8(reinterpret_cast<int>(pixels));
-
- if (pixels) {
- assert(internalformat == format);
- assert(0 == border);
-
- unsigned bytesPerPixel = GetBytesPerPixel(format, type);
- assert(0 < bytesPerPixel);
-
-// LOGD("GLESv2_dbg: glTexImage2D width=%d height=%d level=%d bytesPerPixel=%d",
-// width, height, level, bytesPerPixel);
-#if USE_RLE
- unsigned encodedSize = 0;
- void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
- msg.set_data(data, encodedSize);
- free(data);
- if (encodedSize > bytesPerPixel * width * height)
- LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
-#else
- msg.set_data(pixels, bytesPerPixel * width * height);
-#endif
- }
-
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glTexImage2D);
-}
-
-void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
-{
- glesv2debugger::Message msg;
- const bool expectResponse = false;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLint xoffset;
- GLint yoffset;
- GLsizei width;
- GLsizei height;
- GLenum format;
- GLenum type;
- const GLvoid* pixels;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.xoffset = xoffset;
- caller.yoffset = yoffset;
- caller.width = width;
- caller.height = height;
- caller.format = format;
- caller.type = type;
- caller.pixels = pixels;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(xoffset);
- msg.set_arg3(yoffset);
- msg.set_arg4(width);
- msg.set_arg5(height);
- msg.set_arg6(format);
- msg.set_arg7(type);
- msg.set_arg8(reinterpret_cast<int>(pixels));
-
- assert(pixels);
- if (pixels) {
- unsigned bytesPerPixel = GetBytesPerPixel(format, type);
- assert(0 < bytesPerPixel);
-
-// LOGD("GLESv2_dbg: glTexSubImage2D width=%d height=%d level=%d bytesPerPixel=%d",
-// width, height, level, bytesPerPixel);
-
-#if USE_RLE
- unsigned encodedSize = 0;
- void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
- msg.set_data(data, encodedSize);
- free(data);
- if (encodedSize > bytesPerPixel * width * height)
- LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
-#else
- msg.set_data(pixels, bytesPerPixel * width * height);
-#endif
- }
-
- int * ret = MessageLoop(caller, msg, expectResponse,
- glesv2debugger::Message_Function_glTexSubImage2D);
-}
\ No newline at end of file
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index a73967f..471e5ad 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -19,8 +19,6 @@
namespace android
{
bool capture; // capture after each glDraw*
-
-void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize);
}
void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
@@ -29,7 +27,7 @@
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = false;
+ const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glReadPixels);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glReadPixels);
msg.set_arg0(x);
@@ -39,8 +37,8 @@
msg.set_arg4(format);
msg.set_arg5(type);
msg.set_arg6(reinterpret_cast<int>(pixels));
- //void * data = NULL;
- //unsigned encodedSize = 0;
+
+ const unsigned size = width * height * GetBytesPerPixel(format, type);
if (!expectResponse)
cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
Send(msg, cmd);
@@ -56,30 +54,29 @@
msg.set_function(glesv2debugger::Message_Function_glReadPixels);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- //data = RLEEncode(pixels, GetBytesPerPixel(format, type), width * height, &encodedSize);
- msg.set_data(pixels, width * height * GetBytesPerPixel(format, type));
- //msg.set_data(data, encodedSize);
- //free(data);
- c0 = systemTime(timeMode);
+ if (dbg->IsReadPixelBuffer(pixels)) {
+ dbg->CompressReadPixelBuffer(msg.mutable_data());
+ msg.set_data_type(msg.ReferencedImage);
+ } else {
+ dbg->Compress(pixels, size, msg.mutable_data());
+ msg.set_data_type(msg.NonreferencedImage);
+ }
if (!expectResponse)
cmd.set_function(glesv2debugger::Message_Function_SKIP);
- t = Send(msg, cmd);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_clock(t);
- // time is total send time in seconds, clock is msg serialization time in seconds
- msg.clear_data();
- msg.set_expect_response(false);
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- //Send(msg, cmd);
+ Send(msg, cmd);
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
- SetProp(cmd);
+ SetProp(dbg, cmd);
Receive(cmd);
break;
default:
- assert(0); //GenerateCall(msg, cmd);
+ GenerateCall(dbg, cmd, msg, NULL);
+ msg.set_expect_response(expectResponse);
+ if (!expectResponse)
+ cmd.set_function(cmd.SKIP);
+ Send(msg, cmd);
break;
}
}
@@ -91,7 +88,7 @@
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = false;
+ const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
msg.set_arg0(mode);
@@ -129,22 +126,26 @@
dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
- LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
- viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
- pixels = malloc(viewport[2] * viewport[3] * 4);
+// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
+// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
+ pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+ GetBytesPerPixel(readFormat, readType));
Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
readFormat, readType, pixels);
- free(pixels);
}
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
- SetProp(cmd);
+ SetProp(dbg, cmd);
Receive(cmd);
break;
default:
- assert(0); //GenerateCall(msg, cmd);
+ GenerateCall(dbg, cmd, msg, NULL);
+ msg.set_expect_response(expectResponse);
+ if (!expectResponse)
+ cmd.set_function(cmd.SKIP);
+ Send(msg, cmd);
break;
}
}
@@ -168,7 +169,7 @@
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = false;
+ const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glDrawElements);
msg.set_arg0(mode);
@@ -180,12 +181,14 @@
std::string * const data = msg.mutable_data();
if (GL_UNSIGNED_BYTE == type) {
if (dbg->indexBuffer)
- FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data + (unsigned long)indices, data, dbg);
+ FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data +
+ (unsigned long)indices, data, dbg);
else
FetchIndexed(count, (unsigned char *)indices, data, dbg);
} else if (GL_UNSIGNED_SHORT == type) {
if (dbg->indexBuffer)
- FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data + (unsigned long)indices), data, dbg);
+ FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data +
+ (unsigned long)indices), data, dbg);
else
FetchIndexed(count, (unsigned short *)indices, data, dbg);
} else
@@ -215,22 +218,26 @@
dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
- LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
- viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
- pixels = malloc(viewport[2] * viewport[3] * 4);
+// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
+// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
+ pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+ GetBytesPerPixel(readFormat, readType));
Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
readFormat, readType, pixels);
- free(pixels);
}
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
- SetProp(cmd);
+ SetProp(dbg, cmd);
Receive(cmd);
break;
default:
- assert(0); //GenerateCall(msg, cmd);
+ GenerateCall(dbg, cmd, msg, NULL);
+ msg.set_expect_response(expectResponse);
+ if (!expectResponse)
+ cmd.set_function(cmd.SKIP);
+ Send(msg, cmd);
break;
}
}
diff --git a/opengl/tests/gl2_cameraeye/Android.mk b/opengl/tests/gl2_cameraeye/Android.mk
new file mode 100644
index 0000000..4a43a9e
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := GL2CameraEye
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/opengl/tests/gl2_cameraeye/AndroidManifest.xml b/opengl/tests/gl2_cameraeye/AndroidManifest.xml
new file mode 100644
index 0000000..c53f7be
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<!-- Declare the contents of this Android application. The namespace
+ attribute brings in the Android platform namespace, and the package
+ supplies a unique name for the application. When writing your
+ own application, the package name must be changed from "com.example.*"
+ to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.gl2cameraeye">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-feature android:name="android.hardware.camera" />
+ <uses-feature android:name="android.hardware.camera.autofocus" />
+ <uses-feature android:glEsVersion="0x00020000" />
+ <application android:label="@string/gl2cameraeye_name">
+ <activity android:name="GL2CameraEye">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/gl2_cameraeye/res/values/strings.xml b/opengl/tests/gl2_cameraeye/res/values/strings.xml
new file mode 100644
index 0000000..386b930
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="gl2cameraeye_name">GL2CameraEye</string>
+
+</resources>
diff --git a/opengl/tests/gl2_cameraeye/src/com/android/gl2cameraeye/GL2CameraEye.java b/opengl/tests/gl2_cameraeye/src/com/android/gl2cameraeye/GL2CameraEye.java
new file mode 100644
index 0000000..561e4c5
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/src/com/android/gl2cameraeye/GL2CameraEye.java
@@ -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.
+ */
+
+package com.android.gl2cameraeye;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.app.Activity;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.content.Context;
+import android.util.Log;
+
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLUtils;
+import android.opengl.Matrix;
+
+import android.graphics.SurfaceTexture;
+
+import android.hardware.Camera;
+import android.hardware.SensorManager;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.Sensor;
+
+public class GL2CameraEye extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mGLView = new CamGLSurfaceView(this);
+ setContentView(mGLView);
+ setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLView.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLView.onResume();
+ }
+
+ private GLSurfaceView mGLView;
+}
+
+class CamGLSurfaceView extends GLSurfaceView implements SensorEventListener {
+ public CamGLSurfaceView(Context context) {
+ super(context);
+ setEGLContextClientVersion(2);
+ mRenderer = new CamRenderer(context);
+ setRenderer(mRenderer);
+
+ mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+ mAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
+ }
+
+ public boolean onTouchEvent(final MotionEvent event) {
+ queueEvent(new Runnable(){
+ public void run() {
+ mRenderer.setPosition(event.getX() / getWidth(),
+ event.getY() / getHeight());
+ }});
+ return true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mCamera.stopPreview();
+ mCamera.release();
+
+ mSensorManager.unregisterListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ mCamera = Camera.open();
+ Camera.Parameters p = mCamera.getParameters();
+ // No changes to default camera parameters
+ mCamera.setParameters(p);
+
+ queueEvent(new Runnable(){
+ public void run() {
+ mRenderer.setCamera(mCamera);
+ }});
+
+ mSensorManager.registerListener(this, mAcceleration, SensorManager.SENSOR_DELAY_GAME);
+ super.onResume();
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
+ final float[] accelerationVector = event.values;
+ queueEvent(new Runnable(){
+ public void run() {
+ mRenderer.setAcceleration(accelerationVector);
+ }});
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Ignoring sensor accuracy changes.
+ }
+
+ CamRenderer mRenderer;
+ Camera mCamera;
+
+ SensorManager mSensorManager;
+ Sensor mAcceleration;
+}
+
+class CamRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
+
+ public CamRenderer(Context context) {
+ mContext = context;
+
+ mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
+ * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
+ mTriangleVertices.put(mTriangleVerticesData).position(0);
+
+ Matrix.setIdentityM(mSTMatrix, 0);
+ Matrix.setIdentityM(mMMatrix, 0);
+
+ float[] defaultAcceleration = {0.f,0.f,0.f};
+ setAcceleration(defaultAcceleration);
+ mPos[0] = 0.f;
+ mPos[1] = 0.f;
+ mPos[2] = 0.f;
+ mVel[0] = 0.f;
+ mVel[1] = 0.f;
+ mVel[2] = 0.f;
+
+ }
+
+ /* The following set methods are not synchronized, so should only
+ * be called within the rendering thread context. Use GLSurfaceView.queueEvent for safe access.
+ */
+ public void setPosition(float x, float y) {
+ /* Map from screen (0,0)-(1,1) to scene coordinates */
+ mPos[0] = (x*2-1)*mRatio;
+ mPos[1] = (-y)*2+1;
+ mPos[2] = 0.f;
+ mVel[0] = 0;
+ mVel[1] = 0;
+ mVel[2] = 0;
+ }
+
+ public void setCamera(Camera camera) {
+ mCamera = camera;
+ Camera.Size previewSize = camera.getParameters().getPreviewSize();
+ mCameraRatio = (float)previewSize.width/previewSize.height;
+ }
+
+ public void setAcceleration(float[] accelerationVector) {
+ mGForce[0] = accelerationVector[0];
+ mGForce[1] = accelerationVector[1];
+ mGForce[2] = accelerationVector[2];
+ }
+
+ public void onDrawFrame(GL10 glUnused) {
+ synchronized(this) {
+ if (updateSurface) {
+ mSurface.updateTexImage();
+
+ mSurface.getTransformMatrix(mSTMatrix);
+ long timestamp = mSurface.getTimestamp();
+ doPhysics(timestamp);
+
+ updateSurface = false;
+ }
+ }
+
+ // Ignore the passed-in GL10 interface, and use the GLES20
+ // class's static methods instead.
+ GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+ GLES20.glUseProgram(mProgram);
+ checkGlError("glUseProgram");
+
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
+
+ mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+ GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ checkGlError("glVertexAttribPointer maPosition");
+ GLES20.glEnableVertexAttribArray(maPositionHandle);
+ checkGlError("glEnableVertexAttribArray maPositionHandle");
+
+ mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+ GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ checkGlError("glVertexAttribPointer maTextureHandle");
+ GLES20.glEnableVertexAttribArray(maTextureHandle);
+ checkGlError("glEnableVertexAttribArray maTextureHandle");
+
+ Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
+ Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
+
+ GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+ GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
+ GLES20.glUniform1f(muCRatioHandle, mCameraRatio);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+ checkGlError("glDrawArrays");
+ }
+
+ public void onSurfaceChanged(GL10 glUnused, int width, int height) {
+ // Ignore the passed-in GL10 interface, and use the GLES20
+ // class's static methods instead.
+ GLES20.glViewport(0, 0, width, height);
+ mRatio = (float) width / height;
+ Matrix.frustumM(mProjMatrix, 0, -mRatio, mRatio, -1, 1, 3, 7);
+ }
+
+ public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+ // Ignore the passed-in GL10 interface, and use the GLES20
+ // class's static methods instead.
+
+ /* Set up alpha blending and an Android background color */
+ GLES20.glEnable(GLES20.GL_BLEND);
+ GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+ GLES20.glClearColor(0.643f, 0.776f, 0.223f, 1.0f);
+
+ /* Set up shaders and handles to their variables */
+ mProgram = createProgram(mVertexShader, mFragmentShader);
+ if (mProgram == 0) {
+ return;
+ }
+ maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
+ checkGlError("glGetAttribLocation aPosition");
+ if (maPositionHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for aPosition");
+ }
+ maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
+ checkGlError("glGetAttribLocation aTextureCoord");
+ if (maTextureHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for aTextureCoord");
+ }
+
+ muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+ checkGlError("glGetUniformLocation uMVPMatrix");
+ if (muMVPMatrixHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for uMVPMatrix");
+ }
+
+ muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
+ checkGlError("glGetUniformLocation uSTMatrix");
+ if (muMVPMatrixHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for uSTMatrix");
+ }
+
+ muCRatioHandle = GLES20.glGetUniformLocation(mProgram, "uCRatio");
+ checkGlError("glGetUniformLocation uCRatio");
+ if (muMVPMatrixHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for uCRatio");
+ }
+
+ /*
+ * Create our texture. This has to be done each time the
+ * surface is created.
+ */
+
+ int[] textures = new int[1];
+ GLES20.glGenTextures(1, textures, 0);
+
+ mTextureID = textures[0];
+ GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
+ checkGlError("glBindTexture mTextureID");
+
+ // Can't do mipmapping with camera source
+ GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_NEAREST);
+ GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+ GLES20.GL_LINEAR);
+ // Clamp to edge is the only option
+ GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
+ GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
+ GLES20.GL_CLAMP_TO_EDGE);
+ checkGlError("glTexParameteri mTextureID");
+
+ /*
+ * Create the SurfaceTexture that will feed this textureID, and pass it to the camera
+ */
+
+ mSurface = new SurfaceTexture(mTextureID);
+ mSurface.setOnFrameAvailableListener(this);
+ try {
+ mCamera.setPreviewTexture(mSurface);
+ } catch (IOException t) {
+ Log.e(TAG, "Cannot set preview texture target!");
+ }
+
+ /* Start the camera */
+ mCamera.startPreview();
+
+ Matrix.setLookAtM(mVMatrix, 0, 0, 0, 5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+
+ mLastTime = 0;
+
+ synchronized(this) {
+ updateSurface = false;
+ }
+ }
+
+ synchronized public void onFrameAvailable(SurfaceTexture surface) {
+ /* For simplicity, SurfaceTexture calls here when it has new
+ * data available. Call may come in from some random thread,
+ * so let's be safe and use synchronize. No OpenGL calls can be done here.
+ */
+ updateSurface = true;
+ }
+
+ private void doPhysics(long timestamp) {
+ /*
+ * Move the camera surface around based on some simple spring physics with drag
+ */
+
+ if (mLastTime == 0)
+ mLastTime = timestamp;
+
+ float deltaT = (timestamp - mLastTime)/1000000000.f; // To seconds
+
+ float springStrength = 20.f;
+ float frictionCoeff = 10.f;
+ float mass = 10.f;
+ float gMultiplier = 4.f;
+ /* Only update physics every 30 ms */
+ if (deltaT > 0.030f) {
+ mLastTime = timestamp;
+
+ float[] totalForce = new float[3];
+ totalForce[0] = -mPos[0] * springStrength - mVel[0]*frictionCoeff + gMultiplier*mGForce[0]*mass;
+ totalForce[1] = -mPos[1] * springStrength - mVel[1]*frictionCoeff + gMultiplier*mGForce[1]*mass;
+ totalForce[2] = -mPos[2] * springStrength - mVel[2]*frictionCoeff + gMultiplier*mGForce[2]*mass;
+
+ float[] accel = new float[3];
+ accel[0] = totalForce[0]/mass;
+ accel[1] = totalForce[1]/mass;
+ accel[2] = totalForce[2]/mass;
+
+ /* Not a very accurate integrator */
+ mVel[0] = mVel[0] + accel[0]*deltaT;
+ mVel[1] = mVel[1] + accel[1]*deltaT;
+ mVel[2] = mVel[2] + accel[2]*deltaT;
+
+ mPos[0] = mPos[0] + mVel[0]*deltaT;
+ mPos[1] = mPos[1] + mVel[1]*deltaT;
+ mPos[2] = mPos[2] + mVel[2]*deltaT;
+
+ Matrix.setIdentityM(mMMatrix, 0);
+ Matrix.translateM(mMMatrix, 0, mPos[0], mPos[1], mPos[2]);
+ }
+
+ }
+
+ private int loadShader(int shaderType, String source) {
+ int shader = GLES20.glCreateShader(shaderType);
+ if (shader != 0) {
+ GLES20.glShaderSource(shader, source);
+ GLES20.glCompileShader(shader);
+ int[] compiled = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+ if (compiled[0] == 0) {
+ Log.e(TAG, "Could not compile shader " + shaderType + ":");
+ Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+ }
+
+ private int createProgram(String vertexSource, String fragmentSource) {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+ if (vertexShader == 0) {
+ return 0;
+ }
+ int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+ if (pixelShader == 0) {
+ return 0;
+ }
+
+ int program = GLES20.glCreateProgram();
+ if (program != 0) {
+ GLES20.glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ GLES20.glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ GLES20.glLinkProgram(program);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+ }
+
+ private void checkGlError(String op) {
+ int error;
+ while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+ Log.e(TAG, op + ": glError " + error);
+ throw new RuntimeException(op + ": glError " + error);
+ }
+ }
+
+ private static final int FLOAT_SIZE_BYTES = 4;
+ private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+ private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+ private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+ private final float[] mTriangleVerticesData = {
+ // X, Y, Z, U, V
+ -1.0f, -1.0f, 0, 0.f, 0.f,
+ 1.0f, -1.0f, 0, 1.f, 0.f,
+ -1.0f, 1.0f, 0, 0.f, 1.f,
+ 1.0f, 1.0f, 0, 1.f, 1.f,
+ };
+
+ private FloatBuffer mTriangleVertices;
+
+ private final String mVertexShader =
+ "uniform mat4 uMVPMatrix;\n" +
+ "uniform mat4 uSTMatrix;\n" +
+ "uniform float uCRatio;\n" +
+ "attribute vec4 aPosition;\n" +
+ "attribute vec4 aTextureCoord;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "varying vec2 vTextureNormCoord;\n" +
+ "void main() {\n" +
+ " vec4 scaledPos = aPosition;\n" +
+ " scaledPos.x = scaledPos.x * uCRatio;\n" +
+ " gl_Position = uMVPMatrix * scaledPos;\n" +
+ " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
+ " vTextureNormCoord = aTextureCoord.xy;\n" +
+ "}\n";
+
+ private final String mFragmentShader =
+ "#extension GL_OES_EGL_image_external : require\n" +
+ "precision mediump float;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "varying vec2 vTextureNormCoord;\n" +
+ "uniform samplerExternalOES sTexture;\n" +
+ "void main() {\n" +
+ " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+ " gl_FragColor.a = 1.0-min(length(vTextureNormCoord-0.5)*2.0,1.0);\n" +
+ "}\n";
+
+ private float[] mMVPMatrix = new float[16];
+ private float[] mProjMatrix = new float[16];
+ private float[] mMMatrix = new float[16];
+ private float[] mVMatrix = new float[16];
+ private float[] mSTMatrix = new float[16];
+
+ private int mProgram;
+ private int mTextureID;
+ private int muMVPMatrixHandle;
+ private int muSTMatrixHandle;
+ private int muCRatioHandle;
+ private int maPositionHandle;
+ private int maTextureHandle;
+
+ private float mRatio = 1.0f;
+ private float mCameraRatio = 1.0f;
+ private float[] mVel = new float[3];
+ private float[] mPos = new float[3];
+ private float[] mGForce = new float[3];
+
+ private long mLastTime;
+
+ private SurfaceTexture mSurface;
+ private Camera mCamera;
+ private boolean updateSurface = false;
+
+ private Context mContext;
+ private static String TAG = "CamRenderer";
+
+ // Magic key
+ private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
+}
diff --git a/opengl/tools/glgen/specs/gles11/checks.spec b/opengl/tools/glgen/specs/gles11/checks.spec
index f917128..f478a32 100644
--- a/opengl/tools/glgen/specs/gles11/checks.spec
+++ b/opengl/tools/glgen/specs/gles11/checks.spec
@@ -31,28 +31,12 @@
glDrawTexivOES check coords 5
glDrawTexsvOES check coords 5
glDrawTexxvOES check coords 5
-glBindFramebufferOES unsupported
-glBindRenderbufferOES unsupported
-glBlendEquation unsupported
-glBlendEquationSeparate unsupported
-glBlendFuncSeparate unsupported
-glCheckFramebufferStatusOES unsupported return 0
-glDeleteFramebuffersOES unsupported
-glDeleteRenderbuffersOES unsupported
-glFramebufferRenderbufferOES unsupported
-glFramebufferStorageOES unsupported
-glFramebufferTexture2DOES unsupported
-glGenFramebuffersOES unsupported
-glGenRenderbuffersOES unsupported
-glGenerateMipmapOES unsupported
-glGetBufferParameter unsupported
-glGetFramebufferAttachmentParameterivOES unsupported
-glGetRenderbufferParameterivOES unsupported
-glGetTexGen unsupported
-glIsFramebufferOES unsupported return JNI_FALSE
-glIsRenderbufferOES unsupported return JNI_FALSE
-glRenderbufferStorageOES unsupported return false
-glTexGen unsupported
-glTexGenf unsupported
-glTexGeni unsupported
-glTexGenx unsupported
+glDeleteFramebuffersOES check framebuffers n
+glDeleteRenderbuffersOES check renderbuffers n
+glGenFramebuffersOES check framebuffers n
+glGenRenderbuffersOES check renderbuffers n
+glGetBufferParameter check params 1
+glGetFramebufferAttachmentParameterivOES check params 1
+glGetRenderbufferParameterivOES check params 1
+glGetTexGen ifcheck params 1 pname GL_TEXTURE_GEN_MODE ifcheck params 4 pname GL_OBJECT_PLANE,GL_EYE_PLANE
+
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8e18f2a..4fa5bcb 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -646,12 +646,17 @@
* Create (if necessary) and launch the recent apps dialog
*/
void showRecentAppsDialog() {
- if (mRecentAppsDialog == null) {
- mRecentAppsDialog = new RecentApplicationsDialog(mContext);
- }
- mRecentAppsDialog.show();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mRecentAppsDialog == null) {
+ mRecentAppsDialog = new RecentApplicationsDialog(mContext);
+ }
+ mRecentAppsDialog.show();
+ }
+ });
}
-
+
/** {@inheritDoc} */
public void init(Context context, IWindowManager windowManager,
LocalPowerManager powerManager) {
@@ -1386,7 +1391,7 @@
}
return false;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
- if (!down) {
+ if (down && repeatCount == 0) {
showRecentAppsDialog();
}
return true;
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index b52fc69..14f1e8b 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -49,7 +49,6 @@
libcutils \
libmedia \
libcamera_client \
- libsurfaceflinger_client \
libgui
LOCAL_MODULE:= libcameraservice
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a09e16b..f3c9959 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -666,20 +666,6 @@
mHardware->releaseRecordingFrame(mem);
}
-int32_t CameraService::Client::getNumberOfVideoBuffers() const {
- LOG1("getNumberOfVideoBuffers");
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return 0;
- return mHardware->getNumberOfVideoBuffers();
-}
-
-sp<IMemory> CameraService::Client::getVideoBuffer(int32_t index) const {
- LOG1("getVideoBuffer: %d", index);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return 0;
- return mHardware->getVideoBuffer(index);
-}
-
status_t CameraService::Client::storeMetaDataInBuffers(bool enabled)
{
LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
@@ -938,7 +924,7 @@
switch (msgType) {
case CAMERA_MSG_SHUTTER:
// ext1 is the dimension of the yuv picture.
- client->handleShutter((image_rect_type *)ext1);
+ client->handleShutter();
break;
default:
client->handleGenericNotify(msgType, ext1, ext2);
@@ -997,9 +983,7 @@
}
// snapshot taken callback
-// "size" is the width and height of yuv picture for registerBuffer.
-// If it is NULL, use the picture size from parameters.
-void CameraService::Client::handleShutter(image_rect_type *size) {
+void CameraService::Client::handleShutter(void) {
if (mPlayShutterSound) {
mCameraService->playSound(SOUND_SHUTTER);
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 1c43b00..28e8cc0 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -99,8 +99,6 @@
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual int32_t getNumberOfVideoBuffers() const;
- virtual sp<IMemory> getVideoBuffer(int32_t index) const;
virtual status_t storeMetaDataInBuffers(bool enabled);
virtual status_t startRecording();
virtual void stopRecording();
@@ -152,7 +150,7 @@
// convert client from cookie
static sp<Client> getClientFromCookie(void* user);
// handlers for messages
- void handleShutter(image_rect_type *size);
+ void handleShutter(void);
void handlePreviewData(const sp<IMemory>& mem);
void handlePostview(const sp<IMemory>& mem);
void handleRawPicture(const sp<IMemory>& mem);
diff --git a/services/camera/tests/CameraServiceTest/Android.mk b/services/camera/tests/CameraServiceTest/Android.mk
index cf4e42f..cf7302a 100644
--- a/services/camera/tests/CameraServiceTest/Android.mk
+++ b/services/camera/tests/CameraServiceTest/Android.mk
@@ -19,7 +19,7 @@
libutils \
libui \
libcamera_client \
- libsurfaceflinger_client
+ libgui
# Disable it because the ISurface interface may change, and before we have a
# chance to fix this test, we don't want to break normal builds.
diff --git a/services/input/Android.mk b/services/input/Android.mk
index d7b61fc..96431bc 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -29,8 +29,8 @@
libutils \
libhardware \
libhardware_legacy \
- libsurfaceflinger_client \
libskia \
+ libgui \
libui
LOCAL_C_INCLUDES := \
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 456e0e6..6ea068a 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -48,6 +48,9 @@
// Log debug messages about the app switch latency optimization.
#define DEBUG_APP_SWITCH 0
+// Log debug messages about hover events.
+#define DEBUG_HOVER 0
+
#include "InputDispatcher.h"
#include <cutils/log.h>
@@ -115,7 +118,9 @@
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_OUTSIDE:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
case AMOTION_EVENT_ACTION_SCROLL:
return true;
case AMOTION_EVENT_ACTION_POINTER_DOWN:
@@ -185,7 +190,8 @@
mFocusedWindow(NULL),
mFocusedApplication(NULL),
mCurrentInputTargetsValid(false),
- mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
+ mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE),
+ mLastHoverWindow(NULL) {
mLooper = new Looper(false);
mInboundQueue.headSentinel.refCount = -1;
@@ -557,18 +563,19 @@
}
switch (entry->type) {
- case EventEntry::TYPE_KEY:
- synthesizeCancelationEventsForAllConnectionsLocked(
- InputState::CANCEL_NON_POINTER_EVENTS, reason);
+ case EventEntry::TYPE_KEY: {
+ CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
+ synthesizeCancelationEventsForAllConnectionsLocked(options);
break;
+ }
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
- synthesizeCancelationEventsForAllConnectionsLocked(
- InputState::CANCEL_POINTER_EVENTS, reason);
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);
+ synthesizeCancelationEventsForAllConnectionsLocked(options);
} else {
- synthesizeCancelationEventsForAllConnectionsLocked(
- InputState::CANCEL_NON_POINTER_EVENTS, reason);
+ CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
+ synthesizeCancelationEventsForAllConnectionsLocked(options);
}
break;
}
@@ -837,10 +844,11 @@
bool conflictingPointerActions = false;
if (! mCurrentInputTargetsValid) {
int32_t injectionResult;
+ const MotionSample* splitBatchAfterSample = NULL;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime, &conflictingPointerActions);
+ entry, nextWakeupTime, &conflictingPointerActions, &splitBatchAfterSample);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
@@ -857,12 +865,48 @@
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 = mAllocator.obtainMotionEntry(nextSample->eventTime,
+ entry->deviceId, entry->source, entry->policyFlags,
+ entry->action, entry->flags, entry->metaState, entry->edgeFlags,
+ entry->xPrecision, entry->yPrecision, entry->downTime,
+ entry->pointerCount, entry->pointerIds, nextSample->pointerCoords);
+ if (nextSample != entry->lastSample) {
+ nextEntry->firstSample.next = nextSample->next;
+ nextEntry->lastSample = entry->lastSample;
+ }
+ mAllocator.freeMotionSample(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
+ LOGD("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);
+ }
}
// Dispatch the motion.
if (conflictingPointerActions) {
- synthesizeCancelationEventsForAllConnectionsLocked(
- InputState::CANCEL_POINTER_EVENTS, "Conflicting pointer actions.");
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+ "conflicting pointer actions");
+ synthesizeCancelationEventsForAllConnectionsLocked(options);
}
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
return true;
@@ -1028,9 +1072,9 @@
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
if (connection->status == Connection::STATUS_NORMAL) {
- synthesizeCancelationEventsForConnectionLocked(
- connection, InputState::CANCEL_ALL_EVENTS,
+ CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
"application not responding");
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
}
}
}
@@ -1107,7 +1151,8 @@
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));
+ addWindowTargetLocked(mFocusedWindow,
+ InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
// Done.
Failed:
@@ -1124,7 +1169,8 @@
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
+ const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
+ const MotionSample** outSplitBatchAfterSample) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
@@ -1167,14 +1213,19 @@
// Update the touch state as needed based on the properties of the touch event.
int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
+ const InputWindow* newHoverWindow = NULL;
bool isSplit = mTouchState.split;
bool wrongDevice = mTouchState.down
&& (mTouchState.deviceId != entry->deviceId
|| mTouchState.source != entry->source);
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
- || maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
+ bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
+ bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN
+ || maskedAction == AMOTION_EVENT_ACTION_SCROLL
+ || isHoverAction);
+ if (newGesture) {
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
if (wrongDevice && !down) {
mTempTouchState.copyFrom(mTouchState);
@@ -1190,26 +1241,25 @@
mTempTouchState.copyFrom(mTouchState);
}
if (wrongDevice) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Dropping event because a pointer for a different device is already down.");
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)
- || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
- || maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
+ 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(entry->firstSample.pointerCoords[pointerIndex].
+ int32_t x = int32_t(sample->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex].
+ int32_t y = int32_t(sample->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
const InputWindow* newTouchedWindow = NULL;
const InputWindow* topErrorWindow = NULL;
+ bool isTouchModal = false;
// Traverse windows from front to back to find touched window and outside targets.
size_t numWindows = mWindows.size();
@@ -1225,7 +1275,7 @@
if (window->visible) {
if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
- bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
+ isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
@@ -1237,7 +1287,7 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
&& (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
- int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
+ int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(window, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
@@ -1290,7 +1340,7 @@
}
// Set target flags.
- int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
+ int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
@@ -1298,6 +1348,28 @@
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
+ // Update hover state.
+ if (isHoverAction) {
+ newHoverWindow = newTouchedWindow;
+
+ // 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 (!newHoverWindow->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) {
+ newHoverWindow = mLastHoverWindow;
+ }
+
// Update the temporary touch state.
BitSet32 pointerIds;
if (isSplit) {
@@ -1310,7 +1382,7 @@
// If the pointer is not currently down, then ignore the event.
if (! mTempTouchState.down) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Dropping event because the pointer is not down or we previously "
"dropped the pointer down event.");
#endif
@@ -1319,6 +1391,29 @@
}
}
+ if (newHoverWindow != mLastHoverWindow) {
+ // 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 (mLastHoverWindow) {
+#if DEBUG_HOVER
+ LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string());
+#endif
+ mTempTouchState.addOrUpdateWindow(mLastHoverWindow,
+ InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
+ }
+
+ // Let the new window know that the hover sequence is starting.
+ if (newHoverWindow) {
+#if DEBUG_HOVER
+ LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string());
+#endif
+ mTempTouchState.addOrUpdateWindow(newHoverWindow,
+ InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
+ }
+ }
+
// Check permission to inject into all touched foreground windows and ensure there
// is at least one touched foreground window.
{
@@ -1335,7 +1430,7 @@
}
}
if (! haveForegroundWindow) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Dropping event because there is no touched foreground window to receive it.");
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
@@ -1352,7 +1447,7 @@
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// If the touched window is paused then keep waiting.
if (touchedWindow.window->paused) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Waiting because touched window is paused.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
@@ -1385,7 +1480,9 @@
const InputWindow* window = & mWindows[i];
if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(window,
- InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));
+ InputTarget::FLAG_WINDOW_IS_OBSCURED
+ | InputTarget::FLAG_DISPATCH_AS_IS,
+ BitSet32(0));
}
}
}
@@ -1400,8 +1497,9 @@
touchedWindow.pointerIds);
}
- // Drop the outside touch window since we will not care about them in the next iteration.
- mTempTouchState.removeOutsideTouchWindows();
+ // Drop the outside or hover touch windows since we will not care about them
+ // in the next iteration.
+ mTempTouchState.filterNonAsIsTouchWindows();
Failed:
// Check injection permission once and for all.
@@ -1418,7 +1516,7 @@
if (!wrongDevice) {
if (maskedAction == AMOTION_EVENT_ACTION_UP
|| maskedAction == AMOTION_EVENT_ACTION_CANCEL
- || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ || isHoverAction) {
// All pointers up or canceled.
mTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
@@ -1455,6 +1553,9 @@
// Save changes to touch state as-is for all other actions.
mTouchState.copyFrom(mTempTouchState);
}
+
+ // Update hover state.
+ mLastHoverWindow = newHoverWindow;
}
} else {
#if DEBUG_FOCUS
@@ -1720,10 +1821,36 @@
}
}
+ // Enqueue dispatch entries for the requested modes.
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS);
+
+ // If the outbound queue was previously empty, start the dispatch cycle going.
+ if (wasEmpty) {
+ 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 inputTargetFlags = inputTarget->flags;
+ if (!(inputTargetFlags & dispatchMode)) {
+ return;
+ }
+ inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
+
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
- inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset);
+ inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset);
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatchesLocked(eventEntry);
}
@@ -1744,12 +1871,6 @@
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
-
- // If the outbound queue was previously empty, start the dispatch cycle going.
- if (wasEmpty) {
- activateConnectionLocked(connection.get());
- startDispatchCycleLocked(currentTime, connection);
- }
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -1768,12 +1889,9 @@
// Mark the dispatch entry as in progress.
dispatchEntry->inProgress = true;
- // Update the connection's input state.
- EventEntry* eventEntry = dispatchEntry->eventEntry;
- connection->inputState.trackEvent(eventEntry);
-
// Publish the event.
status_t status;
+ EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
@@ -1782,6 +1900,9 @@
int32_t action = keyEntry->action;
int32_t flags = keyEntry->flags;
+ // Update the connection's input state.
+ connection->inputState.trackKey(keyEntry, action);
+
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source,
action, flags, keyEntry->keyCode, keyEntry->scanCode,
@@ -1803,8 +1924,12 @@
// Apply target flags.
int32_t action = motionEntry->action;
int32_t flags = motionEntry->flags;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_OUTSIDE) {
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
action = AMOTION_EVENT_ACTION_OUTSIDE;
+ } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
+ action = AMOTION_EVENT_ACTION_HOVER_EXIT;
+ } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
+ action = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -1829,6 +1954,9 @@
yOffset = 0.0f;
}
+ // Update the connection's input state.
+ connection->inputState.trackMotion(motionEntry, action);
+
// Publish the motion event and the first motion sample.
status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
@@ -1845,31 +1973,34 @@
return;
}
- // Append additional motion samples.
- MotionSample* nextMotionSample = firstMotionSample->next;
- for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
- status = connection->inputPublisher.appendMotionSample(
- nextMotionSample->eventTime, nextMotionSample->pointerCoords);
- if (status == NO_MEMORY) {
+ if (action == AMOTION_EVENT_ACTION_MOVE
+ || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ // Append additional motion samples.
+ MotionSample* nextMotionSample = firstMotionSample->next;
+ for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
+ status = connection->inputPublisher.appendMotionSample(
+ nextMotionSample->eventTime, nextMotionSample->pointerCoords);
+ if (status == NO_MEMORY) {
#if DEBUG_DISPATCH_CYCLE
LOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will "
"be sent in the next dispatch cycle.",
connection->getInputChannelName());
#endif
- break;
+ break;
+ }
+ if (status != OK) {
+ LOGE("channel '%s' ~ Could not append motion sample "
+ "for a reason other than out of memory, status=%d",
+ connection->getInputChannelName(), status);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
+ return;
+ }
}
- if (status != OK) {
- LOGE("channel '%s' ~ Could not append motion sample "
- "for a reason other than out of memory, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
- return;
- }
- }
- // 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;
+ // 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;
+ }
break;
}
@@ -2040,26 +2171,24 @@
}
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
- InputState::CancelationOptions options, const char* reason) {
+ const CancelationOptions& options) {
for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
synthesizeCancelationEventsForConnectionLocked(
- mConnectionsByReceiveFd.valueAt(i), options, reason);
+ mConnectionsByReceiveFd.valueAt(i), options);
}
}
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
- const sp<InputChannel>& channel, InputState::CancelationOptions options,
- const char* reason) {
+ const sp<InputChannel>& channel, const CancelationOptions& options) {
ssize_t index = getConnectionIndexLocked(channel);
if (index >= 0) {
synthesizeCancelationEventsForConnectionLocked(
- mConnectionsByReceiveFd.valueAt(index), options, reason);
+ mConnectionsByReceiveFd.valueAt(index), options);
}
}
void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
- const sp<Connection>& connection, InputState::CancelationOptions options,
- const char* reason) {
+ const sp<Connection>& connection, const CancelationOptions& options) {
nsecs_t currentTime = now();
mTempCancelationEvents.clear();
@@ -2070,8 +2199,9 @@
&& connection->status != Connection::STATUS_BROKEN) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
- "with reality: %s, options=%d.",
- connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options);
+ "with reality: %s, mode=%d.",
+ connection->getInputChannelName(), mTempCancelationEvents.size(),
+ options.reason, options.mode);
#endif
for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
@@ -2199,6 +2329,11 @@
splitPointerCoords);
}
+ if (originalMotionEntry->injectionState) {
+ splitMotionEntry->injectionState = originalMotionEntry->injectionState;
+ splitMotionEntry->injectionState->refCount += 1;
+ }
+
return splitMotionEntry;
}
@@ -2408,6 +2543,29 @@
continue;
}
+ if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ if (!mLastHoverWindow) {
+#if DEBUG_BATCHING
+ LOGD("Not streaming hover move because there is no "
+ "last hovered window.");
+#endif
+ goto NoBatchingOrStreaming;
+ }
+
+ const InputWindow* hoverWindow = findTouchedWindowAtLocked(
+ pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
+ pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ if (mLastHoverWindow != hoverWindow) {
+#if DEBUG_BATCHING
+ LOGD("Not streaming hover move because the last hovered window "
+ "is '%s' but the currently hovered window is '%s'.",
+ mLastHoverWindow->name.string(),
+ hoverWindow ? hoverWindow->name.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.
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
@@ -2686,6 +2844,11 @@
oldFocusedWindowChannel = mFocusedWindow->inputChannel;
mFocusedWindow = NULL;
}
+ sp<InputChannel> oldLastHoverWindowChannel;
+ if (mLastHoverWindow) {
+ oldLastHoverWindowChannel = mLastHoverWindow->inputChannel;
+ mLastHoverWindow = NULL;
+ }
mWindows.clear();
@@ -2708,8 +2871,9 @@
LOGD("Focus left window: %s",
oldFocusedWindowChannel->getName().string());
#endif
- synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel,
- InputState::CANCEL_NON_POINTER_EVENTS, "focus left window");
+ CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
+ "focus left window");
+ synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options);
oldFocusedWindowChannel.clear();
}
}
@@ -2730,12 +2894,19 @@
#if DEBUG_FOCUS
LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
#endif
- synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel,
- InputState::CANCEL_POINTER_EVENTS, "touched window was removed");
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+ "touched window was removed");
+ synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options);
mTouchState.windows.removeAt(i);
}
}
+ // Recover the last hovered window.
+ if (oldLastHoverWindowChannel != NULL) {
+ mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel);
+ oldLastHoverWindowChannel.clear();
+ }
+
#if DEBUG_FOCUS
//logDispatchStateLocked();
#endif
@@ -2845,7 +3016,8 @@
mTouchState.windows.removeAt(i);
int32_t newTargetFlags = oldTargetFlags
- & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT);
+ & (InputTarget::FLAG_FOREGROUND
+ | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
found = true;
@@ -2867,9 +3039,9 @@
sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
- synthesizeCancelationEventsForConnectionLocked(fromConnection,
- InputState::CANCEL_POINTER_EVENTS,
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"transferring touch focus from this window to another window");
+ synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
}
#if DEBUG_FOCUS
@@ -2887,7 +3059,8 @@
LOGD("Resetting and dropping all events (%s).", reason);
#endif
- synthesizeCancelationEventsForAllConnectionsLocked(InputState::CANCEL_ALL_EVENTS, reason);
+ CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason);
+ synthesizeCancelationEventsForAllConnectionsLocked(options);
resetKeyRepeatLocked();
releasePendingEventLocked();
@@ -3217,58 +3390,49 @@
if (!connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
if (dispatchEntry->inProgress
- && dispatchEntry->hasForegroundTarget()
&& dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
- if (handled) {
- // If the application handled a non-fallback key, then immediately
- // cancel all fallback keys previously dispatched to the application.
- // This behavior will prevent chording with fallback keys (so they cannot
- // be used as modifiers) but it will ensure that fallback keys do not
- // get stuck. This takes care of the case where the application does not handle
- // the original DOWN so we generate a fallback DOWN but it does handle
- // the original UP in which case we want to send a fallback CANCEL.
- synthesizeCancelationEventsForConnectionLocked(connection,
- InputState::CANCEL_FALLBACK_EVENTS,
- "application handled a non-fallback event, "
- "canceling all fallback events");
- connection->originalKeyCodeForFallback = -1;
+ // Get the fallback key state.
+ // Clear it out after dispatching the UP.
+ int32_t originalKeyCode = keyEntry->keyCode;
+ int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode);
+ if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+ connection->inputState.removeFallbackKey(originalKeyCode);
+ }
+
+ if (handled || !dispatchEntry->hasForegroundTarget()) {
+ // If the application handles the original key for which we previously
+ // generated a fallback or if the window is not a foreground window,
+ // then cancel the associated fallback key, if any.
+ if (fallbackKeyCode != -1) {
+ if (fallbackKeyCode != AKEYCODE_UNKNOWN) {
+ CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
+ "application handled the original non-fallback key "
+ "or is no longer a foreground target, "
+ "canceling previously dispatched fallback key");
+ options.keyCode = fallbackKeyCode;
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
+ }
+ connection->inputState.removeFallbackKey(originalKeyCode);
+ }
} else {
// If the application did not handle a non-fallback key, first check
- // that we are in a good state to handle the fallback key. Then ask
- // the policy what to do with it.
- if (connection->originalKeyCodeForFallback < 0) {
- if (keyEntry->action != AKEY_EVENT_ACTION_DOWN
- || keyEntry->repeatCount != 0) {
+ // that we are in a good state to perform unhandled key event processing
+ // Then ask the policy what to do with it.
+ bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN
+ && keyEntry->repeatCount == 0;
+ if (fallbackKeyCode == -1 && !initialDown) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("Unhandled key event: Skipping fallback since this "
- "is not an initial down. "
- "keyCode=%d, action=%d, repeatCount=%d",
- keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount);
+ LOGD("Unhandled key event: Skipping unhandled key event processing "
+ "since this is not an initial down. "
+ "keyCode=%d, action=%d, repeatCount=%d",
+ originalKeyCode, keyEntry->action, keyEntry->repeatCount);
#endif
- goto SkipFallback;
- }
-
- // Start handling the fallback key on DOWN.
- connection->originalKeyCodeForFallback = keyEntry->keyCode;
- } else {
- if (keyEntry->keyCode != connection->originalKeyCodeForFallback) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("Unhandled key event: Skipping fallback since there is "
- "already a different fallback in progress. "
- "keyCode=%d, originalKeyCodeForFallback=%d",
- keyEntry->keyCode, connection->originalKeyCodeForFallback);
-#endif
- goto SkipFallback;
- }
-
- // Finish handling the fallback key on UP.
- if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
- connection->originalKeyCodeForFallback = -1;
- }
+ goto SkipFallback;
}
+ // Dispatch the unhandled key to the policy.
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("Unhandled key event: Asking policy to perform fallback action. "
"keyCode=%d, action=%d, repeatCount=%d",
@@ -3285,18 +3449,78 @@
mLock.lock();
if (connection->status != Connection::STATUS_NORMAL) {
+ connection->inputState.removeFallbackKey(originalKeyCode);
return;
}
assert(connection->outboundQueue.headSentinel.next == 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) {
+ if (fallback) {
+ fallbackKeyCode = event.getKeyCode();
+ } else {
+ fallbackKeyCode = AKEYCODE_UNKNOWN;
+ }
+ connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode);
+ }
+
+ assert(fallbackKeyCode != -1);
+
+ // Cancel the fallback key if the policy decides not to send it anymore.
+ // We will continue to dispatch the key to the policy but we will no
+ // longer dispatch a fallback key to the application.
+ if (fallbackKeyCode != AKEYCODE_UNKNOWN
+ && (!fallback || fallbackKeyCode != event.getKeyCode())) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ if (fallback) {
+ LOGD("Unhandled key event: Policy requested to send key %d"
+ "as a fallback for %d, but on the DOWN it had requested "
+ "to send %d instead. Fallback canceled.",
+ event.getKeyCode(), originalKeyCode, fallbackKeyCode);
+ } else {
+ LOGD("Unhandled key event: Policy did not request fallback for %d,"
+ "but on the DOWN it had requested to send %d. "
+ "Fallback canceled.",
+ originalKeyCode, fallbackKeyCode);
+ }
+#endif
+
+ CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
+ "canceling fallback, policy no longer desires it");
+ options.keyCode = fallbackKeyCode;
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
+
+ fallback = false;
+ fallbackKeyCode = AKEYCODE_UNKNOWN;
+ if (keyEntry->action != AKEY_EVENT_ACTION_UP) {
+ connection->inputState.setFallbackKey(originalKeyCode,
+ fallbackKeyCode);
+ }
+ }
+
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ {
+ String8 msg;
+ const KeyedVector<int32_t, int32_t>& fallbackKeys =
+ connection->inputState.getFallbackKeys();
+ for (size_t i = 0; i < fallbackKeys.size(); i++) {
+ msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
+ fallbackKeys.valueAt(i));
+ }
+ LOGD("Unhandled key event: %d currently tracked fallback keys%s.",
+ fallbackKeys.size(), msg.string());
+ }
+#endif
+
if (fallback) {
// Restart the dispatch cycle using the fallback key.
keyEntry->eventTime = event.getEventTime();
keyEntry->deviceId = event.getDeviceId();
keyEntry->source = event.getSource();
keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
- keyEntry->keyCode = event.getKeyCode();
+ keyEntry->keyCode = fallbackKeyCode;
keyEntry->scanCode = event.getScanCode();
keyEntry->metaState = event.getMetaState();
keyEntry->repeatCount = event.getRepeatCount();
@@ -3305,13 +3529,17 @@
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("Unhandled key event: Dispatching fallback key. "
- "fallbackKeyCode=%d, fallbackMetaState=%08x",
- keyEntry->keyCode, keyEntry->metaState);
+ "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
+ originalKeyCode, fallbackKeyCode, keyEntry->metaState);
#endif
dispatchEntry->inProgress = false;
startDispatchCycleLocked(now(), connection);
return;
+ } else {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("Unhandled key event: No fallback key.");
+#endif
}
}
}
@@ -3533,6 +3761,10 @@
}
}
+void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) {
+ mMotionSamplePool.free(sample);
+}
+
void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) {
releaseEventEntry(entry->eventEntry);
mDispatchEntryPool.free(entry);
@@ -3588,22 +3820,30 @@
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-void InputDispatcher::InputState::trackEvent(
- const EventEntry* entry) {
+void InputDispatcher::InputState::trackEvent(const EventEntry* entry, int32_t action) {
switch (entry->type) {
case EventEntry::TYPE_KEY:
- trackKey(static_cast<const KeyEntry*>(entry));
+ trackKey(static_cast<const KeyEntry*>(entry), action);
break;
case EventEntry::TYPE_MOTION:
- trackMotion(static_cast<const MotionEntry*>(entry));
+ trackMotion(static_cast<const MotionEntry*>(entry), action);
break;
}
}
-void InputDispatcher::InputState::trackKey(
- const KeyEntry* entry) {
- int32_t action = entry->action;
+void InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action) {
+ if (action == AKEY_EVENT_ACTION_UP
+ && (entry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
+ for (size_t i = 0; i < mFallbackKeys.size(); ) {
+ if (mFallbackKeys.valueAt(i) == entry->keyCode) {
+ mFallbackKeys.removeItemsAt(i);
+ } else {
+ i += 1;
+ }
+ }
+ }
+
for (size_t i = 0; i < mKeyMementos.size(); i++) {
KeyMemento& memento = mKeyMementos.editItemAt(i);
if (memento.deviceId == entry->deviceId
@@ -3638,17 +3878,18 @@
}
}
-void InputDispatcher::InputState::trackMotion(
- const MotionEntry* entry) {
- int32_t action = entry->action & AMOTION_EVENT_ACTION_MASK;
+void InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action) {
+ int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
for (size_t i = 0; i < mMotionMementos.size(); i++) {
MotionMemento& memento = mMotionMementos.editItemAt(i);
if (memento.deviceId == entry->deviceId
&& memento.source == entry->source) {
- switch (action) {
+ switch (actionMasked) {
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
mMotionMementos.removeAt(i);
return;
@@ -3669,7 +3910,11 @@
}
Found:
- if (action == AMOTION_EVENT_ACTION_DOWN) {
+ switch (actionMasked) {
+ case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
mMotionMementos.push();
MotionMemento& memento = mMotionMementos.editTop();
memento.deviceId = entry->deviceId;
@@ -3678,6 +3923,7 @@
memento.yPrecision = entry->yPrecision;
memento.downTime = entry->downTime;
memento.setPointers(entry);
+ memento.hovering = actionMasked != AMOTION_EVENT_ACTION_DOWN;
}
}
@@ -3691,7 +3937,7 @@
void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
Allocator* allocator, Vector<EventEntry*>& outEvents,
- CancelationOptions options) {
+ const CancelationOptions& options) {
for (size_t i = 0; i < mKeyMementos.size(); ) {
const KeyMemento& memento = mKeyMementos.itemAt(i);
if (shouldCancelKey(memento, options)) {
@@ -3710,7 +3956,10 @@
if (shouldCancelMotion(memento, options)) {
outEvents.push(allocator->obtainMotionEntry(currentTime,
memento.deviceId, memento.source, 0,
- AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
+ memento.hovering
+ ? AMOTION_EVENT_ACTION_HOVER_EXIT
+ : AMOTION_EVENT_ACTION_CANCEL,
+ 0, 0, 0,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.pointerCount, memento.pointerIds, memento.pointerCoords));
mMotionMementos.removeAt(i);
@@ -3723,6 +3972,7 @@
void InputDispatcher::InputState::clear() {
mKeyMementos.clear();
mMotionMementos.clear();
+ mFallbackKeys.clear();
}
void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
@@ -3743,13 +3993,36 @@
}
}
+int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) {
+ ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
+ return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
+}
+
+void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode,
+ int32_t fallbackKeyCode) {
+ ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
+ if (index >= 0) {
+ mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
+ } else {
+ mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
+ }
+}
+
+void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) {
+ mFallbackKeys.removeItem(originalKeyCode);
+}
+
bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
- CancelationOptions options) {
- switch (options) {
- case CANCEL_ALL_EVENTS:
- case CANCEL_NON_POINTER_EVENTS:
+ const CancelationOptions& options) {
+ if (options.keyCode != -1 && memento.keyCode != options.keyCode) {
+ return false;
+ }
+
+ switch (options.mode) {
+ case CancelationOptions::CANCEL_ALL_EVENTS:
+ case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
return true;
- case CANCEL_FALLBACK_EVENTS:
+ case CancelationOptions::CANCEL_FALLBACK_EVENTS:
return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
default:
return false;
@@ -3757,13 +4030,13 @@
}
bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
- CancelationOptions options) {
- switch (options) {
- case CANCEL_ALL_EVENTS:
+ const CancelationOptions& options) {
+ switch (options.mode) {
+ case CancelationOptions::CANCEL_ALL_EVENTS:
return true;
- case CANCEL_POINTER_EVENTS:
+ case CancelationOptions::CANCEL_POINTER_EVENTS:
return memento.source & AINPUT_SOURCE_CLASS_POINTER;
- case CANCEL_NON_POINTER_EVENTS:
+ case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
default:
return false;
@@ -3777,8 +4050,7 @@
const sp<InputWindowHandle>& inputWindowHandle) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
inputPublisher(inputChannel),
- lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX),
- originalKeyCodeForFallback(-1) {
+ lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
}
InputDispatcher::Connection::~Connection() {
@@ -3876,12 +4148,15 @@
touchedWindow.channel = window->inputChannel;
}
-void InputDispatcher::TouchState::removeOutsideTouchWindows() {
+void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
for (size_t i = 0 ; i < windows.size(); ) {
- if (windows[i].targetFlags & InputTarget::FLAG_OUTSIDE) {
- windows.removeAt(i);
- } else {
+ TouchedWindow& window = windows.editItemAt(i);
+ if (window.targetFlags & InputTarget::FLAG_DISPATCH_AS_IS) {
+ window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
+ window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
i += 1;
+ } else {
+ windows.removeAt(i);
}
}
}
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 1e118c4..48e4d43 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -86,20 +86,40 @@
struct InputTarget {
enum {
/* This flag indicates that the event is being delivered to a foreground application. */
- FLAG_FOREGROUND = 0x01,
-
- /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
- * of the area of this target and so should instead be delivered as an
- * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
- FLAG_OUTSIDE = 0x02,
+ FLAG_FOREGROUND = 1 << 0,
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
- FLAG_WINDOW_IS_OBSCURED = 0x04,
+ FLAG_WINDOW_IS_OBSCURED = 1 << 1,
/* This flag indicates that a motion event is being split across multiple windows. */
- FLAG_SPLIT = 0x08,
+ FLAG_SPLIT = 1 << 2,
+
+ /* This flag indicates that the event should be sent as is.
+ * Should always be set unless the event is to be transmuted. */
+ FLAG_DISPATCH_AS_IS = 1 << 8,
+
+ /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
+ * of the area of this target and so should instead be delivered as an
+ * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
+ FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
+
+ /* This flag indicates that a hover sequence is starting in the given window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
+
+ /* This flag indicates that a hover event happened outside of a window which handled
+ * previous hover events, signifying the end of the current hover sequence for that
+ * window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
+
+ /* Mask for all dispatch modes. */
+ FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS
+ | FLAG_DISPATCH_AS_OUTSIDE
+ | FLAG_DISPATCH_AS_HOVER_ENTER
+ | FLAG_DISPATCH_AS_HOVER_EXIT,
};
// The input channel to be targeted.
@@ -567,6 +587,7 @@
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
void releaseKeyEntry(KeyEntry* entry);
void releaseMotionEntry(MotionEntry* entry);
+ void freeMotionSample(MotionSample* sample);
void releaseDispatchEntry(DispatchEntry* entry);
void releaseCommandEntry(CommandEntry* entry);
@@ -589,18 +610,32 @@
void releaseEventEntryInjectionState(EventEntry* entry);
};
- /* Tracks dispatched key and motion event state so that cancelation events can be
- * synthesized when events are dropped. */
- class InputState {
- public:
- // Specifies the sources to cancel.
- enum CancelationOptions {
+ /* Specifies which events are to be canceled and why. */
+ struct CancelationOptions {
+ enum Mode {
CANCEL_ALL_EVENTS = 0,
CANCEL_POINTER_EVENTS = 1,
CANCEL_NON_POINTER_EVENTS = 2,
CANCEL_FALLBACK_EVENTS = 3,
};
+ // The criterion to use to determine which events should be canceled.
+ Mode mode;
+
+ // Descriptive reason for the cancelation.
+ const char* reason;
+
+ // The specific keycode of the key event to cancel, or -1 to cancel any key event.
+ int32_t keyCode;
+
+ CancelationOptions(Mode mode, const char* reason) :
+ mode(mode), reason(reason), keyCode(-1) { }
+ };
+
+ /* Tracks dispatched key and motion event state so that cancelation events can be
+ * synthesized when events are dropped. */
+ class InputState {
+ public:
InputState();
~InputState();
@@ -608,17 +643,17 @@
bool isNeutral() const;
// Records tracking information for an event that has just been published.
- void trackEvent(const EventEntry* entry);
+ void trackEvent(const EventEntry* entry, int32_t action);
// Records tracking information for a key event that has just been published.
- void trackKey(const KeyEntry* entry);
+ void trackKey(const KeyEntry* entry, int32_t action);
// Records tracking information for a motion event that has just been published.
- void trackMotion(const MotionEntry* entry);
+ void trackMotion(const MotionEntry* entry, int32_t action);
// Synthesizes cancelation events for the current state and resets the tracked state.
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
- Vector<EventEntry*>& outEvents, CancelationOptions options);
+ Vector<EventEntry*>& outEvents, const CancelationOptions& options);
// Clears the current state.
void clear();
@@ -626,6 +661,21 @@
// Copies pointer-related parts of the input state to another instance.
void copyPointerStateTo(InputState& other) const;
+ // Gets the fallback key associated with a keycode.
+ // Returns -1 if none.
+ // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy.
+ int32_t getFallbackKey(int32_t originalKeyCode);
+
+ // Sets the fallback key for a particular keycode.
+ void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode);
+
+ // Removes the fallback key for a particular keycode.
+ void removeFallbackKey(int32_t originalKeyCode);
+
+ inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const {
+ return mFallbackKeys;
+ }
+
private:
struct KeyMemento {
int32_t deviceId;
@@ -645,17 +695,19 @@
uint32_t pointerCount;
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
+ bool hovering;
void setPointers(const MotionEntry* entry);
};
Vector<KeyMemento> mKeyMementos;
Vector<MotionMemento> mMotionMementos;
+ KeyedVector<int32_t, int32_t> mFallbackKeys;
static bool shouldCancelKey(const KeyMemento& memento,
- CancelationOptions options);
+ const CancelationOptions& options);
static bool shouldCancelMotion(const MotionMemento& memento,
- CancelationOptions options);
+ const CancelationOptions& options);
};
/* Manages the dispatch state associated with a single input channel. */
@@ -682,7 +734,6 @@
nsecs_t lastEventTime; // the time when the event was originally captured
nsecs_t lastDispatchTime; // the time when the last event was dispatched
- int32_t originalKeyCodeForFallback; // original keycode for fallback in progress, -1 if none
explicit Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle);
@@ -839,7 +890,7 @@
void reset();
void copyFrom(const TouchState& other);
void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);
- void removeOutsideTouchWindows();
+ void filterNonAsIsTouchWindows();
const InputWindow* getFirstForegroundWindow();
};
@@ -882,6 +933,9 @@
bool mInputTargetWaitTimeoutExpired;
sp<InputApplicationHandle> mInputTargetWaitApplication;
+ // Contains the last window which received a hover event.
+ const InputWindow* mLastHoverWindow;
+
// Finding targets for input events.
void resetTargetsLocked();
void commitTargetsLocked();
@@ -896,7 +950,8 @@
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
nsecs_t* nextWakeupTime);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
- nsecs_t* nextWakeupTime, bool* outConflictingPointerActions);
+ nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
+ const MotionSample** outSplitBatchAfterSample);
void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
BitSet32 pointerIds);
@@ -915,6 +970,9 @@
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample);
+ void enqueueDispatchEntryLocked(const sp<Connection>& connection,
+ EventEntry* eventEntry, const InputTarget* inputTarget,
+ bool resumeWithAppendedMotionSample, int32_t dispatchMode);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool handled);
@@ -924,11 +982,11 @@
static int handleReceiveCallback(int receiveFd, int events, void* data);
void synthesizeCancelationEventsForAllConnectionsLocked(
- InputState::CancelationOptions options, const char* reason);
+ const CancelationOptions& options);
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
- InputState::CancelationOptions options, const char* reason);
+ const CancelationOptions& options);
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
- InputState::CancelationOptions options, const char* reason);
+ const CancelationOptions& options);
// Splitting motion events across windows.
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 94753bf..82cf62f 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -1605,8 +1605,15 @@
motionEventAction, 0, metaState, motionEventEdgeFlags,
1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
- mAccumulator.clear();
+ // Send hover move after UP to tell the application that the mouse is hovering now.
+ if (motionEventAction == AMOTION_EVENT_ACTION_UP
+ && mPointerController != NULL) {
+ getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
+ }
+ // Send scroll events.
if (vscroll != 0 || hscroll != 0) {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
@@ -1615,6 +1622,8 @@
AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
}
+
+ mAccumulator.clear();
}
int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index 799eb76..cabbccb 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -15,7 +15,6 @@
libhardware \
libhardware_legacy \
libui \
- libsurfaceflinger_client \
libskia \
libstlport \
libinput
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index a4a95a0..c03b994 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -541,7 +541,9 @@
IRemoteViewsFactory.Stub.asInterface(service);
try {
cb.onDestroy(intent);
- } catch (Exception e) {
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (RuntimeException e) {
e.printStackTrace();
}
mContext.unbindService(this);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 1ab22c0..12ac052 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1409,10 +1409,13 @@
if (TextUtils.isEmpty(interfaceName)) return;
for (InetAddress gateway : p.getGateways()) {
- if (!NetworkUtils.addDefaultRoute(interfaceName, gateway) && DBG) {
- NetworkInfo networkInfo = nt.getNetworkInfo();
- log("addDefaultRoute for " + networkInfo.getTypeName() +
- " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+ if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
+ NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+ if (DBG) {
+ NetworkInfo networkInfo = nt.getNetworkInfo();
+ log("addDefaultRoute for " + networkInfo.getTypeName() +
+ " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+ }
}
}
}
@@ -1424,10 +1427,12 @@
String interfaceName = p.getInterfaceName();
if (interfaceName != null) {
- if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) {
- NetworkInfo networkInfo = nt.getNetworkInfo();
- log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
- interfaceName + ")");
+ if (NetworkUtils.removeDefaultRoute(interfaceName) >= 0) {
+ if (DBG) {
+ NetworkInfo networkInfo = nt.getNetworkInfo();
+ log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
+ interfaceName + ")");
+ }
}
}
}
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index b0d2158..fc5443e 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -56,7 +56,7 @@
* settings parameter with a default value of 2MB), the free memory is
* logged to the event log.
*/
-class DeviceStorageMonitorService extends Binder {
+public class DeviceStorageMonitorService extends Binder {
private static final String TAG = "DeviceStorageMonitorService";
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
@@ -99,7 +99,7 @@
/**
* This string is used for ServiceManager access to this class.
*/
- static final String SERVICE = "devicestoragemonitor";
+ public static final String SERVICE = "devicestoragemonitor";
/**
* Handler that checks the amount of disk space on the device and sends a
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 91ada6b..4e80147 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -18,6 +18,7 @@
import com.android.internal.app.IMediaContainerService;
import com.android.server.am.ActivityManagerService;
+import com.android.server.pm.PackageManagerService;
import android.Manifest;
import android.content.BroadcastReceiver;
@@ -86,6 +87,9 @@
private static final String VOLD_TAG = "VoldConnector";
+ /** Maximum number of ASEC containers allowed to be mounted. */
+ private static final int MAX_CONTAINERS = 250;
+
/*
* Internal vold volume state constants
*/
@@ -483,7 +487,6 @@
}
}
};
-
private final class MountServiceBinderListener implements IBinder.DeathRecipient {
final IMountServiceListener mListener;
@@ -1087,8 +1090,7 @@
* amount of containers we'd ever expect to have. This keeps an
* "asec list" from blocking a thread repeatedly.
*/
- mConnector = new NativeDaemonConnector(this, "vold",
- PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
+ mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG);
mReady = false;
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d160963..4e1bbac 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.server.am.ActivityManagerService;
+import com.android.server.pm.PackageManagerService;
import com.android.server.usb.UsbService;
import com.android.server.wm.WindowManagerService;
import com.android.internal.app.ShutdownThread;
diff --git a/services/java/com/android/server/pm/BasePermission.java b/services/java/com/android/server/pm/BasePermission.java
new file mode 100644
index 0000000..4f27408
--- /dev/null
+++ b/services/java/com/android/server/pm/BasePermission.java
@@ -0,0 +1,59 @@
+/*
+ * 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 com.android.server.pm;
+
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+
+final class BasePermission {
+ final static int TYPE_NORMAL = 0;
+
+ final static int TYPE_BUILTIN = 1;
+
+ final static int TYPE_DYNAMIC = 2;
+
+ final String name;
+
+ String sourcePackage;
+
+ PackageSettingBase packageSetting;
+
+ final int type;
+
+ int protectionLevel;
+
+ PackageParser.Permission perm;
+
+ PermissionInfo pendingInfo;
+
+ int uid;
+
+ int[] gids;
+
+ BasePermission(String _name, String _sourcePackage, int _type) {
+ name = _name;
+ sourcePackage = _sourcePackage;
+ type = _type;
+ // Default to most conservative protection level.
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ public String toString() {
+ return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
+ + "}";
+ }
+}
diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/java/com/android/server/pm/GrantedPermissions.java
new file mode 100644
index 0000000..c7629b9
--- /dev/null
+++ b/services/java/com/android/server/pm/GrantedPermissions.java
@@ -0,0 +1,50 @@
+/*
+ * 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.server.pm;
+
+import android.content.pm.ApplicationInfo;
+
+import java.util.HashSet;
+
+class GrantedPermissions {
+ int pkgFlags;
+
+ HashSet<String> grantedPermissions = new HashSet<String>();
+
+ int[] gids;
+
+ GrantedPermissions(int pkgFlags) {
+ setFlags(pkgFlags);
+ }
+
+ @SuppressWarnings("unchecked")
+ GrantedPermissions(GrantedPermissions base) {
+ pkgFlags = base.pkgFlags;
+ grantedPermissions = (HashSet<String>) base.grantedPermissions.clone();
+
+ if (base.gids != null) {
+ gids = base.gids.clone();
+ }
+ }
+
+ void setFlags(int pkgFlags) {
+ this.pkgFlags = pkgFlags
+ & (ApplicationInfo.FLAG_SYSTEM
+ | ApplicationInfo.FLAG_FORWARD_LOCK
+ | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
+ }
+}
diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/pm/Installer.java
similarity index 66%
rename from services/java/com/android/server/Installer.java
rename to services/java/com/android/server/pm/Installer.java
index 08d1b82..8d40000 100644
--- a/services/java/com/android/server/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -14,28 +14,31 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.pm;
import android.content.pm.PackageStats;
-import android.net.LocalSocketAddress;
import android.net.LocalSocket;
-import android.util.Config;
+import android.net.LocalSocketAddress;
import android.util.Slog;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.Socket;
-
class Installer {
private static final String TAG = "Installer";
- InputStream mIn;
- OutputStream mOut;
- LocalSocket mSocket;
- byte buf[] = new byte[1024];
- int buflen = 0;
+ private static final boolean LOCAL_DEBUG = true;
+
+ InputStream mIn;
+
+ OutputStream mOut;
+
+ LocalSocket mSocket;
+
+ byte buf[] = new byte[1024];
+
+ int buflen = 0;
private boolean connect() {
if (mSocket != null) {
@@ -45,8 +48,8 @@
try {
mSocket = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(
- "installd", LocalSocketAddress.Namespace.RESERVED);
+ LocalSocketAddress address = new LocalSocketAddress("installd",
+ LocalSocketAddress.Namespace.RESERVED);
mSocket.connect(address);
@@ -59,112 +62,131 @@
return true;
}
- private void disconnect() {
- Slog.i(TAG,"disconnecting...");
- try {
- if (mSocket != null) mSocket.close();
- } catch (IOException ex) { }
- try {
- if (mIn != null) mIn.close();
- } catch (IOException ex) { }
- try {
- if (mOut != null) mOut.close();
- } catch (IOException ex) { }
- mSocket = null;
- mIn = null;
- mOut = null;
- }
+ private void disconnect() {
+ Slog.i(TAG, "disconnecting...");
+ try {
+ if (mSocket != null)
+ mSocket.close();
+ } catch (IOException ex) {
+ }
+ try {
+ if (mIn != null)
+ mIn.close();
+ } catch (IOException ex) {
+ }
+ try {
+ if (mOut != null)
+ mOut.close();
+ } catch (IOException ex) {
+ }
+ mSocket = null;
+ mIn = null;
+ mOut = null;
+ }
- private boolean readBytes(byte buffer[], int len) {
- int off = 0, count;
- if (len < 0) return false;
- while (off != len) {
- try {
- count = mIn.read(buffer, off, len - off);
- if (count <= 0) {
+ private boolean readBytes(byte buffer[], int len) {
+ int off = 0, count;
+ if (len < 0)
+ return false;
+ while (off != len) {
+ try {
+ count = mIn.read(buffer, off, len - off);
+ if (count <= 0) {
Slog.e(TAG, "read error " + count);
break;
}
- off += count;
- } catch (IOException ex) {
- Slog.e(TAG,"read exception");
- break;
- }
- }
-// Slog.i(TAG, "read "+len+" bytes");
- if (off == len) return true;
- disconnect();
- return false;
- }
+ off += count;
+ } catch (IOException ex) {
+ Slog.e(TAG, "read exception");
+ break;
+ }
+ }
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "read " + len + " bytes");
+ }
+ if (off == len)
+ return true;
+ disconnect();
+ return false;
+ }
- private boolean readReply() {
- int len;
- buflen = 0;
- if (!readBytes(buf, 2)) return false;
- len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
- if ((len < 1) || (len > 1024)) {
- Slog.e(TAG,"invalid reply length ("+len+")");
- disconnect();
- return false;
- }
- if (!readBytes(buf, len)) return false;
- buflen = len;
- return true;
- }
+ private boolean readReply() {
+ int len;
+ buflen = 0;
+ if (!readBytes(buf, 2))
+ return false;
+ len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
+ if ((len < 1) || (len > 1024)) {
+ Slog.e(TAG, "invalid reply length (" + len + ")");
+ disconnect();
+ return false;
+ }
+ if (!readBytes(buf, len))
+ return false;
+ buflen = len;
+ return true;
+ }
- private boolean writeCommand(String _cmd) {
- byte[] cmd = _cmd.getBytes();
- int len = cmd.length;
- if ((len < 1) || (len > 1024)) return false;
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- try {
- mOut.write(buf, 0, 2);
- mOut.write(cmd, 0, len);
- } catch (IOException ex) {
- Slog.e(TAG,"write error");
- disconnect();
- return false;
- }
- return true;
- }
-
- private synchronized String transaction(String cmd) {
- if (!connect()) {
+ private boolean writeCommand(String _cmd) {
+ byte[] cmd = _cmd.getBytes();
+ int len = cmd.length;
+ if ((len < 1) || (len > 1024))
+ return false;
+ buf[0] = (byte) (len & 0xff);
+ buf[1] = (byte) ((len >> 8) & 0xff);
+ try {
+ mOut.write(buf, 0, 2);
+ mOut.write(cmd, 0, len);
+ } catch (IOException ex) {
+ Slog.e(TAG, "write error");
+ disconnect();
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized String transaction(String cmd) {
+ if (!connect()) {
Slog.e(TAG, "connection failed");
return "-1";
}
if (!writeCommand(cmd)) {
- /* If installd died and restarted in the background
- * (unlikely but possible) we'll fail on the next
- * write (this one). Try to reconnect and write
- * the command one more time before giving up.
- */
+ /*
+ * If installd died and restarted in the background (unlikely but
+ * possible) we'll fail on the next write (this one). Try to
+ * reconnect and write the command one more time before giving up.
+ */
Slog.e(TAG, "write command failed? reconnect!");
if (!connect() || !writeCommand(cmd)) {
return "-1";
}
}
-// Slog.i(TAG,"send: '"+cmd+"'");
- if (readReply()) {
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "send: '" + cmd + "'");
+ }
+ if (readReply()) {
String s = new String(buf, 0, buflen);
-// Slog.i(TAG,"recv: '"+s+"'");
- return s;
- } else {
-// Slog.i(TAG,"fail");
- return "-1";
- }
- }
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "recv: '" + s + "'");
+ }
+ return s;
+ } else {
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "fail");
+ }
+ return "-1";
+ }
+ }
- private int execute(String cmd) {
- String res = transaction(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
+ private int execute(String cmd) {
+ String res = transaction(cmd);
+ try {
+ return Integer.parseInt(res);
+ } catch (NumberFormatException ex) {
+ return -1;
+ }
+ }
public int install(String name, int uid, int gid) {
StringBuilder builder = new StringBuilder("install");
@@ -225,14 +247,14 @@
builder.append(name);
return execute(builder.toString());
}
-
+
public int clearUserData(String name) {
StringBuilder builder = new StringBuilder("rmuserdata");
builder.append(' ');
builder.append(name);
return execute(builder.toString());
}
-
+
public boolean ping() {
if (execute("ping") < 0) {
return false;
@@ -240,7 +262,7 @@
return true;
}
}
-
+
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
@@ -250,8 +272,8 @@
/*
* @param packagePathSuffix The name of the path relative to install
- * directory. Say if the path name is /data/app/com.test-1.apk,
- * the package suffix path will be com.test-1
+ * directory. Say if the path name is /data/app/com.test-1.apk, the package
+ * suffix path will be com.test-1
*/
public int setForwardLockPerm(String packagePathSuffix, int gid) {
StringBuilder builder = new StringBuilder("protect");
@@ -261,7 +283,7 @@
builder.append(gid);
return execute(builder.toString());
}
-
+
public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
@@ -275,7 +297,7 @@
String s = transaction(builder.toString());
String res[] = s.split(" ");
- if((res == null) || (res.length != 4)) {
+ if ((res == null) || (res.length != 4)) {
return -1;
}
try {
@@ -286,7 +308,7 @@
} catch (NumberFormatException e) {
return -1;
}
- }
+ }
public int moveFiles() {
return execute("movefiles");
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
similarity index 65%
rename from services/java/com/android/server/PackageManagerService.java
rename to services/java/com/android/server/pm/PackageManagerService.java
index 3d8dccb..669e060 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
@@ -24,13 +24,13 @@
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.server.DeviceStorageMonitorService;
+import com.android.server.EventLogTags;
+import com.android.server.IntentResolver;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
@@ -46,7 +46,6 @@
import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -96,7 +95,6 @@
import android.view.Display;
import android.view.WindowManager;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -135,15 +133,15 @@
mmm frameworks/base/tests/AndroidTests
adb install -r -f out/target/product/passion/data/app/AndroidTests.apk
adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner
- *
+ *
+ * {@hide}
*/
-class PackageManagerService extends IPackageManager.Stub {
- private static final String TAG = "PackageManager";
- private static final boolean DEBUG_SETTINGS = false;
+public class PackageManagerService extends IPackageManager.Stub {
+ static final String TAG = "PackageManager";
+ static final boolean DEBUG_SETTINGS = false;
private static final boolean DEBUG_PREFERRED = false;
- private static final boolean DEBUG_UPGRADE = false;
+ static final boolean DEBUG_UPGRADE = false;
private static final boolean DEBUG_INSTALL = false;
- private static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_REMOVE = false;
private static final boolean DEBUG_SHOW_INFO = false;
private static final boolean DEBUG_PACKAGE_INFO = false;
@@ -151,13 +149,13 @@
private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_APP_DIR_OBSERVER = false;
- private static final boolean MULTIPLE_APPLICATION_UIDS = true;
+ 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;
- private static final int FIRST_APPLICATION_UID =
+ static final int FIRST_APPLICATION_UID =
Process.FIRST_APPLICATION_UID;
- private static final int MAX_APPLICATION_UIDS = 1000;
+ static final int MAX_APPLICATION_UIDS = 1000;
private static final boolean GET_CERTIFICATES = true;
@@ -171,19 +169,6 @@
// package apks to install directory.
private static final String INSTALL_PACKAGE_SUFFIX = "-";
- /**
- * Indicates the state of installation. Used by PackageManager to
- * figure out incomplete installations. Say a package is being installed
- * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till
- * the package installation is successful or unsuccesful lin which case
- * the PackageManager will no longer maintain state information associated
- * with the package. If some exception(like device freeze or battery being
- * pulled out) occurs during installation of a package, the PackageManager
- * needs this information to clean up the previously failed installation.
- */
- private static final int PKG_INSTALL_INCOMPLETE = 0;
- private static final int PKG_INSTALL_COMPLETE = 1;
-
static final int SCAN_MONITOR = 1<<0;
static final int SCAN_NO_DEX = 1<<1;
static final int SCAN_FORCE_DEX = 1<<2;
@@ -672,7 +657,7 @@
synchronized (mPackages) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_STOPPED_PACKAGES);
- mSettings.writeLP();
+ mSettings.writeLPr();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
@@ -680,7 +665,7 @@
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
removeMessages(WRITE_STOPPED_PACKAGES);
- mSettings.writeStoppedLP();
+ mSettings.writeStoppedLPr();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
@@ -752,17 +737,17 @@
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings();
- mSettings.addSharedUserLP("android.uid.system",
+ mSettings.addSharedUserLPw("android.uid.system",
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLP("android.uid.phone",
+ mSettings.addSharedUserLPw("android.uid.phone",
MULTIPLE_APPLICATION_UIDS
? RADIO_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLP("android.uid.log",
+ mSettings.addSharedUserLPw("android.uid.log",
MULTIPLE_APPLICATION_UIDS
? LOG_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLP("android.uid.nfc",
+ mSettings.addSharedUserLPw("android.uid.nfc",
MULTIPLE_APPLICATION_UIDS
? NFC_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
@@ -800,6 +785,7 @@
d.getMetrics(mMetrics);
synchronized (mInstallLock) {
+ // writer
synchronized (mPackages) {
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
@@ -820,7 +806,7 @@
readPermissions();
- mRestoredSettings = mSettings.readLP();
+ mRestoredSettings = mSettings.readLPw();
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -995,7 +981,7 @@
mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
}
//look for any incomplete package installations
- ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackages();
+ ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
for(int i = 0; i < deletePkgsList.size(); i++) {
//clean up here
@@ -1036,9 +1022,10 @@
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
- updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
+ updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
- mSettings.writeLP();
+ // can downgrade to reader
+ mSettings.writeLPr();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
@@ -1088,7 +1075,7 @@
Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath);
}
}
- mSettings.removePackageLP(ps.name);
+ mSettings.removePackageLPw(ps.name);
}
void readPermissions() {
@@ -1355,6 +1342,7 @@
}
public PackageInfo getPackageInfo(String packageName, int flags) {
+ // reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO)
@@ -1363,7 +1351,7 @@
return generatePackageInfo(p, flags);
}
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- return generatePackageInfoFromSettingsLP(packageName, flags);
+ return generatePackageInfoFromSettingsLPw(packageName, flags);
}
}
return null;
@@ -1371,6 +1359,7 @@
public String[] currentToCanonicalPackageNames(String[] names) {
String[] out = new String[names.length];
+ // reader
synchronized (mPackages) {
for (int i=names.length-1; i>=0; i--) {
PackageSetting ps = mSettings.mPackages.get(names[i]);
@@ -1382,6 +1371,7 @@
public String[] canonicalToCurrentPackageNames(String[] names) {
String[] out = new String[names.length];
+ // reader
synchronized (mPackages) {
for (int i=names.length-1; i>=0; i--) {
String cur = mSettings.mRenamedPackages.get(names[i]);
@@ -1392,6 +1382,7 @@
}
public int getPackageUid(String packageName) {
+ // reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if(p != null) {
@@ -1407,6 +1398,7 @@
}
public int[] getPackageGids(String packageName) {
+ // reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO)
@@ -1435,6 +1427,7 @@
}
public PermissionInfo getPermissionInfo(String name, int flags) {
+ // reader
synchronized (mPackages) {
final BasePermission p = mSettings.mPermissions.get(name);
if (p != null) {
@@ -1445,6 +1438,7 @@
}
public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
+ // reader
synchronized (mPackages) {
ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
for (BasePermission p : mSettings.mPermissions.values()) {
@@ -1467,6 +1461,7 @@
}
public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
+ // reader
synchronized (mPackages) {
return PackageParser.generatePermissionGroupInfo(
mPermissionGroups.get(name), flags);
@@ -1474,6 +1469,7 @@
}
public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ // reader
synchronized (mPackages) {
final int N = mPermissionGroups.size();
ArrayList<PermissionGroupInfo> out
@@ -1485,12 +1481,12 @@
}
}
- private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) {
+ private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags) {
PackageSetting ps = mSettings.mPackages.get(packageName);
- if(ps != null) {
- if(ps.pkg == null) {
- PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags);
- if(pInfo != null) {
+ if (ps != null) {
+ if (ps.pkg == null) {
+ PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags);
+ if (pInfo != null) {
return pInfo.applicationInfo;
}
return null;
@@ -1500,10 +1496,10 @@
return null;
}
- private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) {
+ private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags) {
PackageSetting ps = mSettings.mPackages.get(packageName);
- if(ps != null) {
- if(ps.pkg == null) {
+ if (ps != null) {
+ if (ps.pkg == null) {
ps.pkg = new PackageParser.Package(packageName);
ps.pkg.applicationInfo.packageName = packageName;
ps.pkg.applicationInfo.flags = ps.pkgFlags;
@@ -1520,6 +1516,7 @@
}
public ApplicationInfo getApplicationInfo(String packageName, int flags) {
+ // writer
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -1533,7 +1530,7 @@
return mAndroidApplication;
}
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- return generateApplicationInfoFromSettingsLP(packageName, flags);
+ return generateApplicationInfoFromSettingsLPw(packageName, flags);
}
}
return null;
@@ -1598,7 +1595,7 @@
PackageParser.Activity a = mActivities.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledLP(a.info, flags)) {
+ if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
return PackageParser.generateActivityInfo(a, flags);
}
if (mResolveComponentName.equals(component)) {
@@ -1613,7 +1610,7 @@
PackageParser.Activity a = mReceivers.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledLP(a.info, flags)) {
+ if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
return PackageParser.generateActivityInfo(a, flags);
}
}
@@ -1625,7 +1622,7 @@
PackageParser.Service s = mServices.mServices.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
- if (s != null && mSettings.isEnabledLP(s.info, flags)) {
+ if (s != null && mSettings.isEnabledLPr(s.info, flags)) {
return PackageParser.generateServiceInfo(s, flags);
}
}
@@ -1637,7 +1634,7 @@
PackageParser.Provider p = mProvidersByComponent.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getProviderInfo " + component + ": " + p);
- if (p != null && mSettings.isEnabledLP(p.info, flags)) {
+ if (p != null && mSettings.isEnabledLPr(p.info, flags)) {
return PackageParser.generateProviderInfo(p, flags);
}
}
@@ -1701,7 +1698,7 @@
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj != null) {
GrantedPermissions gp = (GrantedPermissions)obj;
if (gp.grantedPermissions.contains(permName)) {
@@ -1806,7 +1803,7 @@
}
if (changed) {
if (!async) {
- mSettings.writeLP();
+ mSettings.writeLPr();
} else {
scheduleWriteSettingsLocked();
}
@@ -1837,7 +1834,7 @@
+ name);
}
mSettings.mPermissions.remove(name);
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
}
@@ -1850,21 +1847,22 @@
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
- PackageParser.Package p1 = mPackages.get(pkg1);
- PackageParser.Package p2 = mPackages.get(pkg2);
+ final PackageParser.Package p1 = mPackages.get(pkg1);
+ final PackageParser.Package p2 = mPackages.get(pkg2);
if (p1 == null || p1.mExtras == null
|| p2 == null || p2.mExtras == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return checkSignaturesLP(p1.mSignatures, p2.mSignatures);
+ return compareSignatures(p1.mSignatures, p2.mSignatures);
}
}
public int checkUidSignatures(int uid1, int uid2) {
+ // reader
synchronized (mPackages) {
Signature[] s1;
Signature[] s2;
- Object obj = mSettings.getUserIdLP(uid1);
+ Object obj = mSettings.getUserIdLPr(uid1);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
s1 = ((SharedUserSetting)obj).signatures.mSignatures;
@@ -1876,7 +1874,7 @@
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- obj = mSettings.getUserIdLP(uid2);
+ obj = mSettings.getUserIdLPr(uid2);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
s2 = ((SharedUserSetting)obj).signatures.mSignatures;
@@ -1888,11 +1886,11 @@
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return checkSignaturesLP(s1, s2);
+ return compareSignatures(s1, s2);
}
}
- int checkSignaturesLP(Signature[] s1, Signature[] s2) {
+ static int compareSignatures(Signature[] s1, Signature[] s2) {
if (s1 == null) {
return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
@@ -1917,20 +1915,21 @@
}
public String[] getPackagesForUid(int uid) {
+ // reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
- SharedUserSetting sus = (SharedUserSetting)obj;
+ final SharedUserSetting sus = (SharedUserSetting) obj;
final int N = sus.packages.size();
- String[] res = new String[N];
- Iterator<PackageSetting> it = sus.packages.iterator();
- int i=0;
+ final String[] res = new String[N];
+ final Iterator<PackageSetting> it = sus.packages.iterator();
+ int i = 0;
while (it.hasNext()) {
res[i++] = it.next().name;
}
return res;
} else if (obj instanceof PackageSetting) {
- PackageSetting ps = (PackageSetting)obj;
+ final PackageSetting ps = (PackageSetting) obj;
return new String[] { ps.name };
}
}
@@ -1938,13 +1937,14 @@
}
public String getNameForUid(int uid) {
+ // reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
- SharedUserSetting sus = (SharedUserSetting)obj;
+ final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.name + ":" + sus.userId;
} else if (obj instanceof PackageSetting) {
- PackageSetting ps = (PackageSetting)obj;
+ final PackageSetting ps = (PackageSetting) obj;
return ps.name;
}
}
@@ -1955,8 +1955,9 @@
if(sharedUserName == null) {
return -1;
}
+ // reader
synchronized (mPackages) {
- SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false);
+ final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
if(suid == null) {
return -1;
}
@@ -2007,6 +2008,7 @@
ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, int priority) {
+ // writer
synchronized (mPackages) {
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
List<PreferredActivity> prefs =
@@ -2017,24 +2019,35 @@
// We will only allow preferred activities that came
// from the same match quality.
int match = 0;
- final int N = query.size();
- if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match...");
- for (int j=0; j<N; j++) {
- ResolveInfo ri = query.get(j);
- if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo
- + ": 0x" + Integer.toHexString(match));
- if (ri.match > match) match = ri.match;
+
+ if (DEBUG_PREFERRED) {
+ Log.v(TAG, "Figuring out best match...");
}
- if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x"
- + Integer.toHexString(match));
+
+ final int N = query.size();
+ for (int j=0; j<N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (DEBUG_PREFERRED) {
+ Log.v(TAG, "Match for " + ri.activityInfo + ": 0x"
+ + Integer.toHexString(match));
+ }
+ if (ri.match > match) {
+ match = ri.match;
+ }
+ }
+
+ if (DEBUG_PREFERRED) {
+ Log.v(TAG, "Best match: 0x" + Integer.toHexString(match));
+ }
+
match &= IntentFilter.MATCH_CATEGORY_MASK;
final int M = prefs.size();
for (int i=0; i<M; i++) {
- PreferredActivity pa = prefs.get(i);
+ final PreferredActivity pa = prefs.get(i);
if (pa.mPref.mMatch != match) {
continue;
}
- ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags);
+ final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags);
if (DEBUG_PREFERRED) {
Log.v(TAG, "Got preferred activity:");
if (ai != null) {
@@ -2045,7 +2058,7 @@
}
if (ai != null) {
for (int j=0; j<N; j++) {
- ResolveInfo ri = query.get(j);
+ final ResolveInfo ri = query.get(j);
if (!ri.activityInfo.applicationInfo.packageName
.equals(ai.applicationInfo.packageName)) {
continue;
@@ -2077,28 +2090,28 @@
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags) {
- ComponentName comp = intent.getComponent();
+ final ComponentName comp = intent.getComponent();
if (comp != null) {
- List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- ActivityInfo ai = getActivityInfo(comp, flags);
+ final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final ActivityInfo ai = getActivityInfo(comp, flags);
if (ai != null) {
- ResolveInfo ri = new ResolveInfo();
+ final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
return list;
}
+ // reader
synchronized (mPackages) {
- String pkgName = intent.getPackage();
+ final String pkgName = intent.getPackage();
if (pkgName == null) {
- return (List<ResolveInfo>)mActivities.queryIntent(intent,
- resolvedType, flags);
+ return mActivities.queryIntent(intent, resolvedType, flags);
}
- PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
- resolvedType, flags, pkg.activities);
+ return mActivities.queryIntentForPackage(intent, resolvedType, flags,
+ pkg.activities);
}
return new ArrayList<ResolveInfo>();
}
@@ -2109,9 +2122,12 @@
String resolvedType, int flags) {
final String resultsAction = intent.getAction();
- List<ResolveInfo> results = queryIntentActivities(
- intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER);
- if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Query " + intent + ": " + results);
+ List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
+ | PackageManager.GET_RESOLVED_FILTER);
+
+ if (DEBUG_INTENT_MATCHING) {
+ Log.v(TAG, "Query " + intent + ": " + results);
+ }
int specificsPos = 0;
int N;
@@ -2131,16 +2147,21 @@
continue;
}
- if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Specific #" + i + ": " + sintent);
+ if (DEBUG_INTENT_MATCHING) {
+ Log.v(TAG, "Specific #" + i + ": " + sintent);
+ }
+
String action = sintent.getAction();
if (resultsAction != null && resultsAction.equals(action)) {
// If this action was explicitly requested, then don't
// remove things that have it.
action = null;
}
- ComponentName comp = sintent.getComponent();
+
ResolveInfo ri = null;
ActivityInfo ai = null;
+
+ ComponentName comp = sintent.getComponent();
if (comp == null) {
ri = resolveIntent(
sintent,
@@ -2265,8 +2286,7 @@
return results;
}
- public List<ResolveInfo> queryIntentReceivers(Intent intent,
- String resolvedType, int flags) {
+ public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) {
ComponentName comp = intent.getComponent();
if (comp != null) {
List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
@@ -2279,25 +2299,22 @@
return list;
}
+ // reader
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
- return (List<ResolveInfo>)mReceivers.queryIntent(intent,
- resolvedType, flags);
+ return mReceivers.queryIntent(intent, resolvedType, flags);
}
- PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent,
- resolvedType, flags, pkg.receivers);
+ return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers);
}
return null;
}
}
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- int flags) {
- List<ResolveInfo> query = queryIntentServices(intent, resolvedType,
- flags);
+ public ResolveInfo resolveService(Intent intent, String resolvedType, int flags) {
+ List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags);
if (query != null) {
if (query.size() >= 1) {
// If there is more than one service with the same priority,
@@ -2308,56 +2325,54 @@
return null;
}
- public List<ResolveInfo> queryIntentServices(Intent intent,
- String resolvedType, int flags) {
- ComponentName comp = intent.getComponent();
+ public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) {
+ final ComponentName comp = intent.getComponent();
if (comp != null) {
- List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- ServiceInfo si = getServiceInfo(comp, flags);
+ final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final ServiceInfo si = getServiceInfo(comp, flags);
if (si != null) {
- ResolveInfo ri = new ResolveInfo();
+ final ResolveInfo ri = new ResolveInfo();
ri.serviceInfo = si;
list.add(ri);
}
return list;
}
+ // reader
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
- return (List<ResolveInfo>)mServices.queryIntent(intent,
- resolvedType, flags);
+ return mServices.queryIntent(intent, resolvedType, flags);
}
- PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return (List<ResolveInfo>)mServices.queryIntentForPackage(intent,
- resolvedType, flags, pkg.services);
+ return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services);
}
return null;
}
}
public List<PackageInfo> getInstalledPackages(int flags) {
- ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
+ final ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
+ // writer
synchronized (mPackages) {
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
+ final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
while (i.hasNext()) {
final PackageSetting ps = i.next();
- PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags);
- if(psPkg != null) {
+ final PackageInfo psPkg = generatePackageInfoFromSettingsLPw(ps.name, flags);
+ if (psPkg != null) {
finalList.add(psPkg);
}
}
- }
- else {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ } else {
+ final Iterator<PackageParser.Package> i = mPackages.values().iterator();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
if (p.applicationInfo != null) {
- PackageInfo pi = generatePackageInfo(p, flags);
- if(pi != null) {
+ final PackageInfo pi = generatePackageInfo(p, flags);
+ if (pi != null) {
finalList.add(pi);
}
}
@@ -2368,20 +2383,20 @@
}
public List<ApplicationInfo> getInstalledApplications(int flags) {
- ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ // writer
synchronized(mPackages) {
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
+ final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
while (i.hasNext()) {
final PackageSetting ps = i.next();
- ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags);
+ ApplicationInfo ai = generateApplicationInfoFromSettingsLPw(ps.name, flags);
if(ai != null) {
finalList.add(ai);
}
}
- }
- else {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ } else {
+ final Iterator<PackageParser.Package> i = mPackages.values().iterator();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
if (p.applicationInfo != null) {
@@ -2397,12 +2412,13 @@
}
public List<ApplicationInfo> getPersistentApplications(int flags) {
- ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ // reader
synchronized (mPackages) {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ final Iterator<PackageParser.Package> i = mPackages.values().iterator();
while (i.hasNext()) {
- PackageParser.Package p = i.next();
+ final PackageParser.Package p = i.next();
if (p.applicationInfo != null
&& (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
&& (!mSafeMode || isSystemApp(p))) {
@@ -2415,10 +2431,11 @@
}
public ProviderInfo resolveContentProvider(String name, int flags) {
+ // reader
synchronized (mPackages) {
final PackageParser.Provider provider = mProviders.get(name);
return provider != null
- && mSettings.isEnabledLP(provider.info, flags)
+ && mSettings.isEnabledLPr(provider.info, flags)
&& (!mSafeMode || (provider.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)
? PackageParser.generateProviderInfo(provider, flags)
@@ -2431,9 +2448,10 @@
*/
@Deprecated
public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
+ // reader
synchronized (mPackages) {
- Iterator<Map.Entry<String, PackageParser.Provider>> i
- = mProviders.entrySet().iterator();
+ final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
+ .iterator();
while (i.hasNext()) {
Map.Entry<String, PackageParser.Provider> entry = i.next();
@@ -2453,22 +2471,22 @@
int uid, int flags) {
ArrayList<ProviderInfo> finalList = null;
+ // reader
synchronized (mPackages) {
- Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
+ final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
while (i.hasNext()) {
- PackageParser.Provider p = i.next();
+ final PackageParser.Provider p = i.next();
if (p.info.authority != null
- && (processName == null ||
- (p.info.processName.equals(processName)
- && p.info.applicationInfo.uid == uid))
- && mSettings.isEnabledLP(p.info, flags)
- && (!mSafeMode || (p.info.applicationInfo.flags
- &ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ && (processName == null
+ || (p.info.processName.equals(processName)
+ && p.info.applicationInfo.uid == uid))
+ && mSettings.isEnabledLPr(p.info, flags)
+ && (!mSafeMode
+ || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
- finalList.add(PackageParser.generateProviderInfo(p,
- flags));
+ finalList.add(PackageParser.generateProviderInfo(p, flags));
}
}
}
@@ -2482,6 +2500,7 @@
public InstrumentationInfo getInstrumentationInfo(ComponentName name,
int flags) {
+ // reader
synchronized (mPackages) {
final PackageParser.Instrumentation i = mInstrumentation.get(name);
return PackageParser.generateInstrumentationInfo(i, flags);
@@ -2493,10 +2512,11 @@
ArrayList<InstrumentationInfo> finalList =
new ArrayList<InstrumentationInfo>();
+ // reader
synchronized (mPackages) {
- Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
+ final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
while (i.hasNext()) {
- PackageParser.Instrumentation p = i.next();
+ final PackageParser.Instrumentation p = i.next();
if (targetPackage == null
|| targetPackage.equals(p.info.targetPackage)) {
finalList.add(PackageParser.generateInstrumentationInfo(p,
@@ -2545,7 +2565,7 @@
return fname;
}
- private static void reportSettingsProblem(int priority, String msg) {
+ static void reportSettingsProblem(int priority, String msg) {
try {
File fname = getSettingsProblemFile();
FileOutputStream out = new FileOutputStream(fname, true);
@@ -2609,17 +2629,18 @@
}
PackageSetting ps = null;
PackageSetting updatedPkg;
+ // reader
synchronized (mPackages) {
// Look to see if we already know about this package.
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
- ps = mSettings.peekPackageLP(oldName);
+ ps = mSettings.peekPackageLPr(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
- ps = mSettings.peekPackageLP(pkg.packageName);
+ ps = mSettings.peekPackageLPr(pkg.packageName);
}
// Check to see if this package could be hiding/updating a system
// package. Must look for it either under the original or real
@@ -2648,6 +2669,7 @@
// At this point, its safely assumed that package installation for
// apps in system partition will go through. If not there won't be a working
// version of the app
+ // writer
synchronized (mPackages) {
// Just remove the loaded entries from package lists.
mPackages.remove(ps.name);
@@ -2659,7 +2681,7 @@
InstallArgs args = new FileInstallArgs(ps.codePathString,
ps.resourcePathString, ps.nativeLibraryPathString);
args.cleanUpResourcesLI();
- mSettings.enableSystemPackageLP(ps.name);
+ mSettings.enableSystemPackageLPw(ps.name);
}
}
}
@@ -2717,7 +2739,7 @@
PackageParser.Package pkg) {
if (pkgSetting.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
- if (checkSignaturesLP(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
+ if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
PackageManager.SIGNATURE_MATCH) {
Slog.e(TAG, "Package " + pkg.packageName
+ " signatures do not match the previously installed version; ignoring!");
@@ -2727,7 +2749,7 @@
}
// Check for shared user signatures
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
- if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no signatures that match those in shared user "
@@ -2794,7 +2816,7 @@
return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
}
- private boolean verifyPackageUpdate(PackageSetting oldPkg, PackageParser.Package newPkg) {
+ private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
+ " to " + newPkg.packageName
@@ -2895,6 +2917,7 @@
pkg.mAdoptPermissions = null;
}
+ // writer
synchronized (mPackages) {
// Check all shared libraries and map to their actual file path.
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
@@ -2905,7 +2928,7 @@
int num = 0;
int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
for (int i=0; i<N; i++) {
- String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
+ final String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
if (file == null) {
Slog.e(TAG, "Package " + pkg.packageName
+ " requires unavailable shared library "
@@ -2918,7 +2941,7 @@
}
N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
for (int i=0; i<N; i++) {
- String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
+ final String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
if (file == null) {
Slog.w(TAG, "Package " + pkg.packageName
+ " desires unavailable shared library "
@@ -2936,7 +2959,7 @@
}
if (pkg.mSharedUserId != null) {
- suid = mSettings.getSharedUserLP(pkg.mSharedUserId,
+ suid = mSettings.getSharedUserLPw(pkg.mSharedUserId,
pkg.applicationInfo.flags, true);
if (suid == null) {
Slog.w(TAG, "Creating application package " + pkg.packageName
@@ -2957,7 +2980,7 @@
if (pkg.mOriginalPackages != null) {
// This package may need to be renamed to a previously
// installed name. Let's check on that...
- String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
+ final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
if (pkg.mOriginalPackages.contains(renamed)) {
// This package had originally been installed as the
// original name, and we have already taken care of
@@ -2973,11 +2996,11 @@
} else {
for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
- if ((origPackage=mSettings.peekPackageLP(
+ if ((origPackage = mSettings.peekPackageLPr(
pkg.mOriginalPackages.get(i))) != null) {
// We do have the package already installed under its
// original name... should we use it?
- if (!verifyPackageUpdate(origPackage, pkg)) {
+ if (!verifyPackageUpdateLPr(origPackage, pkg)) {
// New package is not compatible with original.
origPackage = null;
continue;
@@ -3008,7 +3031,7 @@
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
- pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile,
+ pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
pkg.applicationInfo.flags, true, false);
if (pkgSetting == null) {
@@ -3061,7 +3084,7 @@
// associated with an overall shared user, which doesn't seem all
// that unreasonable.
if (pkgSetting.sharedUser != null) {
- if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
@@ -3100,25 +3123,25 @@
}
}
}
- }
- final String pkgName = pkg.packageName;
-
- if (pkg.mAdoptPermissions != null) {
- // This package wants to adopt ownership of permissions from
- // another package.
- for (int i=pkg.mAdoptPermissions.size()-1; i>=0; i--) {
- String origName = pkg.mAdoptPermissions.get(i);
- PackageSetting orig = mSettings.peekPackageLP(origName);
- if (orig != null) {
- if (verifyPackageUpdate(orig, pkg)) {
- Slog.i(TAG, "Adopting permissions from "
- + origName + " to " + pkg.packageName);
- mSettings.transferPermissions(origName, pkg.packageName);
+ if (pkg.mAdoptPermissions != null) {
+ // This package wants to adopt ownership of permissions from
+ // another package.
+ for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
+ final String origName = pkg.mAdoptPermissions.get(i);
+ final PackageSetting orig = mSettings.peekPackageLPr(origName);
+ if (orig != null) {
+ if (verifyPackageUpdateLPr(orig, pkg)) {
+ Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ + pkg.packageName);
+ mSettings.transferPermissionsLPw(origName, pkg.packageName);
+ }
}
}
}
}
+
+ final String pkgName = pkg.packageName;
final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
@@ -3186,6 +3209,7 @@
+ " has mismatched uid: "
+ mOutPermissions[1] + " on disk, "
+ pkg.applicationInfo.uid + " in settings";
+ // writer
synchronized (mPackages) {
mSettings.mReadMessages.append(msg);
mSettings.mReadMessages.append('\n');
@@ -3319,13 +3343,14 @@
pkg.applicationInfo.uid);
}
+ // writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
mAppDirs.put(pkg.mPath, pkg);
}
// Add the new setting to mSettings
- mSettings.insertPackageSettingLP(pkgSetting, pkg);
+ mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
@@ -3624,8 +3649,9 @@
Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
}
+ // writer
synchronized (mPackages) {
- clearPackagePreferredActivitiesLP(pkg.packageName);
+ clearPackagePreferredActivitiesLPw(pkg.packageName);
mPackages.remove(pkg.applicationInfo.packageName);
if (pkg.mPath != null) {
@@ -3783,14 +3809,13 @@
return false;
}
- private void updatePermissionsLP(String changingPkg,
+ private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, boolean grantPermissions,
boolean replace, boolean replaceAll) {
// Make sure there are no dangling permission trees.
- Iterator<BasePermission> it = mSettings.mPermissionTrees
- .values().iterator();
+ Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
- BasePermission bp = it.next();
+ final BasePermission bp = it.next();
if (bp.packageSetting == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
@@ -3814,13 +3839,13 @@
// and make sure there are no dangling permissions.
it = mSettings.mPermissions.values().iterator();
while (it.hasNext()) {
- BasePermission bp = it.next();
+ final BasePermission bp = it.next();
if (bp.type == BasePermission.TYPE_DYNAMIC) {
if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+ bp.name + " pkg=" + bp.sourcePackage
+ " info=" + bp.pendingInfo);
if (bp.packageSetting == null && bp.pendingInfo != null) {
- BasePermission tree = findPermissionTreeLP(bp.name);
+ final BasePermission tree = findPermissionTreeLP(bp.name);
if (tree != null) {
bp.packageSetting = tree.packageSetting;
bp.perm = new PackageParser.Permission(tree.perm.owner,
@@ -3855,18 +3880,18 @@
if (grantPermissions) {
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
- grantPermissionsLP(pkg, replaceAll);
+ grantPermissionsLPw(pkg, replaceAll);
}
}
}
if (pkgInfo != null) {
- grantPermissionsLP(pkgInfo, replace);
+ grantPermissionsLPw(pkgInfo, replace);
}
}
- private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
- final PackageSetting ps = (PackageSetting)pkg.mExtras;
+ private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
@@ -3887,8 +3912,8 @@
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
- String name = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(name);
+ final String name = pkg.requestedPermissions.get(i);
+ final BasePermission bp = mSettings.mPermissions.get(name);
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
@@ -3906,10 +3931,10 @@
allowed = false;
} else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
|| bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
- allowed = (checkSignaturesLP(
+ allowed = (compareSignatures(
bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
- || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
+ || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (!allowed && bp.protectionLevel
== PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
@@ -3917,8 +3942,8 @@
// For updated system applications, the signatureOrSystem permission
// is granted only if it had been defined by the original application.
if (isUpdatedSystemApp(pkg)) {
- PackageSetting sysPs = mSettings.getDisabledSystemPkg(
- pkg.packageName);
+ final PackageSetting sysPs = mSettings
+ .getDisabledSystemPkgLPr(pkg.packageName);
final GrantedPermissions origGp = sysPs.sharedUser != null
? sysPs.sharedUser : sysPs;
if (origGp.grantedPermissions.contains(perm)) {
@@ -4129,7 +4154,7 @@
@Override
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
int match) {
- if (!mSettings.isEnabledLP(info.activity.info, mFlags)) {
+ if (!mSettings.isEnabledLPr(info.activity.info, mFlags)) {
return null;
}
final PackageParser.Activity activity = info.activity;
@@ -4301,7 +4326,7 @@
protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
int match) {
final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
- if (!mSettings.isEnabledLP(info.service.info, mFlags)) {
+ if (!mSettings.isEnabledLPr(info.service.info, mFlags)) {
return null;
}
final PackageParser.Service service = info.service;
@@ -4394,7 +4419,7 @@
}
};
- private static final void sendPackageBroadcast(String action, String pkg,
+ static final void sendPackageBroadcast(String action, String pkg,
Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) {
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
@@ -4425,6 +4450,7 @@
}
public String nextPackageToClean(String lastPackage) {
+ // writer
synchronized (mPackages) {
if (!isExternalMediaAvailable()) {
// If the external storage is no longer mounted at this point,
@@ -4445,6 +4471,7 @@
}
void startCleaningPackages() {
+ // reader
synchronized (mPackages) {
if (!isExternalMediaAvailable()) {
return;
@@ -4477,6 +4504,7 @@
String addedPackage = null;
int addedUid = -1;
+ // TODO post a message to the handler to obtain serial ordering
synchronized (mInstallLock) {
String fullPathStr = null;
File fullPath = null;
@@ -4500,6 +4528,7 @@
return;
}
PackageParser.Package p = null;
+ // reader
synchronized (mPackages) {
p = mAppDirs.get(fullPathStr);
}
@@ -4521,8 +4550,14 @@
SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
System.currentTimeMillis());
if (p != null) {
+ /*
+ * TODO this seems dangerous as the package may have
+ * changed since we last acquired the mPackages
+ * lock.
+ */
+ // writer
synchronized (mPackages) {
- updatePermissionsLP(p.packageName, p,
+ updatePermissionsLPw(p.packageName, p,
p.permissions.size() > 0, false, false);
}
addedPackage = p.applicationInfo.packageName;
@@ -4531,8 +4566,9 @@
}
}
+ // reader
synchronized (mPackages) {
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
@@ -4582,6 +4618,7 @@
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
final int uid = Binder.getCallingUid();
+ // writer
synchronized (mPackages) {
PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
if (targetPackageSetting == null) {
@@ -4600,7 +4637,7 @@
}
Signature[] callerSignature;
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
callerSignature = ((SharedUserSetting)obj).signatures.mSignatures;
@@ -4616,7 +4653,7 @@
// Verify: can't set installerPackageName to a package that is
// not signed with the same cert as the caller.
if (installerPackageSetting != null) {
- if (checkSignaturesLP(callerSignature,
+ if (compareSignatures(callerSignature,
installerPackageSetting.signatures.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
throw new SecurityException(
@@ -4633,7 +4670,7 @@
// If the currently set package isn't valid, then it's always
// okay to change it.
if (setting != null) {
- if (checkSignaturesLP(callerSignature,
+ if (compareSignatures(callerSignature,
setting.signatures.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
throw new SecurityException(
@@ -4849,6 +4886,7 @@
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
+ // reader
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg != null) {
@@ -5719,7 +5757,7 @@
// First find the old package info and check signatures
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
- if (checkSignaturesLP(oldPackage.mSignatures, pkg.mSignatures)
+ if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
@@ -5805,10 +5843,12 @@
return;
}
// Restore of old package succeeded. Update permissions.
+ // writer
synchronized (mPackages) {
- updatePermissionsLP(deletedPackage.packageName, deletedPackage,
+ updatePermissionsLPw(deletedPackage.packageName, deletedPackage,
true, false, false);
- mSettings.writeLP();
+ // can downgrade to reader
+ mSettings.writeLPr();
}
Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
}
@@ -5831,6 +5871,7 @@
}
PackageParser.Package oldPkg;
PackageSetting oldPkgSetting;
+ // reader
synchronized (mPackages) {
oldPkg = mPackages.get(packageName);
oldPkgSetting = mSettings.mPackages.get(packageName);
@@ -5847,8 +5888,9 @@
res.removedInfo.removedPackage = packageName;
// Remove existing system package
removePackageLI(oldPkg, true);
+ // writer
synchronized (mPackages) {
- if (!mSettings.disableSystemPackageLP(packageName) && deletedPackage != null) {
+ if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) {
// We didn't need to disable the .apk as a current system package,
// which means we are replacing another update that is already
// installed. We need to make sure to delete the older one's .apk.
@@ -5892,11 +5934,11 @@
// Restore the old system information in Settings
synchronized(mPackages) {
if (updatedSettings) {
- mSettings.enableSystemPackageLP(packageName);
+ mSettings.enableSystemPackageLPw(packageName);
mSettings.setInstallerPackageName(packageName,
oldPkgSetting.installerPackageName);
}
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
}
@@ -5930,8 +5972,8 @@
//write settings. the installStatus will be incomplete at this stage.
//note that the new package setting would have already been
//added to mPackages. It hasn't been persisted yet.
- mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
- mSettings.writeLP();
+ mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
+ mSettings.writeLPr();
}
if ((res.returnCode = moveDexFilesLI(newPackage))
@@ -5949,16 +5991,16 @@
Log.d(TAG, "New package installed in " + newPackage.mPath);
}
synchronized (mPackages) {
- updatePermissionsLP(newPackage.packageName, newPackage,
+ updatePermissionsLPw(newPackage.packageName, newPackage,
newPackage.permissions.size() > 0, true, false);
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
- mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
+ mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
@@ -6336,7 +6378,8 @@
}
removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
- PackageSetting deletedPs;
+ final PackageSetting deletedPs;
+ // reader
synchronized (mPackages) {
deletedPs = mSettings.mPackages.get(packageName);
}
@@ -6350,23 +6393,28 @@
}
} else {
// for simulator
- PackageParser.Package pkg = mPackages.get(packageName);
- File dataDir = new File(pkg.applicationInfo.dataDir);
+ File dataDir;
+ // reader
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ dataDir = new File(pkg.applicationInfo.dataDir);
+ }
dataDir.delete();
}
schedulePackageCleaning(packageName);
}
+ // writer
synchronized (mPackages) {
if (deletedPs != null) {
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
if (outInfo != null) {
- outInfo.removedUid = mSettings.removePackageLP(packageName);
+ outInfo.removedUid = mSettings.removePackageLPw(packageName);
}
if (deletedPs != null) {
- updatePermissionsLP(deletedPs.name, null, false, false, false);
+ updatePermissionsLPw(deletedPs.name, null, false, false, false);
if (deletedPs.sharedUser != null) {
// remove permissions associated with package
- mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
+ mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
}
}
}
@@ -6381,9 +6429,10 @@
mSettings.mPreferredActivities.removeFilter(pa);
}
}
+ // can downgrade to reader
if (writeSettings) {
// Save settings now
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
}
@@ -6403,8 +6452,9 @@
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
+ // reader
synchronized (mPackages) {
- ps = mSettings.getDisabledSystemPkg(p.packageName);
+ ps = mSettings.getDisabledSystemPkgLPr(p.packageName);
}
if (ps == null) {
Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName);
@@ -6426,9 +6476,10 @@
if (!ret) {
return false;
}
+ // writer
synchronized (mPackages) {
// Reinstate the old system package
- mSettings.enableSystemPackageLP(p.packageName);
+ mSettings.enableSystemPackageLPw(p.packageName);
// Remove any native libraries from the upgraded package.
NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir);
}
@@ -6441,10 +6492,12 @@
Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
return false;
}
+ // writer
synchronized (mPackages) {
- updatePermissionsLP(newPkg.packageName, newPkg, true, true, false);
+ updatePermissionsLPw(newPkg.packageName, newPkg, true, true, false);
+ // can downgrade to reader here
if (writeSettings) {
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
return true;
@@ -6732,14 +6785,14 @@
return new ArrayList<PackageInfo>();
}
- private int getUidTargetSdkVersionLockedLP(int uid) {
- Object obj = mSettings.getUserIdLP(uid);
+ private int getUidTargetSdkVersionLockedLPr(int uid) {
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
final Iterator<PackageSetting> it = sus.packages.iterator();
while (it.hasNext()) {
- PackageSetting ps = it.next();
+ final PackageSetting ps = it.next();
if (ps.pkg != null) {
int v = ps.pkg.applicationInfo.targetSdkVersion;
if (v < vers) vers = v;
@@ -6757,11 +6810,12 @@
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity) {
+ // writer
synchronized (mPackages) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ Binder.getCallingUid());
@@ -6801,7 +6855,7 @@
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
+ Binder.getCallingUid());
@@ -6827,14 +6881,15 @@
}
public void clearPackagePreferredActivities(String packageName) {
+ final int uid = Binder.getCallingUid();
+ // writer
synchronized (mPackages) {
- int uid = Binder.getCallingUid();
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null || pkg.applicationInfo.uid != uid) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
+ Binder.getCallingUid());
@@ -6845,13 +6900,13 @@
}
}
- if (clearPackagePreferredActivitiesLP(packageName)) {
+ if (clearPackagePreferredActivitiesLPw(packageName)) {
scheduleWriteSettingsLocked();
}
}
}
- boolean clearPackagePreferredActivitiesLP(String packageName) {
+ boolean clearPackagePreferredActivitiesLPw(String packageName) {
boolean changed = false;
Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
while (it.hasNext()) {
@@ -6868,10 +6923,11 @@
List<ComponentName> outActivities, String packageName) {
int num = 0;
+ // reader
synchronized (mPackages) {
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
+ final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
while (it.hasNext()) {
- PreferredActivity pa = it.next();
+ final PreferredActivity pa = it.next();
if (packageName == null
|| pa.mPref.mComponent.getPackageName().equals(packageName)) {
if (outFilters != null) {
@@ -6916,6 +6972,8 @@
String componentName = isApp ? packageName : className;
int packageUid = -1;
ArrayList<String> components;
+
+ // writer
synchronized (mPackages) {
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
@@ -6945,17 +7003,17 @@
// We're dealing with a component level state change
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
- if (!pkgSetting.enableComponentLP(className)) {
+ if (!pkgSetting.enableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DISABLED:
- if (!pkgSetting.disableComponentLP(className)) {
+ if (!pkgSetting.disableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
- if (!pkgSetting.restoreComponentLP(className)) {
+ if (!pkgSetting.restoreComponentLPw(className)) {
return;
}
break;
@@ -6964,10 +7022,10 @@
return;
}
}
- mSettings.writeLP();
+ mSettings.writeLPr();
packageUid = pkgSetting.userId;
components = mPendingBroadcasts.get(packageName);
- boolean newPackage = components == null;
+ final boolean newPackage = components == null;
if (newPackage) {
components = new ArrayList<String>();
}
@@ -7017,72 +7075,37 @@
}
public void setPackageStoppedState(String packageName, boolean stopped) {
- PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ // writer
synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- if (!allowedByPermission && (uid != pkgSetting.userId)) {
- throw new SecurityException(
- "Permission Denial: attempt to change stopped state from pid="
- + Binder.getCallingPid()
- + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
- }
- if (DEBUG_STOPPED && stopped) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.i(TAG, "Stopping package " + packageName, e);
- }
- if (pkgSetting.stopped != stopped) {
- pkgSetting.stopped = stopped;
- pkgSetting.pkg.mSetStopped = stopped;
- if (pkgSetting.notLaunched) {
- if (pkgSetting.installerPackageName != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
- pkgSetting.name, null,
- pkgSetting.installerPackageName, null);
- }
- pkgSetting.notLaunched = false;
- }
+ if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
+ uid)) {
scheduleWriteStoppedPackagesLocked();
}
}
}
public String getInstallerPackageName(String packageName) {
+ // reader
synchronized (mPackages) {
- PackageSetting pkg = mSettings.mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return pkg.installerPackageName;
+ return mSettings.getInstallerPackageNameLPr(packageName);
}
}
- public int getApplicationEnabledSetting(String appPackageName) {
+ public int getApplicationEnabledSetting(String packageName) {
+ // reader
synchronized (mPackages) {
- PackageSetting pkg = mSettings.mPackages.get(appPackageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + appPackageName);
- }
- return pkg.enabled;
+ return mSettings.getApplicationEnabledSettingLPr(packageName);
}
}
public int getComponentEnabledSetting(ComponentName componentName) {
+ // reader
synchronized (mPackages) {
- final String packageNameStr = componentName.getPackageName();
- PackageSetting pkg = mSettings.mPackages.get(packageNameStr);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown component: " + componentName);
- }
- final String classNameStr = componentName.getClassName();
- return pkg.currentEnabledStateLP(classNameStr);
+ return mSettings.getComponentEnabledSettingLPr(componentName);
}
}
@@ -7126,6 +7149,76 @@
return buf.toString();
}
+ static class DumpState {
+ public static final int DUMP_LIBS = 1 << 0;
+
+ public static final int DUMP_FEATURES = 1 << 1;
+
+ public static final int DUMP_RESOLVERS = 1 << 2;
+
+ public static final int DUMP_PERMISSIONS = 1 << 3;
+
+ public static final int DUMP_PACKAGES = 1 << 4;
+
+ public static final int DUMP_SHARED_USERS = 1 << 5;
+
+ public static final int DUMP_MESSAGES = 1 << 6;
+
+ public static final int DUMP_PROVIDERS = 1 << 7;
+
+ public static final int OPTION_SHOW_FILTERS = 1 << 0;
+
+ private int mTypes;
+
+ private int mOptions;
+
+ private boolean mTitlePrinted;
+
+ private SharedUserSetting mSharedUser;
+
+ public boolean isDumping(int type) {
+ if (mTypes == 0) {
+ return true;
+ }
+
+ return (mTypes & type) != 0;
+ }
+
+ public void setDump(int type) {
+ mTypes |= type;
+ }
+
+ public boolean isOptionEnabled(int option) {
+ return (mOptions & option) != 0;
+ }
+
+ public void setOptionEnabled(int option) {
+ mOptions |= option;
+ }
+
+ public boolean onTitlePrinted() {
+ final boolean printed = mTitlePrinted;
+ mTitlePrinted = true;
+ return printed;
+ }
+
+ public boolean getTitlePrinted() {
+ return mTitlePrinted;
+ }
+
+ public void setTitlePrinted(boolean enabled) {
+ mTitlePrinted = enabled;
+ }
+
+ public SharedUserSetting getSharedUser() {
+ return mSharedUser;
+ }
+
+ public void setSharedUser(SharedUserSetting user) {
+ mSharedUser = user;
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -7138,18 +7231,9 @@
return;
}
- boolean dumpStar = true;
- boolean dumpLibs = false;
- boolean dumpFeatures = false;
- boolean dumpResolvers = false;
- boolean dumpPermissions = false;
- boolean dumpPackages = false;
- boolean dumpSharedUsers = false;
- boolean dumpMessages = false;
- boolean dumpProviders = false;
+ DumpState dumpState = new DumpState();
String packageName = null;
- boolean showFilters = false;
int opti = 0;
while (opti < args.length) {
@@ -7177,7 +7261,7 @@
pw.println(" <package.name>: info about given package");
return;
} else if ("-f".equals(opt)) {
- showFilters = true;
+ dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
}
@@ -7191,40 +7275,31 @@
if ("android".equals(cmd) || cmd.contains(".")) {
packageName = cmd;
} else if ("l".equals(cmd) || "libraries".equals(cmd)) {
- dumpStar = false;
- dumpLibs = true;
+ dumpState.setDump(DumpState.DUMP_LIBS);
} else if ("f".equals(cmd) || "features".equals(cmd)) {
- dumpStar = false;
- dumpFeatures = true;
+ dumpState.setDump(DumpState.DUMP_FEATURES);
} else if ("r".equals(cmd) || "resolvers".equals(cmd)) {
- dumpStar = false;
- dumpResolvers = true;
+ dumpState.setDump(DumpState.DUMP_RESOLVERS);
} else if ("perm".equals(cmd) || "permissions".equals(cmd)) {
- dumpStar = false;
- dumpPermissions = true;
+ dumpState.setDump(DumpState.DUMP_PERMISSIONS);
} else if ("p".equals(cmd) || "packages".equals(cmd)) {
- dumpStar = false;
- dumpPackages = true;
+ dumpState.setDump(DumpState.DUMP_PACKAGES);
} else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
- dumpStar = false;
- dumpSharedUsers = true;
+ dumpState.setDump(DumpState.DUMP_SHARED_USERS);
} else if ("prov".equals(cmd) || "providers".equals(cmd)) {
- dumpStar = false;
- dumpProviders = true;
+ dumpState.setDump(DumpState.DUMP_PROVIDERS);
} else if ("m".equals(cmd) || "messages".equals(cmd)) {
- dumpStar = false;
- dumpMessages = true;
+ dumpState.setDump(DumpState.DUMP_MESSAGES);
}
}
-
- boolean printedTitle = false;
-
+
+ // reader
synchronized (mPackages) {
- if ((dumpStar || dumpLibs) && packageName == null) {
- if (printedTitle) pw.println(" ");
- printedTitle = true;
+ if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
pw.println("Libraries:");
- Iterator<String> it = mSharedLibraries.keySet().iterator();
+ final Iterator<String> it = mSharedLibraries.keySet().iterator();
while (it.hasNext()) {
String name = it.next();
pw.print(" ");
@@ -7234,9 +7309,9 @@
}
}
- if ((dumpStar || dumpFeatures) && packageName == null) {
- if (printedTitle) pw.println(" ");
- printedTitle = true;
+ if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
pw.println("Features:");
Iterator<String> it = mAvailableFeatures.keySet().iterator();
while (it.hasNext()) {
@@ -7246,276 +7321,72 @@
}
}
- if (dumpStar || dumpResolvers) {
- if (mActivities.dump(pw, printedTitle
- ? "\nActivity Resolver Table:" : "Activity Resolver Table:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (dumpState.isDumping(DumpState.DUMP_RESOLVERS)) {
+ if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
+ : "Activity Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
- if (mReceivers.dump(pw, printedTitle
- ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:"
+ : "Receiver Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
- if (mServices.dump(pw, printedTitle
- ? "\nService Resolver Table:" : "Service Resolver Table:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:"
+ : "Service Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
- if (mSettings.mPreferredActivities.dump(pw, printedTitle
- ? "\nPreferred Activities:" : "Preferred Activities:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (mSettings.mPreferredActivities.dump(pw,
+ dumpState.getTitlePrinted() ? "\nPreferred Activities:"
+ : "Preferred Activities:", " ",
+ packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
}
- boolean printedSomething = false;
- if (dumpStar || dumpPermissions) {
- for (BasePermission p : mSettings.mPermissions.values()) {
- if (packageName != null && !packageName.equals(p.sourcePackage)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Permissions:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(p)));
- pw.println("):");
- pw.print(" sourcePackage="); pw.println(p.sourcePackage);
- pw.print(" uid="); pw.print(p.uid);
- pw.print(" gids="); pw.print(arrayToString(p.gids));
- pw.print(" type="); pw.print(p.type);
- pw.print(" prot="); pw.println(p.protectionLevel);
- if (p.packageSetting != null) {
- pw.print(" packageSetting="); pw.println(p.packageSetting);
- }
- if (p.perm != null) {
- pw.print(" perm="); pw.println(p.perm);
- }
- }
+ if (dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ mSettings.dumpPermissionsLPr(pw, packageName, dumpState);
}
- if (dumpStar || dumpProviders) {
- printedSomething = false;
+ if (dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ boolean printedSomething = false;
for (PackageParser.Provider p : mProviders.values()) {
if (packageName != null && !packageName.equals(p.info.packageName)) {
continue;
}
if (!printedSomething) {
- if (printedTitle) pw.println(" ");
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
pw.println("Registered ContentProviders:");
printedSomething = true;
- printedTitle = true;
}
pw.print(" ["); pw.print(p.info.authority); pw.print("]: ");
pw.println(p.toString());
}
}
- printedSomething = false;
- SharedUserSetting packageSharedUser = null;
- if (dumpStar || dumpPackages) {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date = new Date();
- for (PackageSetting ps : mSettings.mPackages.values()) {
- if (packageName != null && !packageName.equals(ps.realName)
- && !packageName.equals(ps.name)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Packages:");
- printedSomething = true;
- printedTitle = true;
- }
- packageSharedUser = ps.sharedUser;
- pw.print(" Package [");
- pw.print(ps.realName != null ? ps.realName : ps.name);
- pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(ps)));
- pw.println("):");
- if (ps.realName != null) {
- pw.print(" compat name="); pw.println(ps.name);
- }
- pw.print(" userId="); pw.print(ps.userId);
- pw.print(" gids="); pw.println(arrayToString(ps.gids));
- pw.print(" sharedUser="); pw.println(ps.sharedUser);
- pw.print(" pkg="); pw.println(ps.pkg);
- pw.print(" codePath="); pw.println(ps.codePathString);
- pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
- pw.print(" versionCode="); pw.println(ps.versionCode);
- if (ps.pkg != null) {
- 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);
- if (ps.pkg.mOperationPending) {
- pw.println(" mOperationPending=true");
- }
- pw.print(" supportsScreens=[");
- boolean first = true;
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("small");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("medium");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("large");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("xlarge");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("resizeable");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("anyDensity");
- }
- }
- pw.println("]");
- pw.print(" timeStamp=");
- date.setTime(ps.timeStamp); pw.println(sdf.format(date));
- pw.print(" firstInstallTime=");
- date.setTime(ps.firstInstallTime); pw.println(sdf.format(date));
- pw.print(" lastUpdateTime=");
- date.setTime(ps.lastUpdateTime); pw.println(sdf.format(date));
- if (ps.installerPackageName != null) {
- pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
- }
- pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
- pw.print(" haveGids="); pw.println(ps.haveGids);
- pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
- pw.print(" installStatus="); pw.print(ps.installStatus);
- pw.print(" stopped="); pw.print(ps.stopped);
- pw.print(" enabled="); pw.println(ps.enabled);
- if (ps.disabledComponents.size() > 0) {
- pw.println(" disabledComponents:");
- for (String s : ps.disabledComponents) {
- pw.print(" "); pw.println(s);
- }
- }
- if (ps.enabledComponents.size() > 0) {
- pw.println(" enabledComponents:");
- for (String s : ps.enabledComponents) {
- pw.print(" "); pw.println(s);
- }
- }
- if (ps.grantedPermissions.size() > 0) {
- pw.println(" grantedPermissions:");
- for (String s : ps.grantedPermissions) {
- pw.print(" "); pw.println(s);
- }
- }
- }
+ if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
+ mSettings.dumpPackagesLPr(pw, packageName, dumpState);
}
- printedSomething = false;
- if (dumpStar || dumpPackages) {
- if (mSettings.mRenamedPackages.size() > 0) {
- for (HashMap.Entry<String, String> e
- : mSettings.mRenamedPackages.entrySet()) {
- if (packageName != null && !packageName.equals(e.getKey())
- && !packageName.equals(e.getValue())) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Renamed packages:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" "); pw.print(e.getKey()); pw.print(" -> ");
- pw.println(e.getValue());
- }
- }
- printedSomething = false;
- if (mSettings.mDisabledSysPackages.size() > 0) {
- for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) {
- if (packageName != null && !packageName.equals(ps.realName)
- && !packageName.equals(ps.name)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Hidden system packages:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" Package [");
- pw.print(ps.realName != null ? ps.realName : ps.name);
- pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(ps)));
- pw.println("):");
- if (ps.realName != null) {
- pw.print(" compat name="); pw.println(ps.name);
- }
- pw.print(" userId="); pw.println(ps.userId);
- pw.print(" sharedUser="); pw.println(ps.sharedUser);
- pw.print(" codePath="); pw.println(ps.codePathString);
- pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- }
- }
+
+ if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
+ mSettings.dumpSharedUsersLPr(pw, packageName, dumpState);
}
- printedSomething = false;
- if (dumpStar || dumpSharedUsers) {
- for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
- if (packageName != null && su != packageSharedUser) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Shared users:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" SharedUser ["); pw.print(su.name); pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(su)));
- pw.println("):");
- pw.print(" userId="); pw.print(su.userId);
- pw.print(" gids="); pw.println(arrayToString(su.gids));
- pw.println(" grantedPermissions:");
- for (String s : su.grantedPermissions) {
- pw.print(" "); pw.println(s);
- }
- }
- }
-
- if ((dumpStar || dumpMessages) && packageName == null) {
- if (printedTitle) pw.println(" ");
- printedTitle = true;
- pw.println("Settings parse messages:");
- pw.print(mSettings.mReadMessages.toString());
-
+
+ if (dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ mSettings.dumpReadMessagesLPr(pw, dumpState);
+
pw.println(" ");
pw.println("Package warning messages:");
- File fname = getSettingsProblemFile();
+ final File fname = getSettingsProblemFile();
FileInputStream in = null;
try {
in = new FileInputStream(fname);
- int avail = in.available();
- byte[] data = new byte[avail];
+ final int avail = in.available();
+ final byte[] data = new byte[avail];
in.read(data);
pw.print(new String(data));
} catch (FileNotFoundException e) {
@@ -7524,7 +7395,7 @@
if (in != null) {
try {
in.close();
- } catch (IOException e) {
+ } catch (IOException e) {
}
}
}
@@ -7532,2411 +7403,13 @@
}
}
- static final class BasePermission {
- final static int TYPE_NORMAL = 0;
- final static int TYPE_BUILTIN = 1;
- final static int TYPE_DYNAMIC = 2;
-
- final String name;
- String sourcePackage;
- PackageSettingBase packageSetting;
- final int type;
- int protectionLevel;
- PackageParser.Permission perm;
- PermissionInfo pendingInfo;
- int uid;
- int[] gids;
-
- BasePermission(String _name, String _sourcePackage, int _type) {
- name = _name;
- sourcePackage = _sourcePackage;
- type = _type;
- // Default to most conservative protection level.
- protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
- }
-
- public String toString() {
- return "BasePermission{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + name + "}";
- }
- }
-
- static class PackageSignatures {
- private Signature[] mSignatures;
-
- PackageSignatures(PackageSignatures orig) {
- if (orig != null && orig.mSignatures != null) {
- mSignatures = orig.mSignatures.clone();
- }
- }
-
- PackageSignatures(Signature[] sigs) {
- assignSignatures(sigs);
- }
-
- PackageSignatures() {
- }
-
- void writeXml(XmlSerializer serializer, String tagName,
- ArrayList<Signature> pastSignatures) throws IOException {
- if (mSignatures == null) {
- return;
- }
- serializer.startTag(null, tagName);
- serializer.attribute(null, "count",
- Integer.toString(mSignatures.length));
- for (int i=0; i<mSignatures.length; i++) {
- serializer.startTag(null, "cert");
- final Signature sig = mSignatures[i];
- final int sigHash = sig.hashCode();
- final int numPast = pastSignatures.size();
- int j;
- for (j=0; j<numPast; j++) {
- Signature pastSig = pastSignatures.get(j);
- if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
- serializer.attribute(null, "index", Integer.toString(j));
- break;
- }
- }
- if (j >= numPast) {
- pastSignatures.add(sig);
- serializer.attribute(null, "index", Integer.toString(numPast));
- serializer.attribute(null, "key", sig.toCharsString());
- }
- serializer.endTag(null, "cert");
- }
- serializer.endTag(null, tagName);
- }
-
- void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
- throws IOException, XmlPullParserException {
- String countStr = parser.getAttributeValue(null, "count");
- if (countStr == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <signatures> has"
- + " no count at " + parser.getPositionDescription());
- XmlUtils.skipCurrentTag(parser);
- }
- final int count = Integer.parseInt(countStr);
- mSignatures = new Signature[count];
- int pos = 0;
-
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("cert")) {
- if (pos < count) {
- String index = parser.getAttributeValue(null, "index");
- if (index != null) {
- try {
- int idx = Integer.parseInt(index);
- String key = parser.getAttributeValue(null, "key");
- if (key == null) {
- if (idx >= 0 && idx < pastSignatures.size()) {
- Signature sig = pastSignatures.get(idx);
- if (sig != null) {
- mSignatures[pos] = pastSignatures.get(idx);
- pos++;
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> "
- + "index " + index + " is not defined at "
- + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> "
- + "index " + index + " is out of bounds at "
- + parser.getPositionDescription());
- }
- } else {
- while (pastSignatures.size() <= idx) {
- pastSignatures.add(null);
- }
- Signature sig = new Signature(key);
- pastSignatures.set(idx, sig);
- mSignatures[pos] = sig;
- pos++;
- }
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> "
- + "index " + index + " is not a number at "
- + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> has"
- + " no index at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: too "
- + "many <cert> tags, expected " + count
- + " at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <cert>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
-
- if (pos < count) {
- // Should never happen -- there is an error in the written
- // settings -- but if it does we don't want to generate
- // a bad array.
- Signature[] newSigs = new Signature[pos];
- System.arraycopy(mSignatures, 0, newSigs, 0, pos);
- mSignatures = newSigs;
- }
- }
-
- private void assignSignatures(Signature[] sigs) {
- if (sigs == null) {
- mSignatures = null;
- return;
- }
- mSignatures = new Signature[sigs.length];
- for (int i=0; i<sigs.length; i++) {
- mSignatures[i] = sigs[i];
- }
- }
-
- @Override
- public String toString() {
- StringBuffer buf = new StringBuffer(128);
- buf.append("PackageSignatures{");
- buf.append(Integer.toHexString(System.identityHashCode(this)));
- buf.append(" [");
- if (mSignatures != null) {
- for (int i=0; i<mSignatures.length; i++) {
- if (i > 0) buf.append(", ");
- buf.append(Integer.toHexString(
- System.identityHashCode(mSignatures[i])));
- }
- }
- buf.append("]}");
- return buf.toString();
- }
- }
-
- static class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks {
- final PreferredComponent mPref;
-
- PreferredActivity(IntentFilter filter, int match, ComponentName[] set,
- ComponentName activity) {
- super(filter);
- mPref = new PreferredComponent(this, match, set, activity);
- }
-
- PreferredActivity(XmlPullParser parser) throws XmlPullParserException,
- IOException {
- mPref = new PreferredComponent(this, parser);
- }
-
- public void writeToXml(XmlSerializer serializer) throws IOException {
- mPref.writeToXml(serializer);
- serializer.startTag(null, "filter");
- super.writeToXml(serializer);
- serializer.endTag(null, "filter");
- }
-
- public boolean onReadTag(String tagName, XmlPullParser parser)
- throws XmlPullParserException, IOException {
- if (tagName.equals("filter")) {
- //Log.i(TAG, "Starting to parse filter...");
- readFromXml(parser);
- //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
- // + parser.getDepth() + " tag=" + parser.getName());
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- return true;
- }
- }
-
- static class GrantedPermissions {
- int pkgFlags;
-
- HashSet<String> grantedPermissions = new HashSet<String>();
- int[] gids;
-
- GrantedPermissions(int pkgFlags) {
- setFlags(pkgFlags);
- }
-
- GrantedPermissions(GrantedPermissions base) {
- pkgFlags = base.pkgFlags;
- grantedPermissions = (HashSet<String>) base.grantedPermissions.clone();
-
- if (base.gids != null) {
- gids = base.gids.clone();
- }
- }
-
- void setFlags(int pkgFlags) {
- this.pkgFlags = pkgFlags & (
- ApplicationInfo.FLAG_SYSTEM |
- ApplicationInfo.FLAG_FORWARD_LOCK |
- ApplicationInfo.FLAG_EXTERNAL_STORAGE);
- }
- }
-
- /**
- * Settings base class for pending and resolved classes.
- */
- static class PackageSettingBase extends GrantedPermissions {
- final String name;
- final String realName;
- File codePath;
- String codePathString;
- File resourcePath;
- String resourcePathString;
- String nativeLibraryPathString;
- long timeStamp;
- long firstInstallTime;
- long lastUpdateTime;
- int versionCode;
-
- boolean uidError;
-
- PackageSignatures signatures = new PackageSignatures();
-
- boolean permissionsFixed;
- boolean haveGids;
-
- // Whether this package is currently stopped, thus can not be
- // started until explicitly launched by the user.
- public boolean stopped;
-
- // Set to true if we have never launched this app.
- public boolean notLaunched;
-
- /* Explicitly disabled components */
- HashSet<String> disabledComponents = new HashSet<String>(0);
- /* Explicitly enabled components */
- HashSet<String> enabledComponents = new HashSet<String>(0);
- int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- int installStatus = PKG_INSTALL_COMPLETE;
-
- PackageSettingBase origPackage;
-
- /* package name of the app that installed this package */
- String installerPackageName;
-
- PackageSettingBase(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
- super(pkgFlags);
- this.name = name;
- this.realName = realName;
- init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
- }
-
- /**
- * New instance of PackageSetting with one-level-deep cloning.
- */
- PackageSettingBase(PackageSettingBase base) {
- super(base);
-
- name = base.name;
- realName = base.realName;
- codePath = base.codePath;
- codePathString = base.codePathString;
- resourcePath = base.resourcePath;
- resourcePathString = base.resourcePathString;
- nativeLibraryPathString = base.nativeLibraryPathString;
- timeStamp = base.timeStamp;
- firstInstallTime = base.firstInstallTime;
- lastUpdateTime = base.lastUpdateTime;
- versionCode = base.versionCode;
-
- uidError = base.uidError;
-
- signatures = new PackageSignatures(base.signatures);
-
- permissionsFixed = base.permissionsFixed;
- haveGids = base.haveGids;
- stopped = base.stopped;
- notLaunched = base.notLaunched;
-
- disabledComponents = (HashSet<String>) base.disabledComponents.clone();
-
- enabledComponents = (HashSet<String>) base.enabledComponents.clone();
-
- enabled = base.enabled;
- installStatus = base.installStatus;
-
- origPackage = base.origPackage;
-
- installerPackageName = base.installerPackageName;
- }
-
- void init(File codePath, File resourcePath, String nativeLibraryPathString,
- int pVersionCode) {
- this.codePath = codePath;
- this.codePathString = codePath.toString();
- this.resourcePath = resourcePath;
- this.resourcePathString = resourcePath.toString();
- this.nativeLibraryPathString = nativeLibraryPathString;
- this.versionCode = pVersionCode;
- }
-
- public void setInstallerPackageName(String packageName) {
- installerPackageName = packageName;
- }
-
- String getInstallerPackageName() {
- return installerPackageName;
- }
-
- public void setInstallStatus(int newStatus) {
- installStatus = newStatus;
- }
-
- public int getInstallStatus() {
- return installStatus;
- }
-
- public void setTimeStamp(long newStamp) {
- timeStamp = newStamp;
- }
-
- /**
- * Make a shallow copy of this package settings.
- */
- public void copyFrom(PackageSettingBase base) {
- grantedPermissions = base.grantedPermissions;
- gids = base.gids;
-
- timeStamp = base.timeStamp;
- firstInstallTime = base.firstInstallTime;
- lastUpdateTime = base.lastUpdateTime;
- signatures = base.signatures;
- permissionsFixed = base.permissionsFixed;
- haveGids = base.haveGids;
- stopped = base.stopped;
- notLaunched = base.notLaunched;
- disabledComponents = base.disabledComponents;
- enabledComponents = base.enabledComponents;
- enabled = base.enabled;
- installStatus = base.installStatus;
- }
-
- boolean enableComponentLP(String componentClassName) {
- boolean changed = disabledComponents.remove(componentClassName);
- changed |= enabledComponents.add(componentClassName);
- return changed;
- }
-
- boolean disableComponentLP(String componentClassName) {
- boolean changed = enabledComponents.remove(componentClassName);
- changed |= disabledComponents.add(componentClassName);
- return changed;
- }
-
- boolean restoreComponentLP(String componentClassName) {
- boolean changed = enabledComponents.remove(componentClassName);
- changed |= disabledComponents.remove(componentClassName);
- return changed;
- }
-
- int currentEnabledStateLP(String componentName) {
- if (enabledComponents.contains(componentName)) {
- return COMPONENT_ENABLED_STATE_ENABLED;
- } else if (disabledComponents.contains(componentName)) {
- return COMPONENT_ENABLED_STATE_DISABLED;
- } else {
- return COMPONENT_ENABLED_STATE_DEFAULT;
- }
- }
- }
-
- /**
- * Settings data for a particular package we know about.
- */
- static final class PackageSetting extends PackageSettingBase {
- int userId;
- PackageParser.Package pkg;
- SharedUserSetting sharedUser;
-
- PackageSetting(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
- pkgFlags);
- }
-
- /**
- * New instance of PackageSetting replicating the original settings.
- * Note that it keeps the same PackageParser.Package instance.
- */
- PackageSetting(PackageSetting orig) {
- super(orig);
-
- userId = orig.userId;
- pkg = orig.pkg;
- sharedUser = orig.sharedUser;
- }
-
- @Override
- public String toString() {
- return "PackageSetting{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + name + "/" + userId + "}";
- }
- }
-
- /**
- * Settings data for a particular shared user ID we know about.
- */
- static final class SharedUserSetting extends GrantedPermissions {
- final String name;
- int userId;
- final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
- final PackageSignatures signatures = new PackageSignatures();
-
- SharedUserSetting(String _name, int _pkgFlags) {
- super(_pkgFlags);
- name = _name;
- }
-
- @Override
- public String toString() {
- return "SharedUserSetting{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + name + "/" + userId + "}";
- }
- }
-
- /**
- * Holds information about dynamic settings.
- */
- private static final class Settings {
- private final File mSettingsFilename;
- private final File mBackupSettingsFilename;
- private final File mPackageListFilename;
- private final File mStoppedPackagesFilename;
- private final File mBackupStoppedPackagesFilename;
- private final HashMap<String, PackageSetting> mPackages =
- new HashMap<String, PackageSetting>();
- // List of replaced system applications
- final HashMap<String, PackageSetting> mDisabledSysPackages =
- new HashMap<String, PackageSetting>();
-
- // These are the last platform API version we were using for
- // the apps installed on internal and external storage. It is
- // used to grant newer permissions one time during a system upgrade.
- int mInternalSdkPlatform;
- int mExternalSdkPlatform;
-
- // The user's preferred activities associated with particular intent
- // filters.
- private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
- new IntentResolver<PreferredActivity, PreferredActivity>() {
- @Override
- protected String packageForFilter(PreferredActivity filter) {
- return filter.mPref.mComponent.getPackageName();
- }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PreferredActivity filter) {
- filter.mPref.dump(out, prefix, filter);
- }
- };
- private final HashMap<String, SharedUserSetting> mSharedUsers =
- new HashMap<String, SharedUserSetting>();
- private final ArrayList<Object> mUserIds = new ArrayList<Object>();
- private final SparseArray<Object> mOtherUserIds =
- new SparseArray<Object>();
-
- // For reading/writing settings file.
- private final ArrayList<Signature> mPastSignatures =
- new ArrayList<Signature>();
-
- // Mapping from permission names to info about them.
- final HashMap<String, BasePermission> mPermissions =
- new HashMap<String, BasePermission>();
-
- // Mapping from permission tree names to info about them.
- final HashMap<String, BasePermission> mPermissionTrees =
- new HashMap<String, BasePermission>();
-
- // Packages that have been uninstalled and still need their external
- // storage data deleted.
- final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
-
- // Packages that have been renamed since they were first installed.
- // Keys are the new names of the packages, values are the original
- // names. The packages appear everwhere else under their original
- // names.
- final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
-
- private final StringBuilder mReadMessages = new StringBuilder();
-
- private static final class PendingPackage extends PackageSettingBase {
- final int sharedId;
-
- PendingPackage(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString,
- pVersionCode, pkgFlags);
- this.sharedId = sharedId;
- }
- }
- private final ArrayList<PendingPackage> mPendingPackages
- = new ArrayList<PendingPackage>();
-
- Settings() {
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
- File systemSecureDir = new File(dataDir, "secure/system");
- systemDir.mkdirs();
- systemSecureDir.mkdirs();
- FileUtils.setPermissions(systemDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- FileUtils.setPermissions(systemSecureDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- mSettingsFilename = new File(systemDir, "packages.xml");
- mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
- mPackageListFilename = new File(systemDir, "packages.list");
- mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml");
- mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml");
- }
-
- PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
- final String name = pkg.packageName;
- PackageSetting p = getPackageLP(name, origPackage, realName, sharedUser, codePath,
- resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
- return p;
- }
-
- PackageSetting peekPackageLP(String name) {
- return mPackages.get(name);
- /*
- PackageSetting p = mPackages.get(name);
- if (p != null && p.codePath.getPath().equals(codePath)) {
- return p;
- }
- return null;
- */
- }
-
- void setInstallStatus(String pkgName, int status) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- if(p.getInstallStatus() != status) {
- p.setInstallStatus(status);
- }
- }
- }
-
- void setInstallerPackageName(String pkgName,
- String installerPkgName) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- p.setInstallerPackageName(installerPkgName);
- }
- }
-
- SharedUserSetting getSharedUserLP(String name,
- int pkgFlags, boolean create) {
- SharedUserSetting s = mSharedUsers.get(name);
- if (s == null) {
- if (!create) {
- return null;
- }
- s = new SharedUserSetting(name, pkgFlags);
- if (MULTIPLE_APPLICATION_UIDS) {
- s.userId = newUserIdLP(s);
- } else {
- s.userId = FIRST_APPLICATION_UID;
- }
- Log.i(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
- if (s.userId >= 0) {
- mSharedUsers.put(name, s);
- }
- }
-
- return s;
- }
-
- boolean disableSystemPackageLP(String name) {
- PackageSetting p = mPackages.get(name);
- if(p == null) {
- Log.w(TAG, "Package:"+name+" is not an installed package");
- return false;
- }
- PackageSetting dp = mDisabledSysPackages.get(name);
- // always make sure the system package code and resource paths dont change
- if (dp == null) {
- if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
- p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- }
- mDisabledSysPackages.put(name, p);
-
- // a little trick... when we install the new package, we don't
- // want to modify the existing PackageSetting for the built-in
- // version. so at this point we need a new PackageSetting that
- // is okay to muck with.
- PackageSetting newp = new PackageSetting(p);
- replacePackageLP(name, newp);
- return true;
- }
- return false;
- }
-
- PackageSetting enableSystemPackageLP(String name) {
- PackageSetting p = mDisabledSysPackages.get(name);
- if(p == null) {
- Log.w(TAG, "Package:"+name+" is not disabled");
- return null;
- }
- // Reset flag in ApplicationInfo object
- if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
- p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- }
- PackageSetting ret = addPackageLP(name, p.realName, p.codePath, p.resourcePath,
- p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags);
- mDisabledSysPackages.remove(name);
- return ret;
- }
-
- PackageSetting addPackageLP(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- if (p.userId == uid) {
- return p;
- }
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate package, keeping first: " + name);
- return null;
- }
- p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
- vc, pkgFlags);
- p.userId = uid;
- if (addUserIdLP(uid, p, name)) {
- mPackages.put(name, p);
- return p;
- }
- return null;
- }
-
- SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) {
- SharedUserSetting s = mSharedUsers.get(name);
- if (s != null) {
- if (s.userId == uid) {
- return s;
- }
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate shared user, keeping first: " + name);
- return null;
- }
- s = new SharedUserSetting(name, pkgFlags);
- s.userId = uid;
- if (addUserIdLP(uid, s, name)) {
- mSharedUsers.put(name, s);
- return s;
- }
- return null;
- }
-
- // Transfer ownership of permissions from one package to another.
- private void transferPermissions(String origPkg, String newPkg) {
- // Transfer ownership of permissions to the new package.
- for (int i=0; i<2; i++) {
- HashMap<String, BasePermission> permissions =
- i == 0 ? mPermissionTrees : mPermissions;
- for (BasePermission bp : permissions.values()) {
- if (origPkg.equals(bp.sourcePackage)) {
- if (DEBUG_UPGRADE) Log.v(TAG,
- "Moving permission " + bp.name
- + " from pkg " + bp.sourcePackage
- + " to " + newPkg);
- bp.sourcePackage = newPkg;
- bp.packageSetting = null;
- bp.perm = null;
- if (bp.pendingInfo != null) {
- bp.pendingInfo.packageName = newPkg;
- }
- bp.uid = 0;
- bp.gids = null;
- }
- }
- }
- }
-
- private PackageSetting getPackageLP(String name, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- if (!p.codePath.equals(codePath)) {
- // Check to see if its a disabled system app
- if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- // This is an updated system app with versions in both system
- // and data partition. Just let the most recent version
- // take precedence.
- Slog.w(TAG, "Trying to update system app code path from " +
- p.codePathString + " to " + codePath.toString());
- } else {
- // Just a change in the code path is not an issue, but
- // let's log a message about it.
- Slog.i(TAG, "Package " + name + " codePath changed from " + p.codePath
- + " to " + codePath + "; Retaining data and using new");
- /*
- * Since we've changed paths, we need to prefer the new
- * native library path over the one stored in the
- * package settings since we might have moved from
- * internal to external storage or vice versa.
- */
- p.nativeLibraryPathString = nativeLibraryPathString;
- }
- }
- if (p.sharedUser != sharedUser) {
- reportSettingsProblem(Log.WARN,
- "Package " + name + " shared user changed from "
- + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
- + " to "
- + (sharedUser != null ? sharedUser.name : "<nothing>")
- + "; replacing with new");
- p = null;
- } else {
- if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
- // If what we are scanning is a system package, then
- // make it so, regardless of whether it was previously
- // installed only in the data partition.
- p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- }
- }
- }
- if (p == null) {
- // Create a new PackageSettings entry. this can end up here because
- // of code path mismatch or user id mismatch of an updated system partition
- if (!create) {
- return null;
- }
- if (origPackage != null) {
- // We are consuming the data from an existing package.
- p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
- nativeLibraryPathString, vc, pkgFlags);
- if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name
- + " is adopting original package " + origPackage.name);
- // Note that we will retain the new package's signature so
- // that we can keep its data.
- PackageSignatures s = p.signatures;
- p.copyFrom(origPackage);
- p.signatures = s;
- p.sharedUser = origPackage.sharedUser;
- p.userId = origPackage.userId;
- p.origPackage = origPackage;
- mRenamedPackages.put(name, origPackage.name);
- name = origPackage.name;
- // Update new package state.
- p.setTimeStamp(codePath.lastModified());
- } else {
- p = new PackageSetting(name, realName, codePath, resourcePath,
- nativeLibraryPathString, vc, pkgFlags);
- p.setTimeStamp(codePath.lastModified());
- p.sharedUser = sharedUser;
- // If this is not a system app, it starts out stopped.
- if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- if (DEBUG_STOPPED) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.i(TAG, "Stopping package " + name, e);
- }
- p.stopped = true;
- p.notLaunched = true;
- }
- if (sharedUser != null) {
- p.userId = sharedUser.userId;
- } else if (MULTIPLE_APPLICATION_UIDS) {
- // Clone the setting here for disabled system packages
- PackageSetting dis = mDisabledSysPackages.get(name);
- if (dis != null) {
- // For disabled packages a new setting is created
- // from the existing user id. This still has to be
- // added to list of user id's
- // Copy signatures from previous setting
- if (dis.signatures.mSignatures != null) {
- p.signatures.mSignatures = dis.signatures.mSignatures.clone();
- }
- p.userId = dis.userId;
- // Clone permissions
- p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
- // Clone component info
- p.disabledComponents = new HashSet<String>(dis.disabledComponents);
- p.enabledComponents = new HashSet<String>(dis.enabledComponents);
- // Add new setting to list of user ids
- addUserIdLP(p.userId, p, name);
- } else {
- // Assign new user id
- p.userId = newUserIdLP(p);
- }
- } else {
- p.userId = FIRST_APPLICATION_UID;
- }
- }
- if (p.userId < 0) {
- reportSettingsProblem(Log.WARN,
- "Package " + name + " could not be assigned a valid uid");
- return null;
- }
- if (add) {
- // Finish adding new package by adding it and updating shared
- // user preferences
- addPackageSettingLP(p, name, sharedUser);
- }
- }
- return p;
- }
-
- private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) {
- p.pkg = pkg;
- pkg.mSetEnabled = p.enabled;
- pkg.mSetStopped = p.stopped;
- final String codePath = pkg.applicationInfo.sourceDir;
- final String resourcePath = pkg.applicationInfo.publicSourceDir;
- // Update code path if needed
- if (!codePath.equalsIgnoreCase(p.codePathString)) {
- Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName +
- " changing from " + p.codePathString + " to " + codePath);
- p.codePath = new File(codePath);
- p.codePathString = codePath;
- }
- //Update resource path if needed
- if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
- Slog.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
- " changing from " + p.resourcePathString + " to " + resourcePath);
- p.resourcePath = new File(resourcePath);
- p.resourcePathString = resourcePath;
- }
- // Update the native library path if needed
- final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
- if (nativeLibraryPath != null
- && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
- p.nativeLibraryPathString = nativeLibraryPath;
- }
- // Update version code if needed
- if (pkg.mVersionCode != p.versionCode) {
- p.versionCode = pkg.mVersionCode;
- }
- // Update signatures if needed.
- if (p.signatures.mSignatures == null) {
- p.signatures.assignSignatures(pkg.mSignatures);
- }
- // If this app defines a shared user id initialize
- // the shared user signatures as well.
- if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
- p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
- }
- addPackageSettingLP(p, pkg.packageName, p.sharedUser);
- }
-
- // Utility method that adds a PackageSetting to mPackages and
- // completes updating the shared user attributes
- private void addPackageSettingLP(PackageSetting p, String name,
- SharedUserSetting sharedUser) {
- mPackages.put(name, p);
- if (sharedUser != null) {
- if (p.sharedUser != null && p.sharedUser != sharedUser) {
- reportSettingsProblem(Log.ERROR,
- "Package " + p.name + " was user "
- + p.sharedUser + " but is now " + sharedUser
- + "; I am not changing its files so it will probably fail!");
- p.sharedUser.packages.remove(p);
- } else if (p.userId != sharedUser.userId) {
- reportSettingsProblem(Log.ERROR,
- "Package " + p.name + " was user id " + p.userId
- + " but is now user " + sharedUser
- + " with id " + sharedUser.userId
- + "; I am not changing its files so it will probably fail!");
- }
-
- sharedUser.packages.add(p);
- p.sharedUser = sharedUser;
- p.userId = sharedUser.userId;
- }
- }
-
- /*
- * Update the shared user setting when a package using
- * specifying the shared user id is removed. The gids
- * associated with each permission of the deleted package
- * are removed from the shared user's gid list only if its
- * not in use by other permissions of packages in the
- * shared user setting.
- */
- private void updateSharedUserPermsLP(PackageSetting deletedPs, int[] globalGids) {
- if ( (deletedPs == null) || (deletedPs.pkg == null)) {
- Slog.i(TAG, "Trying to update info for null package. Just ignoring");
- return;
- }
- // No sharedUserId
- if (deletedPs.sharedUser == null) {
- return;
- }
- SharedUserSetting sus = deletedPs.sharedUser;
- // Update permissions
- for (String eachPerm: deletedPs.pkg.requestedPermissions) {
- boolean used = false;
- if (!sus.grantedPermissions.contains (eachPerm)) {
- continue;
- }
- for (PackageSetting pkg:sus.packages) {
- if (pkg.pkg != null &&
- !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
- pkg.pkg.requestedPermissions.contains(eachPerm)) {
- used = true;
- break;
- }
- }
- if (!used) {
- // can safely delete this permission from list
- sus.grantedPermissions.remove(eachPerm);
- }
- }
- // Update gids
- int newGids[] = globalGids;
- for (String eachPerm : sus.grantedPermissions) {
- BasePermission bp = mPermissions.get(eachPerm);
- if (bp != null) {
- newGids = appendInts(newGids, bp.gids);
- }
- }
- sus.gids = newGids;
- }
-
- private int removePackageLP(String name) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- mPackages.remove(name);
- if (p.sharedUser != null) {
- p.sharedUser.packages.remove(p);
- if (p.sharedUser.packages.size() == 0) {
- mSharedUsers.remove(p.sharedUser.name);
- removeUserIdLP(p.sharedUser.userId);
- return p.sharedUser.userId;
- }
- } else {
- removeUserIdLP(p.userId);
- return p.userId;
- }
- }
- return -1;
- }
-
- private void replacePackageLP(String name, PackageSetting newp) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- if (p.sharedUser != null) {
- p.sharedUser.packages.remove(p);
- p.sharedUser.packages.add(newp);
- } else {
- replaceUserIdLP(p.userId, newp);
- }
- }
- mPackages.put(name, newp);
- }
-
- private boolean addUserIdLP(int uid, Object obj, Object name) {
- if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) {
- return false;
- }
-
- if (uid >= FIRST_APPLICATION_UID) {
- int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- while (index >= N) {
- mUserIds.add(null);
- N++;
- }
- if (mUserIds.get(index) != null) {
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate user id: " + uid
- + " name=" + name);
- return false;
- }
- mUserIds.set(index, obj);
- } else {
- if (mOtherUserIds.get(uid) != null) {
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate shared id: " + uid
- + " name=" + name);
- return false;
- }
- mOtherUserIds.put(uid, obj);
- }
- return true;
- }
-
- public Object getUserIdLP(int uid) {
- if (uid >= FIRST_APPLICATION_UID) {
- final int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- return index < N ? mUserIds.get(index) : null;
- } else {
- return mOtherUserIds.get(uid);
- }
- }
-
- private void removeUserIdLP(int uid) {
- if (uid >= FIRST_APPLICATION_UID) {
- final int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- if (index < N) mUserIds.set(index, null);
- } else {
- mOtherUserIds.remove(uid);
- }
- }
-
- private void replaceUserIdLP(int uid, Object obj) {
- if (uid >= FIRST_APPLICATION_UID) {
- final int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- if (index < N) mUserIds.set(index, obj);
- } else {
- mOtherUserIds.put(uid, obj);
- }
- }
-
- void writeStoppedLP() {
- // Keep the old stopped packages around until we know the new ones have
- // been successfully written.
- if (mStoppedPackagesFilename.exists()) {
- // Presence of backup settings file indicates that we failed
- // to persist packages earlier. So preserve the older
- // backup for future reference since the current packages
- // might have been corrupted.
- if (!mBackupStoppedPackagesFilename.exists()) {
- if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) {
- Log.wtf(TAG, "Unable to backup package manager stopped packages, "
- + "current changes will be lost at reboot");
- return;
- }
- } else {
- mStoppedPackagesFilename.delete();
- Slog.w(TAG, "Preserving older stopped packages backup");
- }
- }
-
- try {
- FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename);
- BufferedOutputStream str = new BufferedOutputStream(fstr);
-
- //XmlSerializer serializer = XmlUtils.serializerInstance();
- XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(str, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startTag(null, "stopped-packages");
-
- for (PackageSetting pkg : mPackages.values()) {
- if (pkg.stopped) {
- serializer.startTag(null, "pkg");
- serializer.attribute(null, "name", pkg.name);
- if (pkg.notLaunched) {
- serializer.attribute(null, "nl", "1");
- }
- serializer.endTag(null, "pkg");
- }
- }
-
- serializer.endTag(null, "stopped-packages");
-
- serializer.endDocument();
-
- str.flush();
- FileUtils.sync(fstr);
- str.close();
-
- // New settings successfully written, old ones are no longer
- // needed.
- mBackupStoppedPackagesFilename.delete();
- FileUtils.setPermissions(mStoppedPackagesFilename.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP
- |FileUtils.S_IROTH,
- -1, -1);
-
- // Done, all is good!
- return;
-
- } catch(java.io.IOException e) {
- Log.wtf(TAG, "Unable to write package manager stopped packages, "
- + " current changes will be lost at reboot", e);
- }
-
- // Clean up partially written files
- if (mStoppedPackagesFilename.exists()) {
- if (!mStoppedPackagesFilename.delete()) {
- Log.i(TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename);
- }
- }
- }
-
- // Note: assumed "stopped" field is already cleared in all packages.
- void readStoppedLP() {
- FileInputStream str = null;
- if (mBackupStoppedPackagesFilename.exists()) {
- try {
- str = new FileInputStream(mBackupStoppedPackagesFilename);
- mReadMessages.append("Reading from backup stopped packages file\n");
- reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file");
- if (mSettingsFilename.exists()) {
- // If both the backup and normal file exist, we
- // ignore the normal one since it might have been
- // corrupted.
- Slog.w(TAG, "Cleaning up stopped packages file "
- + mStoppedPackagesFilename);
- mStoppedPackagesFilename.delete();
- }
- } catch (java.io.IOException e) {
- // We'll try for the normal settings file.
- }
- }
-
- try {
- if (str == null) {
- if (!mStoppedPackagesFilename.exists()) {
- mReadMessages.append("No stopped packages file found\n");
- reportSettingsProblem(Log.INFO, "No stopped packages file file; "
- + "assuming all started");
- // At first boot, make sure no packages are stopped.
- // We usually want to have third party apps initialize
- // in the stopped state, but not at first boot.
- for (PackageSetting pkg : mPackages.values()) {
- pkg.stopped = false;
- pkg.notLaunched = false;
- }
- return;
- }
- str = new FileInputStream(mStoppedPackagesFilename);
- }
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(str, null);
-
- int type;
- while ((type=parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- mReadMessages.append("No start tag found in stopped packages file\n");
- reportSettingsProblem(Log.WARN,
- "No start tag found in package manager stopped packages");
- return;
- }
-
- int outerDepth = parser.getDepth();
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("pkg")) {
- String name = parser.getAttributeValue(null, "name");
- PackageSetting ps = mPackages.get(name);
- if (ps != null) {
- ps.stopped = true;
- if ("1".equals(parser.getAttributeValue(null, "nl"))) {
- ps.notLaunched = true;
- }
- } else {
- Slog.w(TAG, "No package known for stopped package: " + name);
- }
- XmlUtils.skipCurrentTag(parser);
- } else {
- Slog.w(TAG, "Unknown element under <stopped-packages>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- str.close();
-
- } catch(XmlPullParserException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e);
- Log.wtf(TAG, "Error reading package manager stopped packages", e);
-
- } catch(java.io.IOException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
- Log.wtf(TAG, "Error reading package manager stopped packages", e);
-
- }
- }
-
- void writeLP() {
- //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
-
- // Keep the old settings around until we know the new ones have
- // been successfully written.
- if (mSettingsFilename.exists()) {
- // Presence of backup settings file indicates that we failed
- // to persist settings earlier. So preserve the older
- // backup for future reference since the current settings
- // might have been corrupted.
- if (!mBackupSettingsFilename.exists()) {
- if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
- Log.wtf(TAG, "Unable to backup package manager settings, "
- + " current changes will be lost at reboot");
- return;
- }
- } else {
- mSettingsFilename.delete();
- Slog.w(TAG, "Preserving older settings backup");
- }
- }
-
- mPastSignatures.clear();
-
- try {
- FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
- BufferedOutputStream str = new BufferedOutputStream(fstr);
-
- //XmlSerializer serializer = XmlUtils.serializerInstance();
- XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(str, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startTag(null, "packages");
-
- serializer.startTag(null, "last-platform-version");
- serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
- serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
- serializer.endTag(null, "last-platform-version");
-
- serializer.startTag(null, "permission-trees");
- for (BasePermission bp : mPermissionTrees.values()) {
- writePermission(serializer, bp);
- }
- serializer.endTag(null, "permission-trees");
-
- serializer.startTag(null, "permissions");
- for (BasePermission bp : mPermissions.values()) {
- writePermission(serializer, bp);
- }
- serializer.endTag(null, "permissions");
-
- for (PackageSetting pkg : mPackages.values()) {
- writePackage(serializer, pkg);
- }
-
- for (PackageSetting pkg : mDisabledSysPackages.values()) {
- writeDisabledSysPackage(serializer, pkg);
- }
-
- serializer.startTag(null, "preferred-activities");
- for (PreferredActivity pa : mPreferredActivities.filterSet()) {
- serializer.startTag(null, "item");
- pa.writeToXml(serializer);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "preferred-activities");
-
- for (SharedUserSetting usr : mSharedUsers.values()) {
- serializer.startTag(null, "shared-user");
- serializer.attribute(null, "name", usr.name);
- serializer.attribute(null, "userId",
- Integer.toString(usr.userId));
- usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
- serializer.startTag(null, "perms");
- for (String name : usr.grantedPermissions) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "perms");
- serializer.endTag(null, "shared-user");
- }
-
- if (mPackagesToBeCleaned.size() > 0) {
- for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
- serializer.startTag(null, "cleaning-package");
- serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
- serializer.endTag(null, "cleaning-package");
- }
- }
-
- if (mRenamedPackages.size() > 0) {
- for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
- serializer.startTag(null, "renamed-package");
- serializer.attribute(null, "new", e.getKey());
- serializer.attribute(null, "old", e.getValue());
- serializer.endTag(null, "renamed-package");
- }
- }
-
- serializer.endTag(null, "packages");
-
- serializer.endDocument();
-
- str.flush();
- FileUtils.sync(fstr);
- str.close();
-
- // New settings successfully written, old ones are no longer
- // needed.
- mBackupSettingsFilename.delete();
- FileUtils.setPermissions(mSettingsFilename.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP
- |FileUtils.S_IROTH,
- -1, -1);
-
- // Write package list file now, use a JournaledFile.
- //
- File tempFile = new File(mPackageListFilename.toString() + ".tmp");
- JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
-
- fstr = new FileOutputStream(journal.chooseForWrite());
- str = new BufferedOutputStream(fstr);
- try {
- StringBuilder sb = new StringBuilder();
- for (PackageSetting pkg : mPackages.values()) {
- ApplicationInfo ai = pkg.pkg.applicationInfo;
- String dataPath = ai.dataDir;
- boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-
- // Avoid any application that has a space in its path
- // or that is handled by the system.
- if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
- continue;
-
- // we store on each line the following information for now:
- //
- // pkgName - package name
- // userId - application-specific user id
- // debugFlag - 0 or 1 if the package is debuggable.
- // dataPath - path to package's data path
- //
- // NOTE: We prefer not to expose all ApplicationInfo flags for now.
- //
- // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
- // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
- // system/core/run-as/run-as.c
- //
- sb.setLength(0);
- sb.append(ai.packageName);
- sb.append(" ");
- sb.append((int)ai.uid);
- sb.append(isDebug ? " 1 " : " 0 ");
- sb.append(dataPath);
- sb.append("\n");
- str.write(sb.toString().getBytes());
- }
- str.flush();
- FileUtils.sync(fstr);
- str.close();
- journal.commit();
- }
- catch (Exception e) {
- journal.rollback();
- }
-
- FileUtils.setPermissions(mPackageListFilename.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP
- |FileUtils.S_IROTH,
- -1, -1);
-
- writeStoppedLP();
-
- return;
-
- } catch(XmlPullParserException e) {
- Log.wtf(TAG, "Unable to write package manager settings, "
- + "current changes will be lost at reboot", e);
- } catch(java.io.IOException e) {
- Log.wtf(TAG, "Unable to write package manager settings, "
- + "current changes will be lost at reboot", e);
- }
- // Clean up partially written files
- if (mSettingsFilename.exists()) {
- if (!mSettingsFilename.delete()) {
- Log.wtf(TAG, "Failed to clean up mangled file: " + mSettingsFilename);
- }
- }
- //Debug.stopMethodTracing();
- }
-
- void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
- serializer.startTag(null, "updated-package");
- serializer.attribute(null, "name", pkg.name);
- if (pkg.realName != null) {
- serializer.attribute(null, "realName", pkg.realName);
- }
- serializer.attribute(null, "codePath", pkg.codePathString);
- serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
- serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
- serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
- serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
- if (pkg.nativeLibraryPathString != null) {
- serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
- }
- if (pkg.sharedUser == null) {
- serializer.attribute(null, "userId",
- Integer.toString(pkg.userId));
- } else {
- serializer.attribute(null, "sharedUserId",
- Integer.toString(pkg.userId));
- }
- serializer.startTag(null, "perms");
- if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (final String name : pkg.grantedPermissions) {
- BasePermission bp = mPermissions.get(name);
- if (bp != null) {
- // We only need to write signature or system permissions but this wont
- // match the semantics of grantedPermissions. So write all permissions.
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- }
- }
- serializer.endTag(null, "perms");
- serializer.endTag(null, "updated-package");
- }
-
- void writePackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
- serializer.startTag(null, "package");
- serializer.attribute(null, "name", pkg.name);
- if (pkg.realName != null) {
- serializer.attribute(null, "realName", pkg.realName);
- }
- serializer.attribute(null, "codePath", pkg.codePathString);
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
- if (pkg.nativeLibraryPathString != null) {
- serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
- }
- serializer.attribute(null, "flags",
- Integer.toString(pkg.pkgFlags));
- serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
- serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
- serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
- serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
- if (pkg.sharedUser == null) {
- serializer.attribute(null, "userId",
- Integer.toString(pkg.userId));
- } else {
- serializer.attribute(null, "sharedUserId",
- Integer.toString(pkg.userId));
- }
- if (pkg.uidError) {
- serializer.attribute(null, "uidError", "true");
- }
- if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
- serializer.attribute(null, "enabled",
- pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
- ? "true" : "false");
- }
- if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
- serializer.attribute(null, "installStatus", "false");
- }
- if (pkg.installerPackageName != null) {
- serializer.attribute(null, "installer", pkg.installerPackageName);
- }
- pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
- if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- serializer.startTag(null, "perms");
- if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (final String name : pkg.grantedPermissions) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- }
- serializer.endTag(null, "perms");
- }
- if (pkg.disabledComponents.size() > 0) {
- serializer.startTag(null, "disabled-components");
- for (final String name : pkg.disabledComponents) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "disabled-components");
- }
- if (pkg.enabledComponents.size() > 0) {
- serializer.startTag(null, "enabled-components");
- for (final String name : pkg.enabledComponents) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "enabled-components");
- }
-
- serializer.endTag(null, "package");
- }
-
- void writePermission(XmlSerializer serializer, BasePermission bp)
- throws XmlPullParserException, java.io.IOException {
- if (bp.type != BasePermission.TYPE_BUILTIN
- && bp.sourcePackage != null) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", bp.name);
- serializer.attribute(null, "package", bp.sourcePackage);
- if (bp.protectionLevel !=
- PermissionInfo.PROTECTION_NORMAL) {
- serializer.attribute(null, "protection",
- Integer.toString(bp.protectionLevel));
- }
- if (DEBUG_SETTINGS) Log.v(TAG,
- "Writing perm: name=" + bp.name + " type=" + bp.type);
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- PermissionInfo pi = bp.perm != null ? bp.perm.info
- : bp.pendingInfo;
- if (pi != null) {
- serializer.attribute(null, "type", "dynamic");
- if (pi.icon != 0) {
- serializer.attribute(null, "icon",
- Integer.toString(pi.icon));
- }
- if (pi.nonLocalizedLabel != null) {
- serializer.attribute(null, "label",
- pi.nonLocalizedLabel.toString());
- }
- }
- }
- serializer.endTag(null, "item");
- }
- }
-
- ArrayList<PackageSetting> getListOfIncompleteInstallPackages() {
- HashSet<String> kList = new HashSet<String>(mPackages.keySet());
- Iterator<String> its = kList.iterator();
- ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
- while(its.hasNext()) {
- String key = its.next();
- PackageSetting ps = mPackages.get(key);
- if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) {
- ret.add(ps);
- }
- }
- return ret;
- }
-
- boolean readLP() {
- FileInputStream str = null;
- if (mBackupSettingsFilename.exists()) {
- try {
- str = new FileInputStream(mBackupSettingsFilename);
- mReadMessages.append("Reading from backup settings file\n");
- reportSettingsProblem(Log.INFO, "Need to read from backup settings file");
- if (mSettingsFilename.exists()) {
- // If both the backup and settings file exist, we
- // ignore the settings since it might have been
- // corrupted.
- Slog.w(TAG, "Cleaning up settings file " + mSettingsFilename);
- mSettingsFilename.delete();
- }
- } catch (java.io.IOException e) {
- // We'll try for the normal settings file.
- }
- }
-
- mPastSignatures.clear();
-
- try {
- if (str == null) {
- if (!mSettingsFilename.exists()) {
- mReadMessages.append("No settings file found\n");
- reportSettingsProblem(Log.INFO, "No settings file; creating initial state");
- return false;
- }
- str = new FileInputStream(mSettingsFilename);
- }
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(str, null);
-
- int type;
- while ((type=parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- mReadMessages.append("No start tag found in settings file\n");
- reportSettingsProblem(Log.WARN, "No start tag found in package manager settings");
- Log.wtf(TAG, "No start tag found in package manager settings");
- return false;
- }
-
- int outerDepth = parser.getDepth();
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("package")) {
- readPackageLP(parser);
- } else if (tagName.equals("permissions")) {
- readPermissionsLP(mPermissions, parser);
- } else if (tagName.equals("permission-trees")) {
- readPermissionsLP(mPermissionTrees, parser);
- } else if (tagName.equals("shared-user")) {
- readSharedUserLP(parser);
- } else if (tagName.equals("preferred-packages")) {
- // no longer used.
- } else if (tagName.equals("preferred-activities")) {
- readPreferredActivitiesLP(parser);
- } else if(tagName.equals("updated-package")) {
- readDisabledSysPackageLP(parser);
- } else if (tagName.equals("cleaning-package")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- mPackagesToBeCleaned.add(name);
- }
- } else if (tagName.equals("renamed-package")) {
- String nname = parser.getAttributeValue(null, "new");
- String oname = parser.getAttributeValue(null, "old");
- if (nname != null && oname != null) {
- mRenamedPackages.put(nname, oname);
- }
- } else if (tagName.equals("last-platform-version")) {
- mInternalSdkPlatform = mExternalSdkPlatform = 0;
- try {
- String internal = parser.getAttributeValue(null, "internal");
- if (internal != null) {
- mInternalSdkPlatform = Integer.parseInt(internal);
- }
- String external = parser.getAttributeValue(null, "external");
- if (external != null) {
- mExternalSdkPlatform = Integer.parseInt(external);
- }
- } catch (NumberFormatException e) {
- }
- } else {
- Slog.w(TAG, "Unknown element under <packages>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- str.close();
-
- } catch(XmlPullParserException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
- Log.wtf(TAG, "Error reading package manager settings", e);
-
- } catch(java.io.IOException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
- Log.wtf(TAG, "Error reading package manager settings", e);
-
- }
-
- final int N = mPendingPackages.size();
- for (int i=0; i<N; i++) {
- final PendingPackage pp = mPendingPackages.get(i);
- Object idObj = getUserIdLP(pp.sharedId);
- if (idObj != null && idObj instanceof SharedUserSetting) {
- PackageSetting p = getPackageLP(pp.name, null, pp.realName,
- (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
- pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
- if (p == null) {
- reportSettingsProblem(Log.WARN, "Unable to create application package for "
- + pp.name);
- continue;
- }
- p.copyFrom(pp);
- } else if (idObj != null) {
- String msg = "Bad package setting: package " + pp.name
- + " has shared uid " + pp.sharedId
- + " that is not a shared uid\n";
- mReadMessages.append(msg);
- reportSettingsProblem(Log.ERROR, msg);
- } else {
- String msg = "Bad package setting: package " + pp.name
- + " has shared uid " + pp.sharedId
- + " that is not defined\n";
- mReadMessages.append(msg);
- reportSettingsProblem(Log.ERROR, msg);
- }
- }
- mPendingPackages.clear();
-
- readStoppedLP();
-
- mReadMessages.append("Read completed successfully: "
- + mPackages.size() + " packages, "
- + mSharedUsers.size() + " shared uids\n");
-
- return true;
- }
-
- private int readInt(XmlPullParser parser, String ns, String name,
- int defValue) {
- String v = parser.getAttributeValue(ns, name);
- try {
- if (v == null) {
- return defValue;
- }
- return Integer.parseInt(v);
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: attribute " +
- name + " has bad integer value " + v + " at "
- + parser.getPositionDescription());
- }
- return defValue;
- }
-
- private void readPermissionsLP(HashMap<String, BasePermission> out,
- XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- String sourcePackage = parser.getAttributeValue(null, "package");
- String ptype = parser.getAttributeValue(null, "type");
- if (name != null && sourcePackage != null) {
- boolean dynamic = "dynamic".equals(ptype);
- BasePermission bp = new BasePermission(name, sourcePackage,
- dynamic
- ? BasePermission.TYPE_DYNAMIC
- : BasePermission.TYPE_NORMAL);
- bp.protectionLevel = readInt(parser, null, "protection",
- PermissionInfo.PROTECTION_NORMAL);
- if (dynamic) {
- PermissionInfo pi = new PermissionInfo();
- pi.packageName = sourcePackage.intern();
- pi.name = name.intern();
- pi.icon = readInt(parser, null, "icon", 0);
- pi.nonLocalizedLabel = parser.getAttributeValue(
- null, "label");
- pi.protectionLevel = bp.protectionLevel;
- bp.pendingInfo = pi;
- }
- out.put(bp.name, bp);
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: permissions has"
- + " no name at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element reading permissions: "
- + parser.getName() + " at "
- + parser.getPositionDescription());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readDisabledSysPackageLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String name = parser.getAttributeValue(null, "name");
- String realName = parser.getAttributeValue(null, "realName");
- String codePathStr = parser.getAttributeValue(null, "codePath");
- String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
- String version = parser.getAttributeValue(null, "version");
- int versionCode = 0;
- if (version != null) {
- try {
- versionCode = Integer.parseInt(version);
- } catch (NumberFormatException e) {
- }
- }
-
- int pkgFlags = 0;
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
- new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
- String timeStampStr = parser.getAttributeValue(null, "ft");
- if (timeStampStr != null) {
- try {
- long timeStamp = Long.parseLong(timeStampStr, 16);
- ps.setTimeStamp(timeStamp);
- } catch (NumberFormatException e) {
- }
- } else {
- timeStampStr = parser.getAttributeValue(null, "ts");
- if (timeStampStr != null) {
- try {
- long timeStamp = Long.parseLong(timeStampStr);
- ps.setTimeStamp(timeStamp);
- } catch (NumberFormatException e) {
- }
- }
- }
- timeStampStr = parser.getAttributeValue(null, "it");
- if (timeStampStr != null) {
- try {
- ps.firstInstallTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- timeStampStr = parser.getAttributeValue(null, "ut");
- if (timeStampStr != null) {
- try {
- ps.lastUpdateTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- String idStr = parser.getAttributeValue(null, "userId");
- ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if(ps.userId <= 0) {
- String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
- ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
- }
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser,
- ps.grantedPermissions);
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <updated-package>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- mDisabledSysPackages.put(name, ps);
- }
-
- private void readPackageLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String name = null;
- String realName = null;
- String idStr = null;
- String sharedIdStr = null;
- String codePathStr = null;
- String resourcePathStr = null;
- String nativeLibraryPathStr = null;
- String systemStr = null;
- String installerPackageName = null;
- String uidError = null;
- int pkgFlags = 0;
- long timeStamp = 0;
- long firstInstallTime = 0;
- long lastUpdateTime = 0;
- PackageSettingBase packageSetting = null;
- String version = null;
- int versionCode = 0;
- try {
- name = parser.getAttributeValue(null, "name");
- realName = parser.getAttributeValue(null, "realName");
- idStr = parser.getAttributeValue(null, "userId");
- uidError = parser.getAttributeValue(null, "uidError");
- sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
- codePathStr = parser.getAttributeValue(null, "codePath");
- resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- version = parser.getAttributeValue(null, "version");
- if (version != null) {
- try {
- versionCode = Integer.parseInt(version);
- } catch (NumberFormatException e) {
- }
- }
- installerPackageName = parser.getAttributeValue(null, "installer");
-
- systemStr = parser.getAttributeValue(null, "flags");
- if (systemStr != null) {
- try {
- pkgFlags = Integer.parseInt(systemStr);
- } catch (NumberFormatException e) {
- }
- } else {
- // For backward compatibility
- systemStr = parser.getAttributeValue(null, "system");
- if (systemStr != null) {
- pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM : 0;
- } else {
- // Old settings that don't specify system... just treat
- // them as system, good enough.
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- }
- }
- String timeStampStr = parser.getAttributeValue(null, "ft");
- if (timeStampStr != null) {
- try {
- timeStamp = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- } else {
- timeStampStr = parser.getAttributeValue(null, "ts");
- if (timeStampStr != null) {
- try {
- timeStamp = Long.parseLong(timeStampStr);
- } catch (NumberFormatException e) {
- }
- }
- }
- timeStampStr = parser.getAttributeValue(null, "it");
- if (timeStampStr != null) {
- try {
- firstInstallTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- timeStampStr = parser.getAttributeValue(null, "ut");
- if (timeStampStr != null) {
- try {
- lastUpdateTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name
- + " userId=" + idStr + " sharedUserId=" + sharedIdStr);
- int userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
- if (realName != null) {
- realName = realName.intern();
- }
- if (name == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <package> has no name at "
- + parser.getPositionDescription());
- } else if (codePathStr == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <package> has no codePath at "
- + parser.getPositionDescription());
- } else if (userId > 0) {
- packageSetting = addPackageLP(name.intern(), realName, new File(codePathStr),
- new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode,
- pkgFlags);
- if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
- + ": userId=" + userId + " pkg=" + packageSetting);
- if (packageSetting == null) {
- reportSettingsProblem(Log.ERROR,
- "Failure adding uid " + userId
- + " while parsing settings at "
- + parser.getPositionDescription());
- } else {
- packageSetting.setTimeStamp(timeStamp);
- packageSetting.firstInstallTime = firstInstallTime;
- packageSetting.lastUpdateTime = lastUpdateTime;
- }
- } else if (sharedIdStr != null) {
- userId = sharedIdStr != null
- ? Integer.parseInt(sharedIdStr) : 0;
- if (userId > 0) {
- packageSetting = new PendingPackage(name.intern(), realName,
- new File(codePathStr), new File(resourcePathStr),
- nativeLibraryPathStr, userId, versionCode, pkgFlags);
- packageSetting.setTimeStamp(timeStamp);
- packageSetting.firstInstallTime = firstInstallTime;
- packageSetting.lastUpdateTime = lastUpdateTime;
- mPendingPackages.add((PendingPackage) packageSetting);
- if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
- + ": sharedUserId=" + userId + " pkg="
- + packageSetting);
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad sharedId " + sharedIdStr
- + " at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- }
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- }
- if (packageSetting != null) {
- packageSetting.uidError = "true".equals(uidError);
- packageSetting.installerPackageName = installerPackageName;
- packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
- final String enabledStr = parser.getAttributeValue(null, "enabled");
- if (enabledStr != null) {
- if (enabledStr.equalsIgnoreCase("true")) {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
- } else if (enabledStr.equalsIgnoreCase("false")) {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
- } else if (enabledStr.equalsIgnoreCase("default")) {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad enabled value: " + idStr
- + " at " + parser.getPositionDescription());
- }
- } else {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- }
- final String installStatusStr = parser.getAttributeValue(null, "installStatus");
- if (installStatusStr != null) {
- if (installStatusStr.equalsIgnoreCase("false")) {
- packageSetting.installStatus = PKG_INSTALL_INCOMPLETE;
- } else {
- packageSetting.installStatus = PKG_INSTALL_COMPLETE;
- }
- }
-
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("disabled-components")) {
- readDisabledComponentsLP(packageSetting, parser);
- } else if (tagName.equals("enabled-components")) {
- readEnabledComponentsLP(packageSetting, parser);
- } else if (tagName.equals("sigs")) {
- packageSetting.signatures.readXml(parser, mPastSignatures);
- } else if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser,
- packageSetting.grantedPermissions);
- packageSetting.permissionsFixed = true;
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <package>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- } else {
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readDisabledComponentsLP(PackageSettingBase packageSetting,
- XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- packageSetting.disabledComponents.add(name.intern());
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <disabled-components> has"
- + " no name at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <disabled-components>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readEnabledComponentsLP(PackageSettingBase packageSetting,
- XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- packageSetting.enabledComponents.add(name.intern());
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <enabled-components> has"
- + " no name at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <enabled-components>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readSharedUserLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String name = null;
- String idStr = null;
- int pkgFlags = 0;
- SharedUserSetting su = null;
- try {
- name = parser.getAttributeValue(null, "name");
- idStr = parser.getAttributeValue(null, "userId");
- int userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if ("true".equals(parser.getAttributeValue(null, "system"))) {
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- }
- if (name == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <shared-user> has no name at "
- + parser.getPositionDescription());
- } else if (userId == 0) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: shared-user "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- } else {
- if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) {
- reportSettingsProblem(Log.ERROR,
- "Occurred while parsing settings at "
- + parser.getPositionDescription());
- }
- }
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- };
-
- if (su != null) {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("sigs")) {
- su.signatures.readXml(parser, mPastSignatures);
- } else if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser, su.grantedPermissions);
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <shared-user>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- } else {
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readGrantedPermissionsLP(XmlPullParser parser,
- HashSet<String> outPerms) throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- outPerms.add(name.intern());
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <perms> has"
- + " no name at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <perms>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readPreferredActivitiesLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- PreferredActivity pa = new PreferredActivity(parser);
- if (pa.mPref.getParseError() == null) {
- mPreferredActivities.addFilter(pa);
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <preferred-activity> "
- + pa.mPref.getParseError() + " at "
- + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- }
-
- // Returns -1 if we could not find an available UserId to assign
- private int newUserIdLP(Object obj) {
- // Let's be stupidly inefficient for now...
- final int N = mUserIds.size();
- for (int i=0; i<N; i++) {
- if (mUserIds.get(i) == null) {
- mUserIds.set(i, obj);
- return FIRST_APPLICATION_UID + i;
- }
- }
-
- // None left?
- if (N >= MAX_APPLICATION_UIDS) {
- return -1;
- }
-
- mUserIds.add(obj);
- return FIRST_APPLICATION_UID + N;
- }
-
- public PackageSetting getDisabledSystemPkg(String name) {
- synchronized(mPackages) {
- PackageSetting ps = mDisabledSysPackages.get(name);
- return ps;
- }
- }
-
- boolean isEnabledLP(ComponentInfo componentInfo, int flags) {
- if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
- return true;
- }
- final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
- if (DEBUG_SETTINGS) {
- Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName
- + " componentName = " + componentInfo.name);
- Log.v(TAG, "enabledComponents: "
- + Arrays.toString(packageSettings.enabledComponents.toArray()));
- Log.v(TAG, "disabledComponents: "
- + Arrays.toString(packageSettings.disabledComponents.toArray()));
- }
- if (packageSettings == null) {
- return false;
- }
- if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
- || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
- && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
- return false;
- }
- if (packageSettings.enabledComponents.contains(componentInfo.name)) {
- return true;
- }
- if (packageSettings.disabledComponents.contains(componentInfo.name)) {
- return false;
- }
- return componentInfo.enabled;
- }
- }
-
// ------- apps on sdcard specific code -------
static final boolean DEBUG_SD_INSTALL = false;
+
private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD";
+
private static final String SD_ENCRYPTION_ALGORITHM = "AES";
- static final int MAX_CONTAINERS = 250;
+
private boolean mMediaMounted = false;
private String getEncryptKey() {
@@ -9956,14 +7429,13 @@
Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
return null;
} catch (IOException ioe) {
- Slog.e(TAG, "Failed to retrieve encryption keys with exception: "
- + ioe);
+ Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe);
return null;
}
}
- /* package */ static String getTempContainerId() {
+ /* package */static String getTempContainerId() {
int tmpIdx = 1;
String list[] = PackageHelper.getSecureContainerList();
if (list != null) {
@@ -9986,416 +7458,450 @@
return mTempContainerPrefix + tmpIdx;
}
- /*
- * Update media status on PackageManager.
- */
- public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
- int callingUid = Binder.getCallingUid();
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("Media status can only be updated by the system");
- }
- synchronized (mPackages) {
- Log.i(TAG, "Updating external media status from " +
- (mMediaMounted ? "mounted" : "unmounted") + " to " +
- (mediaStatus ? "mounted" : "unmounted"));
- if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
- mediaStatus+", mMediaMounted=" + mMediaMounted);
- if (mediaStatus == mMediaMounted) {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, -1);
- mHandler.sendMessage(msg);
- return;
- }
- mMediaMounted = mediaStatus;
- }
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- updateExternalMediaStatusInner(mediaStatus, reportStatus);
- }
- });
- }
+ /*
+ * Update media status on PackageManager.
+ */
+ public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("Media status can only be updated by the system");
+ }
+ // reader; this apparently protects mMediaMounted, but should probably
+ // be a different lock in that case.
+ synchronized (mPackages) {
+ Log.i(TAG, "Updating external media status from "
+ + (mMediaMounted ? "mounted" : "unmounted") + " to "
+ + (mediaStatus ? "mounted" : "unmounted"));
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus
+ + ", mMediaMounted=" + mMediaMounted);
+ if (mediaStatus == mMediaMounted) {
+ final Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1
+ : 0, -1);
+ mHandler.sendMessage(msg);
+ return;
+ }
+ mMediaMounted = mediaStatus;
+ }
+ // Queue up an async operation since the package installation may take a
+ // little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ // TODO fix this; this does nothing.
+ mHandler.removeCallbacks(this);
+ updateExternalMediaStatusInner(mediaStatus, reportStatus);
+ }
+ });
+ }
+
+ /*
+ * Collect information of applications on external media, map them against
+ * existing containers and update information based on current mount status.
+ * Please note that we always have to report status if reportStatus has been
+ * set to true especially when unloading packages.
+ */
+ private void updateExternalMediaStatusInner(boolean mediaStatus, boolean reportStatus) {
+ // Collection of uids
+ int uidArr[] = null;
+ // Collection of stale containers
+ HashSet<String> removeCids = new HashSet<String>();
+ // Collection of packages on external media with valid containers.
+ HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+ // Get list of secure containers.
+ final String list[] = PackageHelper.getSecureContainerList();
+ if (list == null || list.length == 0) {
+ Log.i(TAG, "No secure containers on sdcard");
+ } else {
+ // Process list of secure containers and categorize them
+ // as active or stale based on their package internal state.
+ int uidList[] = new int[list.length];
+ int num = 0;
+ // reader
+ synchronized (mPackages) {
+ for (String cid : list) {
+ SdInstallArgs args = new SdInstallArgs(cid);
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Processing container " + cid);
+ String pkgName = args.getPackageName();
+ if (pkgName == null) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
+ continue;
+ }
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Looking for pkg : " + pkgName);
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ // The package status is changed only if the code path
+ // matches between settings and the container id.
+ if (ps != null && ps.codePathString != null
+ && ps.codePathString.equals(args.getCodePath())) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName
+ + " at code path: " + ps.codePathString);
+ // We do have a valid package installed on sdcard
+ processCids.put(args, ps.codePathString);
+ int uid = ps.userId;
+ if (uid != -1) {
+ uidList[num++] = uid;
+ }
+ } else {
+ // Stale container on sdcard. Just delete
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
+ }
+ }
+ }
+
+ if (num > 0) {
+ // Sort uid list
+ Arrays.sort(uidList, 0, num);
+ // Throw away duplicates
+ uidArr = new int[num];
+ uidArr[0] = uidList[0];
+ int di = 0;
+ for (int i = 1; i < num; i++) {
+ if (uidList[i - 1] != uidList[i]) {
+ uidArr[di++] = uidList[i];
+ }
+ }
+ }
+ }
+ // Process packages with valid entries.
+ if (mediaStatus) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Loading packages");
+ loadMediaPackages(processCids, uidArr, removeCids);
+ startCleaningPackages();
+ } else {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Unloading packages");
+ unloadMediaPackages(processCids, uidArr, reportStatus);
+ }
+ }
+
+ private void sendResourcesChangedBroadcast(boolean mediaStatus, ArrayList<String> pkgList,
+ int uidArr[], IIntentReceiver finishedReceiver) {
+ int size = pkgList.size();
+ if (size > 0) {
+ // Send broadcasts here
+ Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList
+ .toArray(new String[size]));
+ if (uidArr != null) {
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+ }
+ String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+ : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
+ sendPackageBroadcast(action, null, extras, null, finishedReceiver);
+ }
+ }
/*
- * Collect information of applications on external media, map them
- * against existing containers and update information based on current
- * mount status. Please note that we always have to report status
- * if reportStatus has been set to true especially when unloading packages.
- */
- private void updateExternalMediaStatusInner(boolean mediaStatus,
- boolean reportStatus) {
- // Collection of uids
- int uidArr[] = null;
- // Collection of stale containers
- HashSet<String> removeCids = new HashSet<String>();
- // Collection of packages on external media with valid containers.
- HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
- // Get list of secure containers.
- final String list[] = PackageHelper.getSecureContainerList();
- if (list == null || list.length == 0) {
- Log.i(TAG, "No secure containers on sdcard");
- } else {
- // Process list of secure containers and categorize them
- // as active or stale based on their package internal state.
- int uidList[] = new int[list.length];
- int num = 0;
- synchronized (mPackages) {
- for (String cid : list) {
- SdInstallArgs args = new SdInstallArgs(cid);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
- String pkgName = args.getPackageName();
- if (pkgName == null) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
- removeCids.add(cid);
- continue;
- }
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- // The package status is changed only if the code path
- // matches between settings and the container id.
- if (ps != null && ps.codePathString != null &&
- ps.codePathString.equals(args.getCodePath())) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid +
- " corresponds to pkg : " + pkgName +
- " at code path: " + ps.codePathString);
- // We do have a valid package installed on sdcard
- processCids.put(args, ps.codePathString);
- int uid = ps.userId;
- if (uid != -1) {
- uidList[num++] = uid;
- }
- } else {
- // Stale container on sdcard. Just delete
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
- removeCids.add(cid);
- }
+ * Look at potentially valid container ids from processCids If package
+ * information doesn't match the one on record or package scanning fails,
+ * the cid is added to list of removeCids. We currently don't delete stale
+ * containers.
+ */
+ private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[],
+ HashSet<String> removeCids) {
+ ArrayList<String> pkgList = new ArrayList<String>();
+ Set<SdInstallArgs> keys = processCids.keySet();
+ boolean doGc = false;
+ for (SdInstallArgs args : keys) {
+ String codePath = processCids.get(args);
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Loading container : " + args.cid);
+ int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+ try {
+ // Make sure there are no container errors first.
+ if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Failed to mount cid : " + args.cid
+ + " when installing from sdcard");
+ continue;
+ }
+ // Check code path here.
+ if (codePath == null || !codePath.equals(args.getCodePath())) {
+ Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()
+ + " does not match one in settings " + codePath);
+ continue;
+ }
+ // Parse package
+ int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+ doGc = true;
+ synchronized (mInstallLock) {
+ final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags,
+ 0, 0);
+ // Scan the package
+ if (pkg != null) {
+ /*
+ * TODO why is the lock being held? doPostInstall is
+ * called in other places without the lock. This needs
+ * to be straightened out.
+ */
+ // writer
+ synchronized (mPackages) {
+ retCode = PackageManager.INSTALL_SUCCEEDED;
+ pkgList.add(pkg.packageName);
+ // Post process args
+ args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
+ }
+ } else {
+ Slog.i(TAG, "Failed to install pkg from " + codePath + " from sdcard");
+ }
+ }
+
+ } finally {
+ if (retCode != PackageManager.INSTALL_SUCCEEDED) {
+ // Don't destroy container here. Wait till gc clears things
+ // up.
+ removeCids.add(args.cid);
+ }
+ }
+ }
+ // writer
+ synchronized (mPackages) {
+ // If the platform SDK has changed since the last time we booted,
+ // we need to re-grant app permission to catch any new ones that
+ // appear. This is really a hack, and means that apps can in some
+ // cases get permissions that the user didn't initially explicitly
+ // allow... it would be nice to have some better way to handle
+ // this situation.
+ final boolean regrantPermissions = mSettings.mExternalSdkPlatform != mSdkVersion;
+ if (regrantPermissions)
+ Slog.i(TAG, "Platform changed from " + mSettings.mExternalSdkPlatform + " to "
+ + mSdkVersion + "; regranting permissions for external storage");
+ mSettings.mExternalSdkPlatform = mSdkVersion;
+
+ // Make sure group IDs have been assigned, and any permission
+ // changes in other apps are accounted for
+ updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
+ // can downgrade to reader
+ // Persist settings
+ mSettings.writeLPr();
+ }
+ // Send a broadcast to let everyone know we are done processing
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
+ }
+ // Force gc to avoid any stale parser references that we might have.
+ if (doGc) {
+ Runtime.getRuntime().gc();
+ }
+ // List stale containers and destroy stale temporary containers.
+ if (removeCids != null) {
+ for (String cid : removeCids) {
+ if (cid.startsWith(mTempContainerPrefix)) {
+ Log.i(TAG, "Destroying stale temporary container " + cid);
+ PackageHelper.destroySdDir(cid);
+ } else {
+ Log.w(TAG, "Container " + cid + " is stale");
}
}
-
- if (num > 0) {
- // Sort uid list
- Arrays.sort(uidList, 0, num);
- // Throw away duplicates
- uidArr = new int[num];
- uidArr[0] = uidList[0];
- int di = 0;
- for (int i = 1; i < num; i++) {
- if (uidList[i-1] != uidList[i]) {
- uidArr[di++] = uidList[i];
- }
- }
- }
- }
- // Process packages with valid entries.
- if (mediaStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr, removeCids);
- startCleaningPackages();
- } else {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr, reportStatus);
- }
- }
-
- private void sendResourcesChangedBroadcast(boolean mediaStatus,
- ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
- int size = pkgList.size();
- if (size > 0) {
- // Send broadcasts here
- Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
- pkgList.toArray(new String[size]));
- if (uidArr != null) {
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
- }
- String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
- : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- sendPackageBroadcast(action, null, extras, null, finishedReceiver);
- }
- }
+ }
+ }
/*
- * Look at potentially valid container ids from processCids
- * If package information doesn't match the one on record
- * or package scanning fails, the cid is added to list of
- * removeCids. We currently don't delete stale containers.
- */
- private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], HashSet<String> removeCids) {
- ArrayList<String> pkgList = new ArrayList<String>();
- Set<SdInstallArgs> keys = processCids.keySet();
- boolean doGc = false;
- for (SdInstallArgs args : keys) {
- String codePath = processCids.get(args);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading container : "
- + args.cid);
- int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- try {
- // Make sure there are no container errors first.
- if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED)
- != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to mount cid : " + args.cid +
- " when installing from sdcard");
- continue;
- }
- // Check code path here.
- if (codePath == null || !codePath.equals(args.getCodePath())) {
- Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()+
- " does not match one in settings " + codePath);
- continue;
- }
- // Parse package
- int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
- doGc = true;
- synchronized (mInstallLock) {
- final PackageParser.Package pkg = scanPackageLI(new File(codePath),
- parseFlags, 0, 0);
- // Scan the package
- if (pkg != null) {
- synchronized (mPackages) {
- retCode = PackageManager.INSTALL_SUCCEEDED;
- pkgList.add(pkg.packageName);
- // Post process args
- args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
- }
- } else {
- Slog.i(TAG, "Failed to install pkg from " +
- codePath + " from sdcard");
- }
- }
-
- } finally {
- if (retCode != PackageManager.INSTALL_SUCCEEDED) {
- // Don't destroy container here. Wait till gc clears things up.
- removeCids.add(args.cid);
- }
- }
- }
- synchronized (mPackages) {
- // If the platform SDK has changed since the last time we booted,
- // we need to re-grant app permission to catch any new ones that
- // appear. This is really a hack, and means that apps can in some
- // cases get permissions that the user didn't initially explicitly
- // allow... it would be nice to have some better way to handle
- // this situation.
- final boolean regrantPermissions = mSettings.mExternalSdkPlatform
- != mSdkVersion;
- if (regrantPermissions) Slog.i(TAG, "Platform changed from "
- + mSettings.mExternalSdkPlatform + " to " + mSdkVersion
- + "; regranting permissions for external storage");
- mSettings.mExternalSdkPlatform = mSdkVersion;
-
- // Make sure group IDs have been assigned, and any permission
- // changes in other apps are accounted for
- updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
- // Persist settings
- mSettings.writeLP();
- }
- // Send a broadcast to let everyone know we are done processing
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
- }
- // Force gc to avoid any stale parser references that we might have.
- if (doGc) {
- Runtime.getRuntime().gc();
- }
- // List stale containers and destroy stale temporary containers.
- if (removeCids != null) {
- for (String cid : removeCids) {
- if (cid.startsWith(mTempContainerPrefix)) {
- Log.i(TAG, "Destroying stale temporary container " + cid);
- PackageHelper.destroySdDir(cid);
- } else {
- Log.w(TAG, "Container " + cid + " is stale");
- }
+ * Utility method to unload a list of specified containers
+ */
+ private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
+ // Just unmount all valid containers.
+ for (SdInstallArgs arg : cidArgs) {
+ synchronized (mInstallLock) {
+ arg.doPostDeleteLI(false);
}
}
}
- /*
- * Utility method to unload a list of specified containers
- */
- private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
- // Just unmount all valid containers.
- for (SdInstallArgs arg : cidArgs) {
- synchronized (mInstallLock) {
- arg.doPostDeleteLI(false);
- }
- }
- }
+ /*
+ * Unload packages mounted on external media. This involves deleting package
+ * data from internal structures, sending broadcasts about diabled packages,
+ * gc'ing to free up references, unmounting all secure containers
+ * corresponding to packages on external media, and posting a
+ * UPDATED_MEDIA_STATUS message if status has been requested. Please note
+ * that we always have to post this message if status has been requested no
+ * matter what.
+ */
+ private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[],
+ final boolean reportStatus) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "unloading media packages");
+ ArrayList<String> pkgList = new ArrayList<String>();
+ ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
+ final Set<SdInstallArgs> keys = processCids.keySet();
+ for (SdInstallArgs args : keys) {
+ String pkgName = args.getPackageName();
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Trying to unload pkg : " + pkgName);
+ // Delete package internally
+ PackageRemovedInfo outInfo = new PackageRemovedInfo();
+ synchronized (mInstallLock) {
+ boolean res = deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
+ outInfo, false);
+ if (res) {
+ pkgList.add(pkgName);
+ } else {
+ Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
+ failedList.add(args);
+ }
+ }
+ }
- /*
- * Unload packages mounted on external media. This involves deleting
- * package data from internal structures, sending broadcasts about
- * diabled packages, gc'ing to free up references, unmounting all
- * secure containers corresponding to packages on external media, and
- * posting a UPDATED_MEDIA_STATUS message if status has been requested.
- * Please note that we always have to post this message if status has
- * been requested no matter what.
- */
- private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], final boolean reportStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
- ArrayList<String> pkgList = new ArrayList<String>();
- ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
- final Set<SdInstallArgs> keys = processCids.keySet();
- for (SdInstallArgs args : keys) {
- String pkgName = args.getPackageName();
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName);
- // Delete package internally
- PackageRemovedInfo outInfo = new PackageRemovedInfo();
- synchronized (mInstallLock) {
- boolean res = deletePackageLI(pkgName, false,
- PackageManager.DONT_DELETE_DATA, outInfo, false);
- if (res) {
- pkgList.add(pkgName);
- } else {
- Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
- failedList.add(args);
- }
- }
- }
+ // reader
+ synchronized (mPackages) {
+ // We didn't update the settings after removing each package;
+ // write them now for all packages.
+ mSettings.writeLPr();
+ }
- synchronized (mPackages) {
- // We didn't update the settings after removing each package;
- // write them now for all packages.
- mSettings.writeLP();
- }
+ // We have to absolutely send UPDATED_MEDIA_STATUS only
+ // after confirming that all the receivers processed the ordered
+ // broadcast when packages get disabled, force a gc to clean things up.
+ // and unload all the containers.
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky) throws RemoteException {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, 1, keys);
+ mHandler.sendMessage(msg);
+ }
+ });
+ } else {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, -1,
+ keys);
+ mHandler.sendMessage(msg);
+ }
+ }
- // We have to absolutely send UPDATED_MEDIA_STATUS only
- // after confirming that all the receivers processed the ordered
- // broadcast when packages get disabled, force a gc to clean things up.
- // and unload all the containers.
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
- public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
- boolean ordered, boolean sticky) throws RemoteException {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, 1, keys);
- mHandler.sendMessage(msg);
- }
- });
- } else {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, -1, keys);
- mHandler.sendMessage(msg);
- }
- }
+ public void movePackage(final String packageName, final IPackageMoveObserver observer,
+ final int flags) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
+ int returnCode = PackageManager.MOVE_SUCCEEDED;
+ int currFlags = 0;
+ int newFlags = 0;
+ // reader
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else {
+ // Disable moving fwd locked apps and system packages
+ if (pkg.applicationInfo != null && isSystemApp(pkg)) {
+ Slog.w(TAG, "Cannot move system application");
+ returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+ } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) {
+ Slog.w(TAG, "Cannot move forward locked app.");
+ returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
+ } else if (pkg.mOperationPending) {
+ Slog.w(TAG, "Attempt to move package which has pending operations");
+ returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING;
+ } else {
+ // Find install location first
+ if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0
+ && (flags & PackageManager.MOVE_INTERNAL) != 0) {
+ Slog.w(TAG, "Ambigous flags specified for move location.");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ } else {
+ newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ? PackageManager.INSTALL_EXTERNAL
+ : PackageManager.INSTALL_INTERNAL;
+ currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL
+ : PackageManager.INSTALL_INTERNAL;
+ if (newFlags == currFlags) {
+ Slog.w(TAG, "No move required. Trying to move to same location");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ }
+ }
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ pkg.mOperationPending = true;
+ }
+ }
+ }
- public void movePackage(final String packageName,
- final IPackageMoveObserver observer, final int flags) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MOVE_PACKAGE, null);
- int returnCode = PackageManager.MOVE_SUCCEEDED;
- int currFlags = 0;
- int newFlags = 0;
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else {
- // Disable moving fwd locked apps and system packages
- if (pkg.applicationInfo != null && isSystemApp(pkg)) {
- Slog.w(TAG, "Cannot move system application");
- returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
- } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) {
- Slog.w(TAG, "Cannot move forward locked app.");
- returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
- } else if (pkg.mOperationPending) {
- Slog.w(TAG, "Attempt to move package which has pending operations");
- returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING;
- } else {
- // Find install location first
- if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 &&
- (flags & PackageManager.MOVE_INTERNAL) != 0) {
- Slog.w(TAG, "Ambigous flags specified for move location.");
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
- } else {
- newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
- PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
- currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL
- : PackageManager.INSTALL_INTERNAL;
- if (newFlags == currFlags) {
- Slog.w(TAG, "No move required. Trying to move to same location");
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
- }
- }
- if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mOperationPending = true;
- }
- }
- }
- if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+ /*
+ * TODO this next block probably shouldn't be inside the lock. We
+ * can't guarantee these won't change after this is fired off
+ * anyway.
+ */
+ if (returnCode != PackageManager.MOVE_SUCCEEDED) {
processPendingMove(new MoveParams(null, observer, 0, packageName, null), returnCode);
- } else {
- Message msg = mHandler.obtainMessage(INIT_COPY);
- InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
+ } else {
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir);
- MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
+ MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
pkg.applicationInfo.dataDir);
- msg.obj = mp;
- mHandler.sendMessage(msg);
- }
- }
- }
+ msg.obj = mp;
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
- private void processPendingMove(final MoveParams mp, final int currentStatus) {
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- int returnCode = currentStatus;
- if (currentStatus == PackageManager.MOVE_SUCCEEDED) {
- int uidArr[] = null;
- ArrayList<String> pkgList = null;
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- if (pkg == null) {
- Slog.w(TAG, " Package " + mp.packageName +
- " doesn't exist. Aborting move");
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
- Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
- mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
- " Aborting move and returning error");
- returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
- } else {
- uidArr = new int[] { pkg.applicationInfo.uid };
- pkgList = new ArrayList<String>();
- pkgList.add(mp.packageName);
- }
- }
- if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- // Send resources unavailable broadcast
- sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
- // Update package code and resource paths
- synchronized (mInstallLock) {
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- // Recheck for package again.
+ private void processPendingMove(final MoveParams mp, final int currentStatus) {
+ // Queue up an async operation since the package deletion may take a
+ // little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ // TODO fix this; this does nothing.
+ mHandler.removeCallbacks(this);
+ int returnCode = currentStatus;
+ if (currentStatus == PackageManager.MOVE_SUCCEEDED) {
+ int uidArr[] = null;
+ ArrayList<String> pkgList = null;
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg == null) {
+ Slog.w(TAG, " Package " + mp.packageName
+ + " doesn't exist. Aborting move");
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
+ Slog.w(TAG, "Package " + mp.packageName + " code path changed from "
+ + mp.srcArgs.getCodePath() + " to "
+ + pkg.applicationInfo.sourceDir
+ + " Aborting move and returning error");
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } else {
+ uidArr = new int[] {
+ pkg.applicationInfo.uid
+ };
+ pkgList = new ArrayList<String>();
+ pkgList.add(mp.packageName);
+ }
+ }
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ // Send resources unavailable broadcast
+ sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
+ // Update package code and resource paths
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ // Recheck for package again.
if (pkg == null) {
Slog.w(TAG, " Package " + mp.packageName
+ " doesn't exist. Aborting move");
returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
- Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
- mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
- " Aborting move and returning error");
- returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
- } else {
- final String oldCodePath = pkg.mPath;
- final String newCodePath = mp.targetArgs.getCodePath();
- final String newResPath = mp.targetArgs.getResourcePath();
- final String newNativePath = mp.targetArgs.getNativeLibraryPath();
+ } else if (!mp.srcArgs.getCodePath().equals(
+ pkg.applicationInfo.sourceDir)) {
+ Slog.w(TAG, "Package " + mp.packageName
+ + " code path changed from " + mp.srcArgs.getCodePath()
+ + " to " + pkg.applicationInfo.sourceDir
+ + " Aborting move and returning error");
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } else {
+ final String oldCodePath = pkg.mPath;
+ final String newCodePath = mp.targetArgs.getCodePath();
+ final String newResPath = mp.targetArgs.getResourcePath();
+ final String newNativePath = mp.targetArgs
+ .getNativeLibraryPath();
if ((mp.flags & PackageManager.INSTALL_EXTERNAL) == 0) {
if (mInstaller
.unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
} else {
- NativeLibraryHelper.copyNativeBinariesLI(
- new File(newCodePath), new File(newNativePath));
+ NativeLibraryHelper.copyNativeBinariesLI(new File(
+ newCodePath), new File(newNativePath));
}
} else {
if (mInstaller.linkNativeLibraryDirectory(
@@ -10416,90 +7922,92 @@
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mScanPath = newCodePath;
- pkg.applicationInfo.sourceDir = newCodePath;
- pkg.applicationInfo.publicSourceDir = newResPath;
- pkg.applicationInfo.nativeLibraryDir = newNativePath;
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- ps.codePath = new File(pkg.applicationInfo.sourceDir);
- ps.codePathString = ps.codePath.getPath();
- ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
- ps.resourcePathString = ps.resourcePath.getPath();
- ps.nativeLibraryPathString = newNativePath;
- // Set the application info flag correctly.
- if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
- } else {
- pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
- }
- ps.setFlags(pkg.applicationInfo.flags);
- mAppDirs.remove(oldCodePath);
- mAppDirs.put(newCodePath, pkg);
- // Persist settings
- mSettings.writeLP();
- }
- }
- }
- }
- // Send resources available broadcast
- sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
- }
- }
- if (returnCode != PackageManager.MOVE_SUCCEEDED){
- // Clean up failed installation
- if (mp.targetArgs != null) {
- mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
- }
- } else {
- // Force a gc to clear things up.
- Runtime.getRuntime().gc();
- // Delete older code
- synchronized (mInstallLock) {
- mp.srcArgs.doPostDeleteLI(true);
- }
- }
+ pkg.mScanPath = newCodePath;
+ pkg.applicationInfo.sourceDir = newCodePath;
+ pkg.applicationInfo.publicSourceDir = newResPath;
+ pkg.applicationInfo.nativeLibraryDir = newNativePath;
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ ps.codePath = new File(pkg.applicationInfo.sourceDir);
+ ps.codePathString = ps.codePath.getPath();
+ ps.resourcePath = new File(
+ pkg.applicationInfo.publicSourceDir);
+ ps.resourcePathString = ps.resourcePath.getPath();
+ ps.nativeLibraryPathString = newNativePath;
+ // Set the application info flag
+ // correctly.
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ } else {
+ pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ }
+ ps.setFlags(pkg.applicationInfo.flags);
+ mAppDirs.remove(oldCodePath);
+ mAppDirs.put(newCodePath, pkg);
+ // Persist settings
+ mSettings.writeLPr();
+ }
+ }
+ }
+ }
+ // Send resources available broadcast
+ sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
+ }
+ }
+ if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+ // Clean up failed installation
+ if (mp.targetArgs != null) {
+ mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ }
+ } else {
+ // Force a gc to clear things up.
+ Runtime.getRuntime().gc();
+ // Delete older code
+ synchronized (mInstallLock) {
+ mp.srcArgs.doPostDeleteLI(true);
+ }
+ }
- // Allow more operations on this file if we didn't fail because
- // an operation was already pending for this package.
- if (returnCode != PackageManager.MOVE_FAILED_OPERATION_PENDING) {
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- if (pkg != null) {
- pkg.mOperationPending = false;
+ // Allow more operations on this file if we didn't fail because
+ // an operation was already pending for this package.
+ if (returnCode != PackageManager.MOVE_FAILED_OPERATION_PENDING) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg != null) {
+ pkg.mOperationPending = false;
}
}
- }
+ }
- IPackageMoveObserver observer = mp.observer;
- if (observer != null) {
- try {
- observer.packageMoved(mp.packageName, returnCode);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- }
- }
- });
+ IPackageMoveObserver observer = mp.observer;
+ if (observer != null) {
+ try {
+ observer.packageMoved(mp.packageName, returnCode);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+ });
+ }
+
+ public boolean setInstallLocation(int loc) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ null);
+ if (getInstallLocation() == loc) {
+ return true;
+ }
+ if (loc == PackageHelper.APP_INSTALL_AUTO || loc == PackageHelper.APP_INSTALL_INTERNAL
+ || loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+ android.provider.Settings.System.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
+ return true;
+ }
+ return false;
}
- public boolean setInstallLocation(int loc) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
- if (getInstallLocation() == loc) {
- return true;
- }
- if (loc == PackageHelper.APP_INSTALL_AUTO ||
- loc == PackageHelper.APP_INSTALL_INTERNAL ||
- loc == PackageHelper.APP_INSTALL_EXTERNAL) {
- android.provider.Settings.System.putInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
- return true;
- }
- return false;
- }
-
- public int getInstallLocation() {
- return android.provider.Settings.System.getInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO);
- }
+ public int getInstallLocation() {
+ return android.provider.Settings.System.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION,
+ PackageHelper.APP_INSTALL_AUTO);
+ }
}
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java
new file mode 100644
index 0000000..efdc2b3
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageSetting.java
@@ -0,0 +1,55 @@
+/*
+ * 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.server.pm;
+
+import android.content.pm.PackageParser;
+
+import java.io.File;
+
+/**
+ * Settings data for a particular package we know about.
+ */
+final class PackageSetting extends PackageSettingBase {
+ int userId;
+ PackageParser.Package pkg;
+ SharedUserSetting sharedUser;
+
+ PackageSetting(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
+ pkgFlags);
+ }
+
+ /**
+ * New instance of PackageSetting replicating the original settings.
+ * Note that it keeps the same PackageParser.Package instance.
+ */
+ PackageSetting(PackageSetting orig) {
+ super(orig);
+
+ userId = orig.userId;
+ pkg = orig.pkg;
+ sharedUser = orig.sharedUser;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageSetting{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + name + "/" + userId + "}";
+ }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
new file mode 100644
index 0000000..e2f83ad
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -0,0 +1,207 @@
+/*
+ * 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.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
+
+import java.io.File;
+import java.util.HashSet;
+
+/**
+ * Settings base class for pending and resolved classes.
+ */
+class PackageSettingBase extends GrantedPermissions {
+ /**
+ * Indicates the state of installation. Used by PackageManager to figure out
+ * incomplete installations. Say a package is being installed (the state is
+ * set to PKG_INSTALL_INCOMPLETE) and remains so till the package
+ * installation is successful or unsuccessful in which case the
+ * PackageManager will no longer maintain state information associated with
+ * the package. If some exception(like device freeze or battery being pulled
+ * out) occurs during installation of a package, the PackageManager needs
+ * this information to clean up the previously failed installation.
+ */
+ static final int PKG_INSTALL_COMPLETE = 1;
+ static final int PKG_INSTALL_INCOMPLETE = 0;
+
+ final String name;
+ final String realName;
+ File codePath;
+ String codePathString;
+ File resourcePath;
+ String resourcePathString;
+ String nativeLibraryPathString;
+ long timeStamp;
+ long firstInstallTime;
+ long lastUpdateTime;
+ int versionCode;
+
+ boolean uidError;
+
+ PackageSignatures signatures = new PackageSignatures();
+
+ boolean permissionsFixed;
+ boolean haveGids;
+
+ // Whether this package is currently stopped, thus can not be
+ // started until explicitly launched by the user.
+ public boolean stopped;
+
+ // Set to true if we have never launched this app.
+ public boolean notLaunched;
+
+ /* Explicitly disabled components */
+ HashSet<String> disabledComponents = new HashSet<String>(0);
+ /* Explicitly enabled components */
+ HashSet<String> enabledComponents = new HashSet<String>(0);
+ int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ int installStatus = PKG_INSTALL_COMPLETE;
+
+ PackageSettingBase origPackage;
+
+ /* package name of the app that installed this package */
+ String installerPackageName;
+ PackageSettingBase(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
+ super(pkgFlags);
+ this.name = name;
+ this.realName = realName;
+ init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
+ }
+
+ /**
+ * New instance of PackageSetting with one-level-deep cloning.
+ */
+ @SuppressWarnings("unchecked")
+ PackageSettingBase(PackageSettingBase base) {
+ super(base);
+
+ name = base.name;
+ realName = base.realName;
+ codePath = base.codePath;
+ codePathString = base.codePathString;
+ resourcePath = base.resourcePath;
+ resourcePathString = base.resourcePathString;
+ nativeLibraryPathString = base.nativeLibraryPathString;
+ timeStamp = base.timeStamp;
+ firstInstallTime = base.firstInstallTime;
+ lastUpdateTime = base.lastUpdateTime;
+ versionCode = base.versionCode;
+
+ uidError = base.uidError;
+
+ signatures = new PackageSignatures(base.signatures);
+
+ permissionsFixed = base.permissionsFixed;
+ haveGids = base.haveGids;
+ stopped = base.stopped;
+ notLaunched = base.notLaunched;
+
+ disabledComponents = (HashSet<String>) base.disabledComponents.clone();
+
+ enabledComponents = (HashSet<String>) base.enabledComponents.clone();
+
+ enabled = base.enabled;
+ installStatus = base.installStatus;
+
+ origPackage = base.origPackage;
+
+ installerPackageName = base.installerPackageName;
+ }
+
+ void init(File codePath, File resourcePath, String nativeLibraryPathString,
+ int pVersionCode) {
+ this.codePath = codePath;
+ this.codePathString = codePath.toString();
+ this.resourcePath = resourcePath;
+ this.resourcePathString = resourcePath.toString();
+ this.nativeLibraryPathString = nativeLibraryPathString;
+ this.versionCode = pVersionCode;
+ }
+
+ public void setInstallerPackageName(String packageName) {
+ installerPackageName = packageName;
+ }
+
+ String getInstallerPackageName() {
+ return installerPackageName;
+ }
+
+ public void setInstallStatus(int newStatus) {
+ installStatus = newStatus;
+ }
+
+ public int getInstallStatus() {
+ return installStatus;
+ }
+
+ public void setTimeStamp(long newStamp) {
+ timeStamp = newStamp;
+ }
+
+ /**
+ * Make a shallow copy of this package settings.
+ */
+ public void copyFrom(PackageSettingBase base) {
+ grantedPermissions = base.grantedPermissions;
+ gids = base.gids;
+
+ timeStamp = base.timeStamp;
+ firstInstallTime = base.firstInstallTime;
+ lastUpdateTime = base.lastUpdateTime;
+ signatures = base.signatures;
+ permissionsFixed = base.permissionsFixed;
+ haveGids = base.haveGids;
+ stopped = base.stopped;
+ notLaunched = base.notLaunched;
+ disabledComponents = base.disabledComponents;
+ enabledComponents = base.enabledComponents;
+ enabled = base.enabled;
+ installStatus = base.installStatus;
+ }
+
+ boolean enableComponentLPw(String componentClassName) {
+ boolean changed = disabledComponents.remove(componentClassName);
+ changed |= enabledComponents.add(componentClassName);
+ return changed;
+ }
+
+ boolean disableComponentLPw(String componentClassName) {
+ boolean changed = enabledComponents.remove(componentClassName);
+ changed |= disabledComponents.add(componentClassName);
+ return changed;
+ }
+
+ boolean restoreComponentLPw(String componentClassName) {
+ boolean changed = enabledComponents.remove(componentClassName);
+ changed |= disabledComponents.remove(componentClassName);
+ return changed;
+ }
+
+ int getCurrentEnabledStateLPr(String componentName) {
+ if (enabledComponents.contains(componentName)) {
+ return COMPONENT_ENABLED_STATE_ENABLED;
+ } else if (disabledComponents.contains(componentName)) {
+ return COMPONENT_ENABLED_STATE_DISABLED;
+ } else {
+ return COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageSignatures.java b/services/java/com/android/server/pm/PackageSignatures.java
new file mode 100644
index 0000000..a25ec6c
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageSignatures.java
@@ -0,0 +1,198 @@
+/*
+ * 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.server.pm;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.pm.Signature;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+class PackageSignatures {
+ Signature[] mSignatures;
+
+ PackageSignatures(PackageSignatures orig) {
+ if (orig != null && orig.mSignatures != null) {
+ mSignatures = orig.mSignatures.clone();
+ }
+ }
+
+ PackageSignatures(Signature[] sigs) {
+ assignSignatures(sigs);
+ }
+
+ PackageSignatures() {
+ }
+
+ void writeXml(XmlSerializer serializer, String tagName,
+ ArrayList<Signature> pastSignatures) throws IOException {
+ if (mSignatures == null) {
+ return;
+ }
+ serializer.startTag(null, tagName);
+ serializer.attribute(null, "count",
+ Integer.toString(mSignatures.length));
+ for (int i=0; i<mSignatures.length; i++) {
+ serializer.startTag(null, "cert");
+ final Signature sig = mSignatures[i];
+ final int sigHash = sig.hashCode();
+ final int numPast = pastSignatures.size();
+ int j;
+ for (j=0; j<numPast; j++) {
+ Signature pastSig = pastSignatures.get(j);
+ if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
+ serializer.attribute(null, "index", Integer.toString(j));
+ break;
+ }
+ }
+ if (j >= numPast) {
+ pastSignatures.add(sig);
+ serializer.attribute(null, "index", Integer.toString(numPast));
+ serializer.attribute(null, "key", sig.toCharsString());
+ }
+ serializer.endTag(null, "cert");
+ }
+ serializer.endTag(null, tagName);
+ }
+
+ void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
+ throws IOException, XmlPullParserException {
+ String countStr = parser.getAttributeValue(null, "count");
+ if (countStr == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <signatures> has"
+ + " no count at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ final int count = Integer.parseInt(countStr);
+ mSignatures = new Signature[count];
+ int pos = 0;
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("cert")) {
+ if (pos < count) {
+ String index = parser.getAttributeValue(null, "index");
+ if (index != null) {
+ try {
+ int idx = Integer.parseInt(index);
+ String key = parser.getAttributeValue(null, "key");
+ if (key == null) {
+ if (idx >= 0 && idx < pastSignatures.size()) {
+ Signature sig = pastSignatures.get(idx);
+ if (sig != null) {
+ mSignatures[pos] = pastSignatures.get(idx);
+ pos++;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> "
+ + "index " + index + " is not defined at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> "
+ + "index " + index + " is out of bounds at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ while (pastSignatures.size() <= idx) {
+ pastSignatures.add(null);
+ }
+ Signature sig = new Signature(key);
+ pastSignatures.set(idx, sig);
+ mSignatures[pos] = sig;
+ pos++;
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> "
+ + "index " + index + " is not a number at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> has"
+ + " no index at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: too "
+ + "many <cert> tags, expected " + count
+ + " at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <cert>: "
+ + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ if (pos < count) {
+ // Should never happen -- there is an error in the written
+ // settings -- but if it does we don't want to generate
+ // a bad array.
+ Signature[] newSigs = new Signature[pos];
+ System.arraycopy(mSignatures, 0, newSigs, 0, pos);
+ mSignatures = newSigs;
+ }
+ }
+
+ void assignSignatures(Signature[] sigs) {
+ if (sigs == null) {
+ mSignatures = null;
+ return;
+ }
+ mSignatures = new Signature[sigs.length];
+ for (int i=0; i<sigs.length; i++) {
+ mSignatures[i] = sigs[i];
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer(128);
+ buf.append("PackageSignatures{");
+ buf.append(Integer.toHexString(System.identityHashCode(this)));
+ buf.append(" [");
+ if (mSignatures != null) {
+ for (int i=0; i<mSignatures.length; i++) {
+ if (i > 0) buf.append(", ");
+ buf.append(Integer.toHexString(
+ System.identityHashCode(mSignatures[i])));
+ }
+ }
+ buf.append("]}");
+ return buf.toString();
+ }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/PendingPackage.java b/services/java/com/android/server/pm/PendingPackage.java
new file mode 100644
index 0000000..c17cc46
--- /dev/null
+++ b/services/java/com/android/server/pm/PendingPackage.java
@@ -0,0 +1,30 @@
+/*
+ * 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.server.pm;
+
+import java.io.File;
+
+final class PendingPackage extends PackageSettingBase {
+ final int sharedId;
+
+ PendingPackage(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
+ pkgFlags);
+ this.sharedId = sharedId;
+ }
+}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
new file mode 100644
index 0000000..b100eb1
--- /dev/null
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -0,0 +1,73 @@
+/*
+ * 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.server.pm;
+
+import com.android.internal.util.XmlUtils;
+import com.android.server.PreferredComponent;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.io.IOException;
+
+class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks {
+ private static final String TAG = "PreferredActivity";
+
+ private static final boolean DEBUG_FILTERS = false;
+
+ final PreferredComponent mPref;
+
+ PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
+ super(filter);
+ mPref = new PreferredComponent(this, match, set, activity);
+ }
+
+ PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
+ mPref = new PreferredComponent(this, parser);
+ }
+
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ mPref.writeToXml(serializer);
+ serializer.startTag(null, "filter");
+ super.writeToXml(serializer);
+ serializer.endTag(null, "filter");
+ }
+
+ public boolean onReadTag(String tagName, XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ if (tagName.equals("filter")) {
+ if (DEBUG_FILTERS) {
+ Log.i(TAG, "Starting to parse filter...");
+ }
+ readFromXml(parser);
+ if (DEBUG_FILTERS) {
+ Log.i(TAG, "Finished filter: depth=" + parser.getDepth() + " tag="
+ + parser.getName());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ return true;
+ }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
new file mode 100644
index 0000000..11dde75
--- /dev/null
+++ b/services/java/com/android/server/pm/Settings.java
@@ -0,0 +1,2224 @@
+/*
+ * 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.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
+import com.android.internal.util.XmlUtils;
+import com.android.server.IntentResolver;
+import com.android.server.pm.PackageManagerService.DumpState;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+import android.content.pm.Signature;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Process;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Holds information about dynamic settings.
+ */
+final class Settings {
+ private static final String TAG = "PackageSettings";
+
+ private static final boolean DEBUG_STOPPED = false;
+
+ private final File mSettingsFilename;
+ private final File mBackupSettingsFilename;
+ private final File mPackageListFilename;
+ private final File mStoppedPackagesFilename;
+ private final File mBackupStoppedPackagesFilename;
+ final HashMap<String, PackageSetting> mPackages =
+ new HashMap<String, PackageSetting>();
+ // List of replaced system applications
+ final HashMap<String, PackageSetting> mDisabledSysPackages =
+ new HashMap<String, PackageSetting>();
+
+ // These are the last platform API version we were using for
+ // the apps installed on internal and external storage. It is
+ // used to grant newer permissions one time during a system upgrade.
+ int mInternalSdkPlatform;
+ int mExternalSdkPlatform;
+
+ // The user's preferred activities associated with particular intent
+ // filters.
+ final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
+ new IntentResolver<PreferredActivity, PreferredActivity>() {
+ @Override
+ protected String packageForFilter(PreferredActivity filter) {
+ return filter.mPref.mComponent.getPackageName();
+ }
+ @Override
+ protected void dumpFilter(PrintWriter out, String prefix,
+ PreferredActivity filter) {
+ filter.mPref.dump(out, prefix, filter);
+ }
+ };
+ final HashMap<String, SharedUserSetting> mSharedUsers =
+ new HashMap<String, SharedUserSetting>();
+ private final ArrayList<Object> mUserIds = new ArrayList<Object>();
+ private final SparseArray<Object> mOtherUserIds =
+ new SparseArray<Object>();
+
+ // For reading/writing settings file.
+ private final ArrayList<Signature> mPastSignatures =
+ new ArrayList<Signature>();
+
+ // Mapping from permission names to info about them.
+ final HashMap<String, BasePermission> mPermissions =
+ new HashMap<String, BasePermission>();
+
+ // Mapping from permission tree names to info about them.
+ final HashMap<String, BasePermission> mPermissionTrees =
+ new HashMap<String, BasePermission>();
+
+ // Packages that have been uninstalled and still need their external
+ // storage data deleted.
+ final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
+
+ // Packages that have been renamed since they were first installed.
+ // Keys are the new names of the packages, values are the original
+ // names. The packages appear everwhere else under their original
+ // names.
+ final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
+
+ final StringBuilder mReadMessages = new StringBuilder();
+
+ /**
+ * Used to track packages that have a shared user ID that hasn't been read
+ * in yet.
+ * <p>
+ * TODO: make this just a local variable that is passed in during package
+ * scanning to make it less confusing.
+ */
+ private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>();
+
+ Settings() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
+ File systemSecureDir = new File(dataDir, "secure/system");
+ systemDir.mkdirs();
+ systemSecureDir.mkdirs();
+ FileUtils.setPermissions(systemDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ FileUtils.setPermissions(systemSecureDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ mSettingsFilename = new File(systemDir, "packages.xml");
+ mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
+ mPackageListFilename = new File(systemDir, "packages.list");
+ mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml");
+ mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml");
+ }
+
+ PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
+ String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
+ String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
+ final String name = pkg.packageName;
+ PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
+ resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
+ return p;
+ }
+
+ PackageSetting peekPackageLPr(String name) {
+ return mPackages.get(name);
+ }
+
+ void setInstallStatus(String pkgName, int status) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ if(p.getInstallStatus() != status) {
+ p.setInstallStatus(status);
+ }
+ }
+ }
+
+ void setInstallerPackageName(String pkgName,
+ String installerPkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ p.setInstallerPackageName(installerPkgName);
+ }
+ }
+
+ SharedUserSetting getSharedUserLPw(String name,
+ int pkgFlags, boolean create) {
+ SharedUserSetting s = mSharedUsers.get(name);
+ if (s == null) {
+ if (!create) {
+ return null;
+ }
+ s = new SharedUserSetting(name, pkgFlags);
+ if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+ s.userId = newUserIdLPw(s);
+ } else {
+ s.userId = PackageManagerService.FIRST_APPLICATION_UID;
+ }
+ 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
+ if (s.userId >= 0) {
+ mSharedUsers.put(name, s);
+ }
+ }
+
+ return s;
+ }
+
+ boolean disableSystemPackageLPw(String name) {
+ final PackageSetting p = mPackages.get(name);
+ if(p == null) {
+ Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package");
+ return false;
+ }
+ final PackageSetting dp = mDisabledSysPackages.get(name);
+ // always make sure the system package code and resource paths dont change
+ if (dp == null) {
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ mDisabledSysPackages.put(name, p);
+
+ // a little trick... when we install the new package, we don't
+ // want to modify the existing PackageSetting for the built-in
+ // version. so at this point we need a new PackageSetting that
+ // is okay to muck with.
+ PackageSetting newp = new PackageSetting(p);
+ replacePackageLPw(name, newp);
+ return true;
+ }
+ return false;
+ }
+
+ PackageSetting enableSystemPackageLPw(String name) {
+ PackageSetting p = mDisabledSysPackages.get(name);
+ if(p == null) {
+ Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled");
+ return null;
+ }
+ // Reset flag in ApplicationInfo object
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
+ p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags);
+ mDisabledSysPackages.remove(name);
+ return ret;
+ }
+
+ PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
+ PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (p.userId == uid) {
+ return p;
+ }
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate package, keeping first: " + name);
+ return null;
+ }
+ p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
+ vc, pkgFlags);
+ p.userId = uid;
+ if (addUserIdLPw(uid, p, name)) {
+ mPackages.put(name, p);
+ return p;
+ }
+ return null;
+ }
+
+ SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
+ SharedUserSetting s = mSharedUsers.get(name);
+ if (s != null) {
+ if (s.userId == uid) {
+ return s;
+ }
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate shared user, keeping first: " + name);
+ return null;
+ }
+ s = new SharedUserSetting(name, pkgFlags);
+ s.userId = uid;
+ if (addUserIdLPw(uid, s, name)) {
+ mSharedUsers.put(name, s);
+ return s;
+ }
+ return null;
+ }
+
+ // Transfer ownership of permissions from one package to another.
+ void transferPermissionsLPw(String origPkg, String newPkg) {
+ // Transfer ownership of permissions to the new package.
+ for (int i=0; i<2; i++) {
+ HashMap<String, BasePermission> permissions =
+ i == 0 ? mPermissionTrees : mPermissions;
+ for (BasePermission bp : permissions.values()) {
+ if (origPkg.equals(bp.sourcePackage)) {
+ if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG,
+ "Moving permission " + bp.name
+ + " from pkg " + bp.sourcePackage
+ + " to " + newPkg);
+ bp.sourcePackage = newPkg;
+ bp.packageSetting = null;
+ bp.perm = null;
+ if (bp.pendingInfo != null) {
+ bp.pendingInfo.packageName = newPkg;
+ }
+ bp.uid = 0;
+ bp.gids = null;
+ }
+ }
+ }
+ }
+
+ private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
+ String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
+ String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
+ PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (!p.codePath.equals(codePath)) {
+ // Check to see if its a disabled system app
+ if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ // This is an updated system app with versions in both system
+ // and data partition. Just let the most recent version
+ // take precedence.
+ Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " +
+ p.codePathString + " to " + codePath.toString());
+ } else {
+ // Just a change in the code path is not an issue, but
+ // let's log a message about it.
+ Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + p.codePath
+ + " to " + codePath + "; Retaining data and using new");
+ /*
+ * Since we've changed paths, we need to prefer the new
+ * native library path over the one stored in the
+ * package settings since we might have moved from
+ * internal to external storage or vice versa.
+ */
+ p.nativeLibraryPathString = nativeLibraryPathString;
+ }
+ }
+ if (p.sharedUser != sharedUser) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + name + " shared user changed from "
+ + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
+ + " to "
+ + (sharedUser != null ? sharedUser.name : "<nothing>")
+ + "; replacing with new");
+ p = null;
+ } else {
+ if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ // If what we are scanning is a system package, then
+ // make it so, regardless of whether it was previously
+ // installed only in the data partition.
+ p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ }
+ }
+ if (p == null) {
+ // Create a new PackageSettings entry. this can end up here because
+ // of code path mismatch or user id mismatch of an updated system partition
+ if (!create) {
+ return null;
+ }
+ if (origPackage != null) {
+ // We are consuming the data from an existing package.
+ p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
+ nativeLibraryPathString, vc, pkgFlags);
+ if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name
+ + " is adopting original package " + origPackage.name);
+ // Note that we will retain the new package's signature so
+ // that we can keep its data.
+ PackageSignatures s = p.signatures;
+ p.copyFrom(origPackage);
+ p.signatures = s;
+ p.sharedUser = origPackage.sharedUser;
+ p.userId = origPackage.userId;
+ p.origPackage = origPackage;
+ mRenamedPackages.put(name, origPackage.name);
+ name = origPackage.name;
+ // Update new package state.
+ p.setTimeStamp(codePath.lastModified());
+ } else {
+ p = new PackageSetting(name, realName, codePath, resourcePath,
+ nativeLibraryPathString, vc, pkgFlags);
+ p.setTimeStamp(codePath.lastModified());
+ p.sharedUser = sharedUser;
+ // If this is not a system app, it starts out stopped.
+ if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (DEBUG_STOPPED) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(PackageManagerService.TAG, "Stopping package " + name, e);
+ }
+ p.stopped = true;
+ p.notLaunched = true;
+ }
+ if (sharedUser != null) {
+ p.userId = sharedUser.userId;
+ } else if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+ // Clone the setting here for disabled system packages
+ PackageSetting dis = mDisabledSysPackages.get(name);
+ if (dis != null) {
+ // For disabled packages a new setting is created
+ // from the existing user id. This still has to be
+ // added to list of user id's
+ // Copy signatures from previous setting
+ if (dis.signatures.mSignatures != null) {
+ p.signatures.mSignatures = dis.signatures.mSignatures.clone();
+ }
+ p.userId = dis.userId;
+ // Clone permissions
+ p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
+ // Clone component info
+ p.disabledComponents = new HashSet<String>(dis.disabledComponents);
+ p.enabledComponents = new HashSet<String>(dis.enabledComponents);
+ // Add new setting to list of user ids
+ addUserIdLPw(p.userId, p, name);
+ } else {
+ // Assign new user id
+ p.userId = newUserIdLPw(p);
+ }
+ } else {
+ p.userId = PackageManagerService.FIRST_APPLICATION_UID;
+ }
+ }
+ if (p.userId < 0) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + name + " could not be assigned a valid uid");
+ return null;
+ }
+ if (add) {
+ // Finish adding new package by adding it and updating shared
+ // user preferences
+ addPackageSettingLPw(p, name, sharedUser);
+ }
+ }
+ return p;
+ }
+
+ void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
+ p.pkg = pkg;
+ pkg.mSetEnabled = p.enabled;
+ pkg.mSetStopped = p.stopped;
+ final String codePath = pkg.applicationInfo.sourceDir;
+ final String resourcePath = pkg.applicationInfo.publicSourceDir;
+ // Update code path if needed
+ if (!codePath.equalsIgnoreCase(p.codePathString)) {
+ Slog.w(PackageManagerService.TAG, "Code path for pkg : " + p.pkg.packageName +
+ " changing from " + p.codePathString + " to " + codePath);
+ p.codePath = new File(codePath);
+ p.codePathString = codePath;
+ }
+ //Update resource path if needed
+ if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
+ Slog.w(PackageManagerService.TAG, "Resource path for pkg : " + p.pkg.packageName +
+ " changing from " + p.resourcePathString + " to " + resourcePath);
+ p.resourcePath = new File(resourcePath);
+ p.resourcePathString = resourcePath;
+ }
+ // Update the native library path if needed
+ final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
+ if (nativeLibraryPath != null
+ && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
+ p.nativeLibraryPathString = nativeLibraryPath;
+ }
+ // Update version code if needed
+ if (pkg.mVersionCode != p.versionCode) {
+ p.versionCode = pkg.mVersionCode;
+ }
+ // Update signatures if needed.
+ if (p.signatures.mSignatures == null) {
+ p.signatures.assignSignatures(pkg.mSignatures);
+ }
+ // If this app defines a shared user id initialize
+ // the shared user signatures as well.
+ if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
+ p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
+ }
+ addPackageSettingLPw(p, pkg.packageName, p.sharedUser);
+ }
+
+ // Utility method that adds a PackageSetting to mPackages and
+ // completes updating the shared user attributes
+ private void addPackageSettingLPw(PackageSetting p, String name,
+ SharedUserSetting sharedUser) {
+ mPackages.put(name, p);
+ if (sharedUser != null) {
+ if (p.sharedUser != null && p.sharedUser != sharedUser) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Package " + p.name + " was user "
+ + p.sharedUser + " but is now " + sharedUser
+ + "; I am not changing its files so it will probably fail!");
+ p.sharedUser.packages.remove(p);
+ } else if (p.userId != sharedUser.userId) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Package " + p.name + " was user id " + p.userId
+ + " but is now user " + sharedUser
+ + " with id " + sharedUser.userId
+ + "; I am not changing its files so it will probably fail!");
+ }
+
+ sharedUser.packages.add(p);
+ p.sharedUser = sharedUser;
+ p.userId = sharedUser.userId;
+ }
+ }
+
+ /*
+ * Update the shared user setting when a package using
+ * specifying the shared user id is removed. The gids
+ * associated with each permission of the deleted package
+ * are removed from the shared user's gid list only if its
+ * not in use by other permissions of packages in the
+ * shared user setting.
+ */
+ void updateSharedUserPermsLPw(PackageSetting deletedPs, int[] globalGids) {
+ if ((deletedPs == null) || (deletedPs.pkg == null)) {
+ Slog.i(PackageManagerService.TAG,
+ "Trying to update info for null package. Just ignoring");
+ return;
+ }
+ // No sharedUserId
+ if (deletedPs.sharedUser == null) {
+ return;
+ }
+ SharedUserSetting sus = deletedPs.sharedUser;
+ // Update permissions
+ for (String eachPerm : deletedPs.pkg.requestedPermissions) {
+ boolean used = false;
+ if (!sus.grantedPermissions.contains(eachPerm)) {
+ continue;
+ }
+ for (PackageSetting pkg:sus.packages) {
+ if (pkg.pkg != null &&
+ !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
+ pkg.pkg.requestedPermissions.contains(eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ if (!used) {
+ // can safely delete this permission from list
+ sus.grantedPermissions.remove(eachPerm);
+ }
+ }
+ // Update gids
+ int newGids[] = globalGids;
+ for (String eachPerm : sus.grantedPermissions) {
+ BasePermission bp = mPermissions.get(eachPerm);
+ if (bp != null) {
+ newGids = PackageManagerService.appendInts(newGids, bp.gids);
+ }
+ }
+ sus.gids = newGids;
+ }
+
+ int removePackageLPw(String name) {
+ final PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ mPackages.remove(name);
+ if (p.sharedUser != null) {
+ p.sharedUser.packages.remove(p);
+ if (p.sharedUser.packages.size() == 0) {
+ mSharedUsers.remove(p.sharedUser.name);
+ removeUserIdLPw(p.sharedUser.userId);
+ return p.sharedUser.userId;
+ }
+ } else {
+ removeUserIdLPw(p.userId);
+ return p.userId;
+ }
+ }
+ return -1;
+ }
+
+ private void replacePackageLPw(String name, PackageSetting newp) {
+ final PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (p.sharedUser != null) {
+ p.sharedUser.packages.remove(p);
+ p.sharedUser.packages.add(newp);
+ } else {
+ replaceUserIdLPw(p.userId, newp);
+ }
+ }
+ mPackages.put(name, newp);
+ }
+
+ private boolean addUserIdLPw(int uid, Object obj, Object name) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS) {
+ return false;
+ }
+
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ while (index >= N) {
+ mUserIds.add(null);
+ N++;
+ }
+ if (mUserIds.get(index) != null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate user id: " + uid
+ + " name=" + name);
+ return false;
+ }
+ mUserIds.set(index, obj);
+ } else {
+ if (mOtherUserIds.get(uid) != null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate shared id: " + uid
+ + " name=" + name);
+ return false;
+ }
+ mOtherUserIds.put(uid, obj);
+ }
+ return true;
+ }
+
+ public Object getUserIdLPr(int uid) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ return index < N ? mUserIds.get(index) : null;
+ } else {
+ return mOtherUserIds.get(uid);
+ }
+ }
+
+ private void removeUserIdLPw(int uid) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ if (index < N) mUserIds.set(index, null);
+ } else {
+ mOtherUserIds.remove(uid);
+ }
+ }
+
+ private void replaceUserIdLPw(int uid, Object obj) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ if (index < N) mUserIds.set(index, obj);
+ } else {
+ mOtherUserIds.put(uid, obj);
+ }
+ }
+
+ void writeStoppedLPr() {
+ // Keep the old stopped packages around until we know the new ones have
+ // been successfully written.
+ if (mStoppedPackagesFilename.exists()) {
+ // Presence of backup settings file indicates that we failed
+ // to persist packages earlier. So preserve the older
+ // backup for future reference since the current packages
+ // might have been corrupted.
+ if (!mBackupStoppedPackagesFilename.exists()) {
+ if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) {
+ Log.wtf(PackageManagerService.TAG, "Unable to backup package manager stopped packages, "
+ + "current changes will be lost at reboot");
+ return;
+ }
+ } else {
+ mStoppedPackagesFilename.delete();
+ Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
+ }
+ }
+
+ try {
+ final FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename);
+ final BufferedOutputStream str = new BufferedOutputStream(fstr);
+
+ //XmlSerializer serializer = XmlUtils.serializerInstance();
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, "stopped-packages");
+
+ for (final PackageSetting pkg : mPackages.values()) {
+ if (pkg.stopped) {
+ serializer.startTag(null, "pkg");
+ serializer.attribute(null, "name", pkg.name);
+ if (pkg.notLaunched) {
+ serializer.attribute(null, "nl", "1");
+ }
+ serializer.endTag(null, "pkg");
+ }
+ }
+
+ serializer.endTag(null, "stopped-packages");
+
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+
+ // New settings successfully written, old ones are no longer
+ // needed.
+ mBackupStoppedPackagesFilename.delete();
+ FileUtils.setPermissions(mStoppedPackagesFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
+ // Done, all is good!
+ return;
+ } catch(java.io.IOException e) {
+ Log.wtf(PackageManagerService.TAG, "Unable to write package manager stopped packages, "
+ + " current changes will be lost at reboot", e);
+ }
+
+ // Clean up partially written files
+ if (mStoppedPackagesFilename.exists()) {
+ if (!mStoppedPackagesFilename.delete()) {
+ Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename);
+ }
+ }
+ }
+
+ // Note: assumed "stopped" field is already cleared in all packages.
+ void readStoppedLPw() {
+ FileInputStream str = null;
+ if (mBackupStoppedPackagesFilename.exists()) {
+ try {
+ str = new FileInputStream(mBackupStoppedPackagesFilename);
+ mReadMessages.append("Reading from backup stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file");
+ if (mSettingsFilename.exists()) {
+ // If both the backup and normal file exist, we
+ // ignore the normal one since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file "
+ + mStoppedPackagesFilename);
+ mStoppedPackagesFilename.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ try {
+ if (str == null) {
+ if (!mStoppedPackagesFilename.exists()) {
+ mReadMessages.append("No stopped packages file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO, "No stopped packages file file; "
+ + "assuming all started");
+ // At first boot, make sure no packages are stopped.
+ // We usually want to have third party apps initialize
+ // in the stopped state, but not at first boot.
+ for (PackageSetting pkg : mPackages.values()) {
+ pkg.stopped = false;
+ pkg.notLaunched = false;
+ }
+ return;
+ }
+ str = new FileInputStream(mStoppedPackagesFilename);
+ }
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager stopped packages");
+ return;
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("pkg")) {
+ String name = parser.getAttributeValue(null, "name");
+ PackageSetting ps = mPackages.get(name);
+ if (ps != null) {
+ ps.stopped = true;
+ if ("1".equals(parser.getAttributeValue(null, "nl"))) {
+ ps.notLaunched = true;
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + name);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ } catch(XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
+
+ } catch(java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
+
+ }
+ }
+
+ void writeLPr() {
+ //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
+
+ // Keep the old settings around until we know the new ones have
+ // been successfully written.
+ if (mSettingsFilename.exists()) {
+ // Presence of backup settings file indicates that we failed
+ // to persist settings earlier. So preserve the older
+ // backup for future reference since the current settings
+ // might have been corrupted.
+ if (!mBackupSettingsFilename.exists()) {
+ if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
+ Log.wtf(PackageManagerService.TAG, "Unable to backup package manager settings, "
+ + " current changes will be lost at reboot");
+ return;
+ }
+ } else {
+ mSettingsFilename.delete();
+ Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
+ }
+ }
+
+ mPastSignatures.clear();
+
+ try {
+ FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
+ BufferedOutputStream str = new BufferedOutputStream(fstr);
+
+ //XmlSerializer serializer = XmlUtils.serializerInstance();
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, "packages");
+
+ serializer.startTag(null, "last-platform-version");
+ serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
+ serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
+ serializer.endTag(null, "last-platform-version");
+
+ serializer.startTag(null, "permission-trees");
+ for (BasePermission bp : mPermissionTrees.values()) {
+ writePermissionLPr(serializer, bp);
+ }
+ serializer.endTag(null, "permission-trees");
+
+ serializer.startTag(null, "permissions");
+ for (BasePermission bp : mPermissions.values()) {
+ writePermissionLPr(serializer, bp);
+ }
+ serializer.endTag(null, "permissions");
+
+ for (final PackageSetting pkg : mPackages.values()) {
+ writePackageLPr(serializer, pkg);
+ }
+
+ for (final PackageSetting pkg : mDisabledSysPackages.values()) {
+ writeDisabledSysPackageLPr(serializer, pkg);
+ }
+
+ serializer.startTag(null, "preferred-activities");
+ for (final PreferredActivity pa : mPreferredActivities.filterSet()) {
+ serializer.startTag(null, "item");
+ pa.writeToXml(serializer);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "preferred-activities");
+
+ for (final SharedUserSetting usr : mSharedUsers.values()) {
+ serializer.startTag(null, "shared-user");
+ serializer.attribute(null, "name", usr.name);
+ serializer.attribute(null, "userId",
+ Integer.toString(usr.userId));
+ usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ serializer.startTag(null, "perms");
+ for (String name : usr.grantedPermissions) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "perms");
+ serializer.endTag(null, "shared-user");
+ }
+
+ if (mPackagesToBeCleaned.size() > 0) {
+ for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
+ serializer.startTag(null, "cleaning-package");
+ serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
+ serializer.endTag(null, "cleaning-package");
+ }
+ }
+
+ if (mRenamedPackages.size() > 0) {
+ for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ serializer.startTag(null, "renamed-package");
+ serializer.attribute(null, "new", e.getKey());
+ serializer.attribute(null, "old", e.getValue());
+ serializer.endTag(null, "renamed-package");
+ }
+ }
+
+ serializer.endTag(null, "packages");
+
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+
+ // New settings successfully written, old ones are no longer
+ // needed.
+ mBackupSettingsFilename.delete();
+ FileUtils.setPermissions(mSettingsFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
+ // Write package list file now, use a JournaledFile.
+ //
+ File tempFile = new File(mPackageListFilename.toString() + ".tmp");
+ JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
+
+ fstr = new FileOutputStream(journal.chooseForWrite());
+ str = new BufferedOutputStream(fstr);
+ try {
+ StringBuilder sb = new StringBuilder();
+ for (final PackageSetting pkg : mPackages.values()) {
+ ApplicationInfo ai = pkg.pkg.applicationInfo;
+ String dataPath = ai.dataDir;
+ boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+ // Avoid any application that has a space in its path
+ // or that is handled by the system.
+ if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
+ continue;
+
+ // we store on each line the following information for now:
+ //
+ // pkgName - package name
+ // userId - application-specific user id
+ // debugFlag - 0 or 1 if the package is debuggable.
+ // dataPath - path to package's data path
+ //
+ // NOTE: We prefer not to expose all ApplicationInfo flags for now.
+ //
+ // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
+ // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
+ // system/core/run-as/run-as.c
+ //
+ sb.setLength(0);
+ sb.append(ai.packageName);
+ sb.append(" ");
+ sb.append((int)ai.uid);
+ sb.append(isDebug ? " 1 " : " 0 ");
+ sb.append(dataPath);
+ sb.append("\n");
+ str.write(sb.toString().getBytes());
+ }
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+ journal.commit();
+ }
+ catch (Exception e) {
+ journal.rollback();
+ }
+
+ FileUtils.setPermissions(mPackageListFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
+ writeStoppedLPr();
+
+ return;
+
+ } catch(XmlPullParserException e) {
+ Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ + "current changes will be lost at reboot", e);
+ } catch(java.io.IOException e) {
+ Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ + "current changes will be lost at reboot", e);
+ }
+ // Clean up partially written files
+ if (mSettingsFilename.exists()) {
+ if (!mSettingsFilename.delete()) {
+ Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " + mSettingsFilename);
+ }
+ }
+ //Debug.stopMethodTracing();
+ }
+
+ void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "updated-package");
+ serializer.attribute(null, "name", pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ if (pkg.nativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ }
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId", Integer.toString(pkg.userId));
+ } else {
+ serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId));
+ }
+ serializer.startTag(null, "perms");
+ if (pkg.sharedUser == null) {
+ // If this is a shared user, the permissions will
+ // be written there. We still need to write an
+ // empty permissions list so permissionsFixed will
+ // be set.
+ for (final String name : pkg.grantedPermissions) {
+ BasePermission bp = mPermissions.get(name);
+ if (bp != null) {
+ // We only need to write signature or system permissions but
+ // this wont
+ // match the semantics of grantedPermissions. So write all
+ // permissions.
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ }
+ }
+ serializer.endTag(null, "perms");
+ serializer.endTag(null, "updated-package");
+ }
+
+ void writePackageLPr(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "package");
+ serializer.attribute(null, "name", pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ if (pkg.nativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ }
+ serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId", Integer.toString(pkg.userId));
+ } else {
+ serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId));
+ }
+ if (pkg.uidError) {
+ serializer.attribute(null, "uidError", "true");
+ }
+ if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attribute(null, "enabled",
+ pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED ? "true" : "false");
+ }
+ if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
+ serializer.attribute(null, "installStatus", "false");
+ }
+ if (pkg.installerPackageName != null) {
+ serializer.attribute(null, "installer", pkg.installerPackageName);
+ }
+ pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ serializer.startTag(null, "perms");
+ if (pkg.sharedUser == null) {
+ // If this is a shared user, the permissions will
+ // be written there. We still need to write an
+ // empty permissions list so permissionsFixed will
+ // be set.
+ for (final String name : pkg.grantedPermissions) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ }
+ serializer.endTag(null, "perms");
+ }
+ if (pkg.disabledComponents.size() > 0) {
+ serializer.startTag(null, "disabled-components");
+ for (final String name : pkg.disabledComponents) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "disabled-components");
+ }
+ if (pkg.enabledComponents.size() > 0) {
+ serializer.startTag(null, "enabled-components");
+ for (final String name : pkg.enabledComponents) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "enabled-components");
+ }
+
+ serializer.endTag(null, "package");
+ }
+
+ void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
+ throws XmlPullParserException, java.io.IOException {
+ if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", bp.name);
+ serializer.attribute(null, "package", bp.sourcePackage);
+ if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
+ serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
+ }
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type="
+ + bp.type);
+ if (bp.type == BasePermission.TYPE_DYNAMIC) {
+ final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo;
+ if (pi != null) {
+ serializer.attribute(null, "type", "dynamic");
+ if (pi.icon != 0) {
+ serializer.attribute(null, "icon", Integer.toString(pi.icon));
+ }
+ if (pi.nonLocalizedLabel != null) {
+ serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+ }
+ }
+ }
+ serializer.endTag(null, "item");
+ }
+ }
+
+ ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
+ final HashSet<String> kList = new HashSet<String>(mPackages.keySet());
+ final Iterator<String> its = kList.iterator();
+ final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
+ while (its.hasNext()) {
+ final String key = its.next();
+ final PackageSetting ps = mPackages.get(key);
+ if (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
+ ret.add(ps);
+ }
+ }
+ return ret;
+ }
+
+ boolean readLPw() {
+ FileInputStream str = null;
+ if (mBackupSettingsFilename.exists()) {
+ try {
+ str = new FileInputStream(mBackupSettingsFilename);
+ mReadMessages.append("Reading from backup settings file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "Need to read from backup settings file");
+ if (mSettingsFilename.exists()) {
+ // If both the backup and settings file exist, we
+ // ignore the settings since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
+ + mSettingsFilename);
+ mSettingsFilename.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ mPendingPackages.clear();
+ mPastSignatures.clear();
+
+ try {
+ if (str == null) {
+ if (!mSettingsFilename.exists()) {
+ mReadMessages.append("No settings file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "No settings file; creating initial state");
+ return false;
+ }
+ str = new FileInputStream(mSettingsFilename);
+ }
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in settings file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager settings");
+ Log
+ .wtf(PackageManagerService.TAG,
+ "No start tag found in package manager settings");
+ return false;
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("package")) {
+ readPackageLPw(parser);
+ } else if (tagName.equals("permissions")) {
+ readPermissionsLPw(mPermissions, parser);
+ } else if (tagName.equals("permission-trees")) {
+ readPermissionsLPw(mPermissionTrees, parser);
+ } else if (tagName.equals("shared-user")) {
+ readSharedUserLPw(parser);
+ } else if (tagName.equals("preferred-packages")) {
+ // no longer used.
+ } else if (tagName.equals("preferred-activities")) {
+ readPreferredActivitiesLPw(parser);
+ } else if (tagName.equals("updated-package")) {
+ readDisabledSysPackageLPw(parser);
+ } else if (tagName.equals("cleaning-package")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ mPackagesToBeCleaned.add(name);
+ }
+ } else if (tagName.equals("renamed-package")) {
+ String nname = parser.getAttributeValue(null, "new");
+ String oname = parser.getAttributeValue(null, "old");
+ if (nname != null && oname != null) {
+ mRenamedPackages.put(nname, oname);
+ }
+ } else if (tagName.equals("last-platform-version")) {
+ mInternalSdkPlatform = mExternalSdkPlatform = 0;
+ try {
+ String internal = parser.getAttributeValue(null, "internal");
+ if (internal != null) {
+ mInternalSdkPlatform = Integer.parseInt(internal);
+ }
+ String external = parser.getAttributeValue(null, "external");
+ if (external != null) {
+ mExternalSdkPlatform = Integer.parseInt(external);
+ }
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ } catch (XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+
+ } catch (java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+
+ }
+
+ final int N = mPendingPackages.size();
+ for (int i = 0; i < N; i++) {
+ final PendingPackage pp = mPendingPackages.get(i);
+ Object idObj = getUserIdLPr(pp.sharedId);
+ if (idObj != null && idObj instanceof SharedUserSetting) {
+ PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
+ (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
+ pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
+ if (p == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unable to create application package for " + pp.name);
+ continue;
+ }
+ p.copyFrom(pp);
+ } else if (idObj != null) {
+ String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ + pp.sharedId + " that is not a shared uid\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
+ } else {
+ String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ + pp.sharedId + " that is not defined\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
+ }
+ }
+ mPendingPackages.clear();
+
+ readStoppedLPw();
+
+ mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ + mSharedUsers.size() + " shared uids\n");
+
+ return true;
+ }
+
+ private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
+ String v = parser.getAttributeValue(ns, name);
+ try {
+ if (v == null) {
+ return defValue;
+ }
+ return Integer.parseInt(v);
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: attribute " + name
+ + " has bad integer value " + v + " at "
+ + parser.getPositionDescription());
+ }
+ return defValue;
+ }
+
+ private void readPermissionsLPw(HashMap<String, BasePermission> out, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ final String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ final String name = parser.getAttributeValue(null, "name");
+ final String sourcePackage = parser.getAttributeValue(null, "package");
+ final String ptype = parser.getAttributeValue(null, "type");
+ if (name != null && sourcePackage != null) {
+ final boolean dynamic = "dynamic".equals(ptype);
+ final BasePermission bp = new BasePermission(name, sourcePackage,
+ dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
+ bp.protectionLevel = readInt(parser, null, "protection",
+ PermissionInfo.PROTECTION_NORMAL);
+ if (dynamic) {
+ PermissionInfo pi = new PermissionInfo();
+ pi.packageName = sourcePackage.intern();
+ pi.name = name.intern();
+ pi.icon = readInt(parser, null, "icon", 0);
+ pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
+ pi.protectionLevel = bp.protectionLevel;
+ bp.pendingInfo = pi;
+ }
+ out.put(bp.name, bp);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: permissions has" + " no name at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element reading permissions: " + parser.getName() + " at "
+ + parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ String name = parser.getAttributeValue(null, "name");
+ String realName = parser.getAttributeValue(null, "realName");
+ String codePathStr = parser.getAttributeValue(null, "codePath");
+ String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+ if (resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+ String version = parser.getAttributeValue(null, "version");
+ int versionCode = 0;
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ int pkgFlags = 0;
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
+ new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
+ String timeStampStr = parser.getAttributeValue(null, "ft");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr, 16);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ ps.firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ ps.lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ String idStr = parser.getAttributeValue(null, "userId");
+ ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if (ps.userId <= 0) {
+ String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ }
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("perms")) {
+ readGrantedPermissionsLPw(parser, ps.grantedPermissions);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <updated-package>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ mDisabledSysPackages.put(name, ps);
+ }
+
+ private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String name = null;
+ String realName = null;
+ String idStr = null;
+ String sharedIdStr = null;
+ String codePathStr = null;
+ String resourcePathStr = null;
+ String nativeLibraryPathStr = null;
+ String systemStr = null;
+ String installerPackageName = null;
+ String uidError = null;
+ int pkgFlags = 0;
+ long timeStamp = 0;
+ long firstInstallTime = 0;
+ long lastUpdateTime = 0;
+ PackageSettingBase packageSetting = null;
+ String version = null;
+ int versionCode = 0;
+ try {
+ name = parser.getAttributeValue(null, "name");
+ realName = parser.getAttributeValue(null, "realName");
+ idStr = parser.getAttributeValue(null, "userId");
+ uidError = parser.getAttributeValue(null, "uidError");
+ sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ codePathStr = parser.getAttributeValue(null, "codePath");
+ resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+ version = parser.getAttributeValue(null, "version");
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
+ installerPackageName = parser.getAttributeValue(null, "installer");
+
+ systemStr = parser.getAttributeValue(null, "flags");
+ if (systemStr != null) {
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+ : 0;
+ } else {
+ // Old settings that don't specify system... just treat
+ // them as system, good enough.
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ }
+ String timeStampStr = parser.getAttributeValue(null, "ft");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.v(PackageManagerService.TAG, "Reading package: " + name + " userId=" + idStr
+ + " sharedUserId=" + sharedIdStr);
+ int userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if (resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+ if (realName != null) {
+ realName = realName.intern();
+ }
+ if (name == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <package> has no name at "
+ + parser.getPositionDescription());
+ } else if (codePathStr == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <package> has no codePath at "
+ + parser.getPositionDescription());
+ } else if (userId > 0) {
+ packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
+ new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode,
+ pkgFlags);
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ + userId + " pkg=" + packageSetting);
+ if (packageSetting == null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid "
+ + userId + " while parsing settings at "
+ + parser.getPositionDescription());
+ } else {
+ packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
+ }
+ } else if (sharedIdStr != null) {
+ userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ if (userId > 0) {
+ packageSetting = new PendingPackage(name.intern(), realName, new File(
+ codePathStr), new File(resourcePathStr), nativeLibraryPathStr, userId,
+ versionCode, pkgFlags);
+ packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
+ mPendingPackages.add((PendingPackage) packageSetting);
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.i(PackageManagerService.TAG, "Reading package " + name
+ + ": sharedUserId=" + userId + " pkg=" + packageSetting);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name
+ + " has bad sharedId " + sharedIdStr + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ if (packageSetting != null) {
+ packageSetting.uidError = "true".equals(uidError);
+ packageSetting.installerPackageName = installerPackageName;
+ packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
+ final String enabledStr = parser.getAttributeValue(null, "enabled");
+ if (enabledStr != null) {
+ if (enabledStr.equalsIgnoreCase("true")) {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
+ } else if (enabledStr.equalsIgnoreCase("false")) {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
+ } else if (enabledStr.equalsIgnoreCase("default")) {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name
+ + " has bad enabled value: " + idStr + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ final String installStatusStr = parser.getAttributeValue(null, "installStatus");
+ if (installStatusStr != null) {
+ if (installStatusStr.equalsIgnoreCase("false")) {
+ packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE;
+ } else {
+ packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
+ }
+ }
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("disabled-components")) {
+ readDisabledComponentsLPw(packageSetting, parser);
+ } else if (tagName.equals("enabled-components")) {
+ readEnabledComponentsLPw(packageSetting, parser);
+ } else if (tagName.equals("sigs")) {
+ packageSetting.signatures.readXml(parser, mPastSignatures);
+ } else if (tagName.equals("perms")) {
+ readGrantedPermissionsLPw(parser, packageSetting.grantedPermissions);
+ packageSetting.permissionsFixed = true;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <package>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ packageSetting.disabledComponents.add(name.intern());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <disabled-components> has"
+ + " no name at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <disabled-components>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ packageSetting.enabledComponents.add(name.intern());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <enabled-components> has"
+ + " no name at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <enabled-components>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String name = null;
+ String idStr = null;
+ int pkgFlags = 0;
+ SharedUserSetting su = null;
+ try {
+ name = parser.getAttributeValue(null, "name");
+ idStr = parser.getAttributeValue(null, "userId");
+ int userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if ("true".equals(parser.getAttributeValue(null, "system"))) {
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ if (name == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <shared-user> has no name at "
+ + parser.getPositionDescription());
+ } else if (userId == 0) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: shared-user " + name
+ + " has bad userId " + idStr + " at "
+ + parser.getPositionDescription());
+ } else {
+ if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
+ PackageManagerService
+ .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
+ + parser.getPositionDescription());
+ }
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ ;
+
+ if (su != null) {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("sigs")) {
+ su.signatures.readXml(parser, mPastSignatures);
+ } else if (tagName.equals("perms")) {
+ readGrantedPermissionsLPw(parser, su.grantedPermissions);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <shared-user>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readGrantedPermissionsLPw(XmlPullParser parser, HashSet<String> outPerms)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ outPerms.add(name.intern());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <perms> has" + " no name at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <perms>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readPreferredActivitiesLPw(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ PreferredActivity pa = new PreferredActivity(parser);
+ if (pa.mPref.getParseError() == null) {
+ mPreferredActivities.addFilter(pa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + pa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ // Returns -1 if we could not find an available UserId to assign
+ private int newUserIdLPw(Object obj) {
+ // Let's be stupidly inefficient for now...
+ final int N = mUserIds.size();
+ for (int i = 0; i < N; i++) {
+ if (mUserIds.get(i) == null) {
+ mUserIds.set(i, obj);
+ return PackageManagerService.FIRST_APPLICATION_UID + i;
+ }
+ }
+
+ // None left?
+ if (N >= PackageManagerService.MAX_APPLICATION_UIDS) {
+ return -1;
+ }
+
+ mUserIds.add(obj);
+ return PackageManagerService.FIRST_APPLICATION_UID + N;
+ }
+
+ public PackageSetting getDisabledSystemPkgLPr(String name) {
+ PackageSetting ps = mDisabledSysPackages.get(name);
+ return ps;
+ }
+
+ boolean isEnabledLPr(ComponentInfo componentInfo, int flags) {
+ if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
+ return true;
+ }
+ final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
+ if (PackageManagerService.DEBUG_SETTINGS) {
+ Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + componentInfo.packageName
+ + " componentName = " + componentInfo.name);
+ Log.v(PackageManagerService.TAG, "enabledComponents: "
+ + Arrays.toString(packageSettings.enabledComponents.toArray()));
+ Log.v(PackageManagerService.TAG, "disabledComponents: "
+ + Arrays.toString(packageSettings.disabledComponents.toArray()));
+ }
+ if (packageSettings == null) {
+ return false;
+ }
+ if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
+ || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
+ && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
+ return false;
+ }
+ if (packageSettings.enabledComponents.contains(componentInfo.name)) {
+ return true;
+ }
+ if (packageSettings.disabledComponents.contains(componentInfo.name)) {
+ return false;
+ }
+ return componentInfo.enabled;
+ }
+
+ String getInstallerPackageNameLPr(String packageName) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.installerPackageName;
+ }
+
+ int getApplicationEnabledSettingLPr(String packageName) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.enabled;
+ }
+
+ int getComponentEnabledSettingLPr(ComponentName componentName) {
+ final String packageName = componentName.getPackageName();
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown component: " + componentName);
+ }
+ final String classNameStr = componentName.getClassName();
+ return pkg.getCurrentEnabledStateLPr(classNameStr);
+ }
+
+ boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
+ boolean allowedByPermission, int uid) {
+ final PackageSetting pkgSetting = mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ if (!allowedByPermission && (uid != pkgSetting.userId)) {
+ throw new SecurityException(
+ "Permission Denial: attempt to change stopped state from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
+ }
+ if (DEBUG_STOPPED) {
+ if (stopped) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(TAG, "Stopping package " + packageName, e);
+ }
+ }
+ if (pkgSetting.stopped != stopped) {
+ pkgSetting.stopped = stopped;
+ pkgSetting.pkg.mSetStopped = stopped;
+ if (pkgSetting.notLaunched) {
+ if (pkgSetting.installerPackageName != null) {
+ PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
+ pkgSetting.name, null,
+ pkgSetting.installerPackageName, null);
+ }
+ pkgSetting.notLaunched = false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ final Date date = new Date();
+ boolean printedSomething = false;
+ for (final PackageSetting ps : mPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+
+ if (packageName != null) {
+ dumpState.setSharedUser(ps.sharedUser);
+ }
+
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Packages:");
+ printedSomething = true;
+ }
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+
+ if (ps.realName != null) {
+ pw.print(" compat name=");
+ pw.println(ps.name);
+ }
+
+ pw.print(" userId="); pw.print(ps.userId);
+ pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
+ pw.print(" sharedUser="); pw.println(ps.sharedUser);
+ pw.print(" pkg="); pw.println(ps.pkg);
+ pw.print(" codePath="); pw.println(ps.codePathString);
+ pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
+ pw.print(" versionCode="); pw.println(ps.versionCode);
+ if (ps.pkg != null) {
+ 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);
+ if (ps.pkg.mOperationPending) {
+ pw.println(" mOperationPending=true");
+ }
+ pw.print(" supportsScreens=[");
+ boolean first = true;
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("small");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("medium");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("large");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("xlarge");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("resizeable");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("anyDensity");
+ }
+ }
+ pw.println("]");
+ pw.print(" timeStamp=");
+ date.setTime(ps.timeStamp);
+ pw.println(sdf.format(date));
+ pw.print(" firstInstallTime=");
+ date.setTime(ps.firstInstallTime);
+ pw.println(sdf.format(date));
+ pw.print(" lastUpdateTime=");
+ date.setTime(ps.lastUpdateTime);
+ pw.println(sdf.format(date));
+ if (ps.installerPackageName != null) {
+ pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
+ }
+ pw.print(" signatures="); pw.println(ps.signatures);
+ pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
+ pw.print(" haveGids="); pw.println(ps.haveGids);
+ pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
+ pw.print(" installStatus="); pw.print(ps.installStatus);
+ pw.print(" stopped="); pw.print(ps.stopped);
+ pw.print(" enabled="); pw.println(ps.enabled);
+ if (ps.disabledComponents.size() > 0) {
+ pw.println(" disabledComponents:");
+ for (String s : ps.disabledComponents) {
+ pw.print(" "); pw.println(s);
+ }
+ }
+ if (ps.enabledComponents.size() > 0) {
+ pw.println(" enabledComponents:");
+ for (String s : ps.enabledComponents) {
+ pw.print(" "); pw.println(s);
+ }
+ }
+ if (ps.grantedPermissions.size() > 0) {
+ pw.println(" grantedPermissions:");
+ for (String s : ps.grantedPermissions) {
+ pw.print(" "); pw.println(s);
+ }
+ }
+ }
+
+ printedSomething = false;
+ if (mRenamedPackages.size() > 0) {
+ for (final HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ if (packageName != null && !packageName.equals(e.getKey())
+ && !packageName.equals(e.getValue())) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Renamed packages:");
+ printedSomething = true;
+ }
+ pw.print(" ");
+ pw.print(e.getKey());
+ pw.print(" -> ");
+ pw.println(e.getValue());
+ }
+ }
+
+ printedSomething = false;
+ if (mDisabledSysPackages.size() > 0) {
+ for (final PackageSetting ps : mDisabledSysPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Hidden system packages:");
+ printedSomething = true;
+ }
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+ if (ps.realName != null) {
+ pw.print(" compat name=");
+ pw.println(ps.name);
+ }
+ pw.print(" userId=");
+ pw.println(ps.userId);
+ pw.print(" sharedUser=");
+ pw.println(ps.sharedUser);
+ pw.print(" codePath=");
+ pw.println(ps.codePathString);
+ pw.print(" resourcePath=");
+ pw.println(ps.resourcePathString);
+ }
+ }
+ }
+
+ void dumpPermissionsLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ boolean printedSomething = false;
+ for (BasePermission p : mPermissions.values()) {
+ if (packageName != null && !packageName.equals(p.sourcePackage)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Permissions:");
+ printedSomething = true;
+ }
+ pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(p)));
+ pw.println("):");
+ pw.print(" sourcePackage="); pw.println(p.sourcePackage);
+ pw.print(" uid="); pw.print(p.uid);
+ pw.print(" gids="); pw.print(PackageManagerService.arrayToString(p.gids));
+ pw.print(" type="); pw.print(p.type);
+ pw.print(" prot="); pw.println(p.protectionLevel);
+ if (p.packageSetting != null) {
+ pw.print(" packageSetting="); pw.println(p.packageSetting);
+ }
+ if (p.perm != null) {
+ pw.print(" perm="); pw.println(p.perm);
+ }
+ }
+ }
+
+ void dumpSharedUsersLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ boolean printedSomething = false;
+ for (SharedUserSetting su : mSharedUsers.values()) {
+ if (packageName != null && su != dumpState.getSharedUser()) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Shared users:");
+ printedSomething = true;
+ }
+ pw.print(" SharedUser [");
+ pw.print(su.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(su)));
+ pw.println("):");
+ pw.print(" userId=");
+ pw.print(su.userId);
+ pw.print(" gids=");
+ pw.println(PackageManagerService.arrayToString(su.gids));
+ pw.println(" grantedPermissions:");
+ for (String s : su.grantedPermissions) {
+ pw.print(" ");
+ pw.println(s);
+ }
+ }
+ }
+
+ void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) {
+ pw.println("Settings parse messages:");
+ pw.print(mReadMessages.toString());
+ }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/java/com/android/server/pm/SharedUserSetting.java
new file mode 100644
index 0000000..76826ea
--- /dev/null
+++ b/services/java/com/android/server/pm/SharedUserSetting.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.server.pm;
+
+import java.util.HashSet;
+
+/**
+ * Settings data for a particular shared user ID we know about.
+ */
+final class SharedUserSetting extends GrantedPermissions {
+ final String name;
+
+ int userId;
+
+ final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
+
+ final PackageSignatures signatures = new PackageSignatures();
+
+ SharedUserSetting(String _name, int _pkgFlags) {
+ super(_pkgFlags);
+ name = _name;
+ }
+
+ @Override
+ public String toString() {
+ return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
+ + name + "/" + userId + "}";
+ }
+}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index be37d5d..4e93fe2 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -34,7 +34,7 @@
libui \
libinput \
libskia \
- libsurfaceflinger_client \
+ libgui \
libusbhost
ifeq ($(TARGET_SIMULATOR),true)
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index e7e1fa2..96cf4bd 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -600,6 +600,7 @@
android_server_InputApplication_toNative(env, applicationObj, &application);
if (application.inputApplicationHandle != NULL) {
mInputManager->getDispatcher()->setFocusedApplication(&application);
+ return;
}
}
mInputManager->getDispatcher()->setFocusedApplication(NULL);
@@ -788,7 +789,9 @@
jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj,
gCallbacksClassInfo.dispatchUnhandledKey,
inputWindowHandleObj, keyEventObj, policyFlags);
- checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
+ if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
+ fallbackKeyEventObj = NULL;
+ }
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
@@ -819,7 +822,9 @@
JNIEnv* env = jniEnv();
jboolean result = env->CallBooleanMethod(mCallbacksObj,
gCallbacksClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
- checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission");
+ if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {
+ result = false;
+ }
return result;
}
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 816f76f..6aeede2 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -117,9 +117,14 @@
jintArray endpointArray = env->NewIntArray(length);
env->SetIntArrayRegion(endpointArray, 0, length, endpointValues.array());
+ jstring deviceName = env->NewStringUTF(devname);
env->CallVoidMethod(thiz, method_usbDeviceAdded,
- env->NewStringUTF(devname), vendorId, productId, deviceClass,
+ deviceName, vendorId, productId, deviceClass,
deviceSubClass, protocol, interfaceArray, endpointArray);
+
+ env->DeleteLocalRef(interfaceArray);
+ env->DeleteLocalRef(endpointArray);
+ env->DeleteLocalRef(deviceName);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return 0;
@@ -129,7 +134,9 @@
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject thiz = (jobject)client_data;
+ jstring deviceName = env->NewStringUTF(devname);
env->CallVoidMethod(thiz, method_usbDeviceRemoved, env->NewStringUTF(devname));
+ env->DeleteLocalRef(deviceName);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return 0;
}
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 8a00a2e..9daaad8 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -41,7 +41,7 @@
libGLESv1_CM \
libbinder \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/services/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk
index 24c2d01..d81679e 100644
--- a/services/surfaceflinger/tests/resize/Android.mk
+++ b/services/surfaceflinger/tests/resize/Android.mk
@@ -8,7 +8,7 @@
libcutils \
libutils \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= test-resize
diff --git a/services/surfaceflinger/tests/screencap/Android.mk b/services/surfaceflinger/tests/screencap/Android.mk
index 1cfb471..5cdd1a8 100644
--- a/services/surfaceflinger/tests/screencap/Android.mk
+++ b/services/surfaceflinger/tests/screencap/Android.mk
@@ -10,7 +10,7 @@
libbinder \
libskia \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= test-screencap
diff --git a/services/surfaceflinger/tests/surface/Android.mk b/services/surfaceflinger/tests/surface/Android.mk
index ce0e807..c59060e 100644
--- a/services/surfaceflinger/tests/surface/Android.mk
+++ b/services/surfaceflinger/tests/surface/Android.mk
@@ -9,7 +9,7 @@
libutils \
libbinder \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= test-surface
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index d4a3c0a..be97124 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -247,6 +247,9 @@
/* Currently active APN */
protected ApnSetting mActiveApn;
+ /* Once disposed dont handle any messages */
+ protected boolean mIsDisposed = false;
+
protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
{
@Override
@@ -327,6 +330,7 @@
}
public void dispose() {
+ mIsDisposed = true;
mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 88aed28..1d47405 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -207,9 +207,8 @@
*/
public final class RIL extends BaseCommands implements CommandsInterface {
static final String LOG_TAG = "RILJ";
- private static final boolean DBG = false;
- static final boolean RILJ_LOGD = Config.LOGD;
- static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV;
+ static final boolean RILJ_LOGD = true;
+ static final boolean RILJ_LOGV = false; // STOP SHIP if true
/**
* Wake lock timeout should be longer than the longest timeout in
@@ -2069,7 +2068,7 @@
if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
setRadioPower(false, null);
} else {
- if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
+ if (RILJ_LOGD) Log.d(LOG_TAG, "Radio OFF @ init");
setRadioState(newState);
setPreferredNetworkType(mNetworkMode, null);
}
@@ -2366,7 +2365,10 @@
case RIL_REQUEST_GET_IMSI:
case RIL_REQUEST_GET_IMEI:
case RIL_REQUEST_GET_IMEISV:
- return "";
+ if (!RILJ_LOGV) {
+ // If not versbose logging just return and don't display IMSI and IMEI, IMEISV
+ return "";
+ }
}
StringBuilder sb;
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 36059ad..a6c7777 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -375,25 +375,30 @@
private void encodeOptionalTags(CommandDetails cmdDet,
ResultCode resultCode, Input cmdInput, ByteArrayOutputStream buf) {
- switch (AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) {
- case GET_INKEY:
- // ETSI TS 102 384,27.22.4.2.8.4.2.
- // If it is a response for GET_INKEY command and the response timeout
- // occured, then add DURATION TLV for variable timeout case.
- if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
- (cmdInput != null) && (cmdInput.duration != null)) {
- getInKeyResponse(buf, cmdInput);
- }
- break;
- case PROVIDE_LOCAL_INFORMATION:
- if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
- (resultCode.value() == ResultCode.OK.value())) {
- getPliResponse(buf);
- }
- break;
- default:
- CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
- break;
+ CommandType cmdType = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand);
+ if (cmdType != null) {
+ switch (cmdType) {
+ case GET_INKEY:
+ // ETSI TS 102 384,27.22.4.2.8.4.2.
+ // If it is a response for GET_INKEY command and the response timeout
+ // occured, then add DURATION TLV for variable timeout case.
+ if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
+ (cmdInput != null) && (cmdInput.duration != null)) {
+ getInKeyResponse(buf, cmdInput);
+ }
+ break;
+ case PROVIDE_LOCAL_INFORMATION:
+ if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
+ (resultCode.value() == ResultCode.OK.value())) {
+ getPliResponse(buf);
+ }
+ break;
+ default:
+ CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
+ break;
+ }
+ } else {
+ CatLog.d(this, "encodeOptionalTags() bad Cmd:" + cmdDet.typeOfCommand);
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index b244945..b24909f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -118,6 +118,8 @@
@Override
public void dispose() {
+ cleanUpConnection(false, null);
+
super.dispose();
// Unregister from all events
@@ -861,7 +863,7 @@
@Override
public void handleMessage (Message msg) {
- if (!mPhone.mIsTheCurrentActivePhone) {
+ if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
log("Ignore CDMA msgs since CDMA phone is inactive");
return;
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 40b5610..81b4077def 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -219,6 +219,7 @@
break;
case ServiceState.RADIO_TECHNOLOGY_EHRPD:
ret = "CDMA - eHRPD";
+ break;
default:
if (DBG) {
Log.e(LOG_TAG, " [CdmaLteServiceStateTracker] Wrong network."
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 4ab3834..658de84 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -1222,6 +1222,7 @@
case 7: // RADIO_TECHNOLOGY_EVDO_0
case 8: // RADIO_TECHNOLOGY_EVDO_A
case 12: // RADIO_TECHNOLOGY_EVDO_B
+ case 13: // RADIO_TECHNOLOGY_EHRPD
retVal = ServiceState.STATE_IN_SERVICE;
break;
default:
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index d602c38..d8ff268 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -192,6 +192,8 @@
@Override
public void dispose() {
+ cleanUpAllConnections(false, null);
+
super.dispose();
//Unregister for all events
@@ -818,6 +820,7 @@
result.add(apn);
} while (cursor.moveToNext());
}
+ if (DBG) log("createApnList: X result=" + result);
return result;
}
@@ -1604,6 +1607,7 @@
if (operator != null) {
String selection = "numeric = '" + operator + "'";
+ if (DBG) log("createAllApnList: selection=" + selection);
Cursor cursor = mPhone.getContext().getContentResolver().query(
Telephony.Carriers.CONTENT_URI, null, selection, null, null);
@@ -1617,18 +1621,19 @@
}
if (mAllApns.isEmpty()) {
- if (DBG) log("No APN found for carrier: " + operator);
+ if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
mPreferredApn = null;
// TODO: What is the right behaviour?
//notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
} else {
mPreferredApn = getPreferredApn();
- log("Get PreferredAPN");
if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
mPreferredApn = null;
setPreferredApn(-1);
}
+ if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
}
+ if (DBG) log("createAllApnList: X mAllApns=" + mAllApns);
}
/** Return the id for a new data connection */
@@ -1687,6 +1692,7 @@
if (requestedApnType.equals(Phone.APN_TYPE_DUN)) {
ApnSetting dun = fetchDunApn();
if (dun != null) apnList.add(dun);
+ if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
return apnList;
}
@@ -1697,10 +1703,11 @@
log("Preferred APN:" + operator + ":"
+ mPreferredApn.numeric + ":" + mPreferredApn);
if (mPreferredApn.numeric.equals(operator)) {
- log("Waiting APN set to preferred APN");
apnList.add(mPreferredApn);
+ if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
return apnList;
} else {
+ if (DBG) log("buildWaitingApns: no preferred APN");
setPreferredApn(-1);
mPreferredApn = null;
}
@@ -1714,6 +1721,7 @@
}
}
}
+ if (DBG) log("buildWaitingApns: X apnList=" + apnList);
return apnList;
}
@@ -1785,7 +1793,7 @@
public void handleMessage (Message msg) {
if (DBG) log("GSMDataConnTrack handleMessage "+msg);
- if (!mPhone.mIsTheCurrentActivePhone) {
+ if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
log("Ignore GSM msgs since GSM phone is inactive");
return;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 11ce83e..e69989a 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -478,6 +478,11 @@
// Length = length of MCC + length of MNC
// length of mcc = 3 (TS 23.003 Section 2.2)
+ if (SystemProperties.getInt(com.android.internal.telephony.TelephonyProperties
+ .PROPERTY_NETWORK_LTE_ON_CDMA, 0) == 1) {
+ Log.e(LOG_TAG, "getSIMOperatorNumeric: STOPSHIP bad numeric operators in lte");
+ return SystemProperties.get("ro.cdma.home.operator.numeric", "310004");
+ }
return imsi.substring(0, 3 + mncLength);
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
old mode 100755
new mode 100644
index 7373cbb..5471289
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -40,6 +40,7 @@
import java.text.ParseException;
import java.util.List;
+import java.util.regex.Pattern;
/**
* {@hide}
@@ -386,8 +387,8 @@
Connection dial(String originalNumber) throws SipException {
String calleeSipUri = originalNumber;
if (!calleeSipUri.contains("@")) {
- calleeSipUri = mProfile.getUriString().replaceFirst(
- mProfile.getUserName() + "@",
+ String replaceStr = Pattern.quote(mProfile.getUserName() + "@");
+ calleeSipUri = mProfile.getUriString().replaceFirst(replaceStr,
calleeSipUri + "@");
}
try {
diff --git a/tests/BiDiTests/Android.mk b/tests/BiDiTests/Android.mk
new file mode 100644
index 0000000..ae29fc2
--- /dev/null
+++ b/tests/BiDiTests/Android.mk
@@ -0,0 +1,27 @@
+# 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
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BiDiTests
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
new file mode 100644
index 0000000..346ace8
--- /dev/null
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<!-- Declare the contents of this Android application. The namespace
+ attribute brings in the Android platform namespace, and the package
+ supplies a unique name for the application. When writing your
+ own application, the package name must be changed from "com.example.*"
+ to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.bidi"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:label="BiDiTests">
+ <activity android:name="BiDiTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/BiDiTests/proguard.flags b/tests/BiDiTests/proguard.flags
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/BiDiTests/proguard.flags
diff --git a/tests/BiDiTests/res/layout/biditest_main.xml b/tests/BiDiTests/res/layout/biditest_main.xml
new file mode 100644
index 0000000..9f77ad2
--- /dev/null
+++ b/tests/BiDiTests/res/layout/biditest_main.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/button"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:onClick="onButtonClick"
+ android:text="@string/button_text"
+ android:textSize="32dip"
+ />
+
+ <TextView android:id="@+id/textview"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="32dip"
+ android:text="@string/textview_text"
+ />
+
+ <EditText android:id="@+id/textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:textSize="32dip"
+ android:text="@string/edittext_text"
+ />
+
+ </LinearLayout>
+
+ <view class="com.android.bidi.BiDiTestView"
+ android:id="@+id/main"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#FF0000"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
new file mode 100644
index 0000000..ecff76e
--- /dev/null
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -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.
+-->
+<resources>
+ <string name="button_text">Button</string>
+ <string name="textview_text">This is a text for a TextView</string>
+ <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
+ <string name="normal_text">Normal String</string>
+ <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
+ <string name="arabic_text">لا</string>
+ <string name="chinese_text">利比亚局势或影响美俄关系发展</string>
+ <string name="italic_text">Italic String</string>
+ <string name="bold_text">Bold String</string>
+ <string name="bold_italic_text">Bold Italic String</string>
+</resources>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
new file mode 100644
index 0000000..3d7dd81
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.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.bidi;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+public class BiDiTestActivity extends Activity {
+
+ static final String TAG = "BiDiTestActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.biditest_main);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ public void onButtonClick(View v) {
+ Log.v(TAG, "onButtonClick");
+ }
+}
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
new file mode 100644
index 0000000..e9b6fa6
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -0,0 +1,190 @@
+/*
+ * 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.bidi;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+public class BiDiTestView extends View {
+
+ private static final String TAG = "BiDiTestView";
+
+ private static final int BORDER_PADDING = 4;
+ private static final int TEXT_PADDING = 16;
+ private static final int TEXT_SIZE = 32;
+ private static final int ORIGIN = 48;
+ private static final int DELTA_Y = TEXT_SIZE;
+
+ private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
+
+ private Paint paint = new Paint();
+ private Rect rect = new Rect();
+
+ private String NORMAL_TEXT;
+ private String NORMAL_LONG_TEXT;
+ private String ITALIC_TEXT;
+ private String BOLD_TEXT;
+ private String BOLD_ITALIC_TEXT;
+ private String ARABIC_TEXT;
+ private String CHINESE_TEXT;
+
+ private Typeface typeface;
+
+ public BiDiTestView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public BiDiTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public BiDiTestView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ private void init(Context context) {
+ NORMAL_TEXT = context.getString(R.string.normal_text);
+ NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
+ ITALIC_TEXT = context.getString(R.string.italic_text);
+ BOLD_TEXT = context.getString(R.string.bold_text);
+ BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
+ ARABIC_TEXT = context.getString(R.string.arabic_text);
+ CHINESE_TEXT = context.getString(R.string.chinese_text);
+
+ typeface = paint.getTypeface();
+ paint.setAntiAlias(true);
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ drawInsideRect(canvas, Color.BLACK);
+
+ int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, paint, typeface,
+ false, false, Paint.DIRECTION_LTR);
+ deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
+ true, false, Paint.DIRECTION_LTR);
+ deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
+ false, true, Paint.DIRECTION_LTR);
+ deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
+ true, true, Paint.DIRECTION_LTR);
+
+ // Test with a long string
+ deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * DELTA_Y, paint, typeface,
+ false, false, Paint.DIRECTION_LTR);
+
+ // Test Arabic ligature
+ deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 4 * DELTA_Y, paint, typeface,
+ false, false, Paint.DIRECTION_RTL);
+
+ // Test Chinese
+ deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 6 * DELTA_Y, paint, typeface,
+ false, false, Paint.DIRECTION_LTR);
+ }
+
+ private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
+ boolean isItalic, boolean isBold, int dir) {
+ paint.setTypeface(typeface);
+
+ // Set paint properties
+ boolean oldFakeBold = paint.isFakeBoldText();
+ paint.setFakeBoldText(isBold);
+
+ float oldTextSkewX = paint.getTextSkewX();
+ if (isItalic) {
+ paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
+ }
+
+ drawTextWithCanvasDrawText(text, canvas, x, y, TEXT_SIZE, Color.WHITE);
+
+ int length = text.length();
+ float[] advances = new float[length];
+ float textWidth = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
+
+ logAdvances(text, textWidth, advances);
+ drawBoxAroundText(canvas, x, y, textWidth, TEXT_SIZE, Color.RED);
+
+ paint.setColor(Color.WHITE);
+ char[] glyphs = new char[2*length];
+ int count = getGlyphs(text, glyphs, dir);
+
+ logGlypths(glyphs, count);
+ drawTextWithDrawGlyph(canvas, glyphs, count, x, y + DELTA_Y);
+
+ // Restore old paint properties
+ paint.setFakeBoldText(oldFakeBold);
+ paint.setTextSkewX(oldTextSkewX);
+
+ return (int) Math.ceil(textWidth) + TEXT_PADDING;
+ }
+
+ private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
+ canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
+ }
+
+ private void logGlypths(char[] glyphs, int count) {
+ Log.v(TAG, "GlyphIds - count=" + count);
+ for (int n = 0; n < count; n++) {
+ Log.v(TAG, "GlyphIds - Id[" + n + "]="+ (int)glyphs[n]);
+ }
+ }
+
+ private int getGlyphs(String text, char[] glyphs, int dir) {
+// int dir = 1; // Paint.DIRECTION_LTR;
+ return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
+ }
+
+ private void drawInsideRect(Canvas canvas, int color) {
+ paint.setColor(color);
+ int width = getWidth();
+ int height = getHeight();
+ rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING);
+ canvas.drawRect(rect, paint);
+ }
+
+ private void drawTextWithCanvasDrawText(String text, Canvas canvas,
+ float x, float y, float textSize, int color) {
+ paint.setColor(color);
+ paint.setTextSize(textSize);
+ canvas.drawText(text, x, y, paint);
+ }
+
+ private void drawBoxAroundText(Canvas canvas, int x, int y, float textWidth, int textSize,
+ int color) {
+ paint.setColor(color);
+ canvas.drawLine(x, y - textSize, x, y + 8, paint);
+ canvas.drawLine(x, y + 8, x + textWidth, y + 8, paint);
+ canvas.drawLine(x + textWidth, y - textSize, x + textWidth, y + 8, paint);
+ }
+
+ private void logAdvances(String text, float textWidth, float[] advances) {
+ Log.v(TAG, "Advances for text: " + text + " total=" + textWidth);
+ int length = advances.length;
+ for(int n=0; n<length; n++){
+ Log.v(TAG, "adv[" + n + "]=" + advances[n]);
+ }
+ }
+}
diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java
index ac580e7..4ee86b6 100644
--- a/voip/java/com/android/server/sip/SipHelper.java
+++ b/voip/java/com/android/server/sip/SipHelper.java
@@ -27,6 +27,8 @@
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
+import java.util.regex.Pattern;
+
import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.DialogTerminatedEvent;
@@ -215,9 +217,11 @@
String tag) throws ParseException, SipException {
FromHeader fromHeader = createFromHeader(userProfile, tag);
ToHeader toHeader = createToHeader(userProfile);
+
+ String replaceStr = Pattern.quote(userProfile.getUserName() + "@");
SipURI requestURI = mAddressFactory.createSipURI(
- userProfile.getUriString().replaceFirst(
- userProfile.getUserName() + "@", ""));
+ userProfile.getUriString().replaceFirst(replaceStr, ""));
+
List<ViaHeader> viaHeaders = createViaHeaders();
CallIdHeader callIdHeader = createCallIdHeader();
CSeqHeader cSeqHeader = createCSeqHeader(requestType);