Merge change 9004
* changes:
Fix NullPointerException when checking if its a sinkDevice.
diff --git a/api/4.xml b/api/4.xml
index c8a2e83..cac3ae8 100644
--- a/api/4.xml
+++ b/api/4.xml
@@ -256713,7 +256713,7 @@
extends="java.lang.Enum"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -258766,7 +258766,7 @@
<package name="java.util.concurrent.locks"
>
<class name="AbstractQueuedSynchronizer"
- extends="java.lang.Object"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
abstract="true"
static="false"
final="false"
diff --git a/api/current.xml b/api/current.xml
index c819972..b1e9c83 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1024,17 +1024,6 @@
visibility="public"
>
</field>
-<field name="SHUTDOWN"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.permission.SHUTDOWN""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SIGNAL_PERSISTENT_PROCESSES"
type="java.lang.String"
transient="false"
@@ -1057,17 +1046,6 @@
visibility="public"
>
</field>
-<field name="STOP_APP_SWITCHES"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.permission.STOP_APP_SWITCHES""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SUBSCRIBED_FEEDS_READ"
type="java.lang.String"
transient="false"
@@ -31763,17 +31741,6 @@
visibility="public"
>
</field>
-<field name="BACKUP_SERVICE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""backup""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="BIND_AUTO_CREATE"
type="int"
transient="false"
@@ -32619,19 +32586,6 @@
<parameter name="mode" type="int">
</parameter>
</method>
-<method name="getSharedPrefsFile"
- return="java.io.File"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</method>
<method name="getSystemService"
return="java.lang.Object"
abstract="false"
@@ -33426,70 +33380,6 @@
</exception>
</method>
</interface>
-<interface name="IIntentReceiver"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.os.IInterface">
-</implements>
-<method name="performReceive"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-<parameter name="resultCode" type="int">
-</parameter>
-<parameter name="data" type="java.lang.String">
-</parameter>
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-<parameter name="ordered" type="boolean">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</interface>
-<interface name="IIntentSender"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.os.IInterface">
-</implements>
-<method name="send"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="code" type="int">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-<parameter name="resolvedType" type="java.lang.String">
-</parameter>
-<parameter name="finishedReceiver" type="android.content.IIntentReceiver">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</interface>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -37683,26 +37573,6 @@
>
<implements name="android.os.Parcelable">
</implements>
-<constructor name="IntentSender"
- type="android.content.IntentSender"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="target" type="android.content.IIntentSender">
-</parameter>
-</constructor>
-<constructor name="IntentSender"
- type="android.content.IntentSender"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="target" type="android.os.IBinder">
-</parameter>
-</constructor>
<method name="describeContents"
return="int"
abstract="false"
@@ -51230,17 +51100,6 @@
<parameter name="entryName" type="java.lang.String">
</parameter>
</method>
-<method name="getLearner"
- return="android.gesture.Learner"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getOrientationStyle"
return="int"
abstract="false"
@@ -52509,15 +52368,6 @@
>
</field>
</class>
-<class name="Learner"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility=""
->
-</class>
<class name="OrientedBoundingBox"
extends="java.lang.Object"
abstract="false"
@@ -123165,19 +123015,6 @@
<parameter name="mode" type="int">
</parameter>
</method>
-<method name="getSharedPrefsFile"
- return="java.io.File"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</method>
<method name="getSystemService"
return="java.lang.Object"
abstract="false"
@@ -146942,7 +146779,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -146968,6 +146805,17 @@
visibility="public"
>
</field>
+<field name="SURFACE_FROZEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SURFACE_HIDDEN"
type="int"
transient="false"
@@ -163493,6 +163341,8 @@
</parameter>
<parameter name="currentQuota" type="long">
</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
</parameter>
</method>
@@ -165153,6 +165003,8 @@
</parameter>
<parameter name="currentQuota" type="long">
</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
</parameter>
</method>
@@ -193475,7 +193327,7 @@
<method name="valid"
return="boolean"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -198598,7 +198450,7 @@
return="java.nio.channels.FileChannel"
abstract="false"
native="false"
- synchronized="false"
+ synchronized="true"
static="false"
final="true"
deprecated="not deprecated"
@@ -207468,7 +207320,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="i" type="int">
+<parameter name="value" type="int">
</parameter>
</method>
<method name="toString"
@@ -208268,10 +208120,10 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="y" type="double">
-</parameter>
<parameter name="x" type="double">
</parameter>
+<parameter name="y" type="double">
+</parameter>
</method>
<method name="cbrt"
return="double"
@@ -273628,7 +273480,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -273641,7 +273493,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -273652,7 +273504,7 @@
return="int"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -273687,7 +273539,7 @@
return="boolean"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -273722,7 +273574,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -276067,7 +275919,7 @@
return="E"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -277433,7 +277285,7 @@
return="E"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -277913,7 +277765,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -277926,7 +277778,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -277984,7 +277836,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -278044,7 +277896,20 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="contains"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="drainTo"
@@ -278085,7 +277950,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -278098,7 +277963,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -278134,7 +277999,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -278150,6 +278015,19 @@
visibility="public"
>
</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="take"
return="E"
abstract="true"
@@ -278367,7 +278245,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="java.util.Map<? extends K, ? extends V>">
+<parameter name="m" type="java.util.Map<? extends K, ? extends V>">
</parameter>
</constructor>
<method name="contains"
@@ -278530,7 +278408,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -278680,7 +278558,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="array" type="E[]">
+<parameter name="toCopyIn" type="E[]">
</parameter>
</constructor>
<method name="add"
@@ -278708,7 +278586,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="e" type="E">
+<parameter name="element" type="E">
</parameter>
</method>
<method name="addAll"
@@ -278836,9 +278714,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="indexOf"
@@ -278851,7 +278727,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
</parameter>
</method>
<method name="isEmpty"
@@ -278886,9 +278764,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="lastIndexOf"
@@ -278901,7 +278777,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
</parameter>
</method>
<method name="listIterator"
@@ -278992,7 +278870,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="e" type="E">
+<parameter name="element" type="E">
</parameter>
</method>
<method name="size"
@@ -279356,7 +279234,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -279369,7 +279247,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -279397,12 +279275,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="time" type="long">
-</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
-</parameter>
-<exception name="InterruptedException" type="java.lang.InterruptedException">
-</exception>
</method>
<method name="poll"
return="E"
@@ -279414,6 +279286,12 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
</method>
<method name="put"
return="void"
@@ -279425,7 +279303,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="remainingCapacity"
@@ -280496,7 +280374,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -280515,7 +280393,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -280567,7 +280445,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -280720,7 +280598,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -280733,7 +280611,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -280789,7 +280667,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="remainingCapacity"
@@ -281519,7 +281397,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -282224,7 +282102,7 @@
extends="java.lang.Enum"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -282238,9 +282116,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="long">
+<parameter name="sourceDuration" type="long">
</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
+<parameter name="sourceUnit" type="java.util.concurrent.TimeUnit">
</parameter>
</method>
<method name="sleep"
@@ -284276,12 +284154,55 @@
</package>
<package name="java.util.concurrent.locks"
>
-<class name="AbstractQueuedSynchronizer"
+<class name="AbstractOwnableSynchronizer"
extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
+ visibility=""
+>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractOwnableSynchronizer"
+ type="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<method name="getExclusiveOwnerThread"
+ return="java.lang.Thread"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="setExclusiveOwnerThread"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="t" type="java.lang.Thread">
+</parameter>
+</method>
+</class>
+<class name="AbstractQueuedSynchronizer"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
visibility="public"
>
<implements name="java.io.Serializable">
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index e2d01de..f101007 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -202,7 +202,6 @@
// draw and update only what we need
mFlingerSurface->setSwapRectangle(updateRect);
- glEnable(GL_SCISSOR_TEST);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
@@ -218,6 +217,10 @@
GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
GLint x = xc - offset;
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 346f156..3c82fe5 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -16,9 +16,12 @@
#define LOG_TAG "BootAnimation"
+#include <cutils/properties.h>
+
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+
#include <utils/Log.h>
#include <utils/threads.h>
@@ -41,12 +44,20 @@
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
#endif
- sp<ProcessState> proc(ProcessState::self());
- ProcessState::self()->startThreadPool();
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.nobootanimation", value, "0");
+ int noBootAnimation = atoi(value);
+ LOGI_IF(noBootAnimation, "boot animation disabled");
+ if (!noBootAnimation) {
- // create the boot animation object
- sp<BootAnimation> boot = new BootAnimation();
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
+ // create the boot animation object
+ sp<BootAnimation> boot = new BootAnimation();
+
+ IPCThreadState::self()->joinThreadPool();
+
+ }
return 0;
}
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 12bdead..d8db8b3 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -119,7 +119,8 @@
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
- OMXDecoder *encoder = OMXDecoder::CreateEncoder(&client, enc_meta);
+ OMXDecoder *encoder =
+ OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
encoder->setSource(decoder);
// encoder->setSource(meta, new DummySource(width, height));
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 961942a..7e23574 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -102,6 +102,7 @@
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
+ bool audioOnly = false;
if (argc > 1 && !strcmp(argv[1], "--list")) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -121,6 +122,10 @@
}
return 0;
+ } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
+ audioOnly = true;
+ ++argv;
+ --argc;
}
#if 0
@@ -149,7 +154,11 @@
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
- if (!strncasecmp(mime, "video/", 6)) {
+ if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+ break;
+ }
+
+ if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
break;
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index a3456c7..79bd6e7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -163,6 +163,10 @@
}
}
+ /**
+ * Implement to return the implementation of the internal accessibility
+ * service interface. Subclasses should not override.
+ */
@Override
public final IBinder onBind(Intent intent) {
return new IEventListenerWrapper(this);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ba6cc32..3aeac53 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1085,6 +1085,14 @@
reply.writeInt(result);
return true;
}
+ case KILL_APPLICATION_WITH_UID_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String pkg = data.readString();
+ int uid = data.readInt();
+ killApplicationWithUid(pkg, uid);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -2368,6 +2376,17 @@
data.recycle();
return result;
}
+ public void killApplicationWithUid(String pkg, int uid) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(pkg);
+ data.writeInt(uid);
+ mRemote.transact(KILL_APPLICATION_WITH_UID_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e21b1d9..32a2891 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3634,7 +3634,7 @@
Locale.setDefault(config.locale);
}
- Resources.updateSystemConfiguration(config, null);
+ Resources.updateSystemConfiguration(config, dm);
ApplicationContext.ApplicationPackageManager.configurationChanged();
//Log.i(TAG, "Configuration changed in " + currentPackageName());
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 95b376c..b1b5282 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -266,6 +266,8 @@
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded)
throws RemoteException;
+
+ public void killApplicationWithUid(String pkg, int uid) throws RemoteException;
/*
* Private non-Binder interfaces
@@ -421,4 +423,5 @@
int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
+ int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f9c38f9..f7479bc 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -273,11 +273,6 @@
return null;
}
- private class IntentSenderWrapper extends IntentSender {
- protected IntentSenderWrapper(IIntentSender target) {
- super(target);
- }
- }
/**
* Retrieve a IntentSender object that wraps the existing sender of the PendingIntent
*
@@ -285,7 +280,7 @@
*
*/
public IntentSender getIntentSender() {
- return new IntentSenderWrapper(mTarget);
+ return new IntentSender(mTarget);
}
/**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index dd70130..e991bc6 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -51,6 +51,7 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -244,7 +245,12 @@
}
return success;
}
-
+
+ private boolean isInRealAppSearch() {
+ return !mGlobalSearchMode
+ && (mPreviousComponents == null || mPreviousComponents.isEmpty());
+ }
+
/**
* Called in response to a press of the hard search button in
* {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app
@@ -535,7 +541,7 @@
// we dismiss the entire dialog instead
mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
- if (mGlobalSearchMode) {
+ if (!isInRealAppSearch()) {
mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in
} else {
mSearchAutoComplete.setDropDownAlwaysVisible(false);
@@ -662,7 +668,40 @@
}
mVoiceButton.setVisibility(visibility);
}
-
+
+ /*
+ * Menu.
+ */
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Show search settings menu item if anyone handles the intent for it
+ Intent settingsIntent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
+ settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ PackageManager pm = getContext().getPackageManager();
+ ActivityInfo activityInfo = settingsIntent.resolveActivityInfo(pm, 0);
+ if (activityInfo != null) {
+ settingsIntent.setClassName(activityInfo.applicationInfo.packageName,
+ activityInfo.name);
+ CharSequence label = activityInfo.loadLabel(getContext().getPackageManager());
+ menu.add(Menu.NONE, Menu.NONE, Menu.NONE, label)
+ .setIcon(android.R.drawable.ic_menu_preferences)
+ .setAlphabeticShortcut('P')
+ .setIntent(settingsIntent);
+ return true;
+ }
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onMenuOpened(int featureId, Menu menu) {
+ // The menu shows up above the IME, regardless of whether it is in front
+ // of the drop-down or not. This looks weird when there is no IME, so
+ // we make sure it is visible.
+ mSearchAutoComplete.ensureImeVisible();
+ return super.onMenuOpened(featureId, menu);
+ }
+
/**
* Listeners of various types
*/
@@ -1259,10 +1298,13 @@
launchGlobalSearchIntent(intent);
} else {
getContext().startActivity(intent);
- // in global search mode, SearchDialogWrapper#performActivityResuming
+ // If the search switches to a different activity,
+ // SearchDialogWrapper#performActivityResuming
// will handle hiding the dialog when the next activity starts, but for
- // in-app search, we still need to dismiss the dialog.
- dismiss();
+ // real in-app search, we still need to dismiss the dialog.
+ if (isInRealAppSearch()) {
+ dismiss();
+ }
}
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
@@ -1401,13 +1443,13 @@
return;
}
if (DBG) Log.d(LOG_TAG, "Switching to " + componentName);
-
- ComponentName previous = mLaunchComponent;
+
+ pushPreviousComponent(mLaunchComponent);
if (!show(componentName, mAppSearchData, false)) {
Log.w(LOG_TAG, "Failed to switch to source " + componentName);
+ popPreviousComponent();
return;
}
- pushPreviousComponent(previous);
String query = intent.getStringExtra(SearchManager.QUERY);
setUserQuery(query);
@@ -1701,6 +1743,12 @@
if (mSearchDialog.backToPreviousComponent()) {
return true;
}
+ // If the drop-down obscures the keyboard, the user wouldn't see anything
+ // happening when pressing back, so we dismiss the entire dialog instead.
+ if (isInputMethodNotNeeded()) {
+ mSearchDialog.cancel();
+ return true;
+ }
return false; // will dismiss soft keyboard if necessary
}
return false;
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index d6044145..5782644 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -16,8 +16,6 @@
package android.bluetooth;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -75,11 +73,11 @@
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
- /** No headset currently connected */
+ /** No Pce currently connected */
public static final int STATE_DISCONNECTED = 0;
/** Connection attempt in progress */
public static final int STATE_CONNECTING = 1;
- /** A headset is currently connected */
+ /** A Pce is currently connected */
public static final int STATE_CONNECTED = 2;
public static final int RESULT_FAILURE = 0;
@@ -87,11 +85,9 @@
/** Connection canceled before completion. */
public static final int RESULT_CANCELED = 2;
- public static final int PRIORITY_AUTO = 100;
- public static final int PRIORITY_OFF = 0;
/**
* An interface for notifying Bluetooth PCE IPC clients when they have
- * been connected to the BluetoothHeadset service.
+ * been connected to the BluetoothPbap service.
*/
public interface ServiceListener {
/**
@@ -113,7 +109,7 @@
}
/**
- * Create a BluetoothHeadset proxy object.
+ * Create a BluetoothPbap proxy object.
*/
public BluetoothPbap(Context context, ServiceListener l) {
mContext = context;
@@ -133,7 +129,7 @@
/**
* Close the connection to the backing service.
- * Other public functions of BluetoothHeadset will return default error
+ * Other public functions of BluetoothPbap will return default error
* results once close() has been called. Multiple invocations of close()
* are ok.
*/
@@ -145,9 +141,9 @@
}
/**
- * Get the current state of the Bluetooth Headset service.
+ * Get the current state of the BluetoothPbap service.
* @return One of the STATE_ return codes, or STATE_ERROR if this proxy
- * object is currently not connected to the Headset service.
+ * object is currently not connected to the Pbap service.
*/
public int getState() {
if (DBG) log("getState()");
@@ -159,13 +155,13 @@
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
}
- return BluetoothHeadset.STATE_ERROR;
+ return BluetoothPbap.STATE_ERROR;
}
/**
- * Get the Bluetooth address of the current headset.
+ * Get the Bluetooth address of the current Pce.
* @return The Bluetooth address, or null if not in connected or connecting
- * state, or if this proxy object is not connected to the Headset
+ * state, or if this proxy object is not connected to the Pbap
* service.
*/
public String getPceAddress() {
@@ -182,9 +178,9 @@
}
/**
- * Returns true if the specified headset is connected (does not include
+ * Returns true if the specified Pcs is connected (does not include
* connecting). Returns false if not connected, or if this proxy object
- * if not currently connected to the headset service.
+ * if not currently connected to the Pbap service.
*/
public boolean isConnected(String address) {
if (DBG) log("isConnected(" + address + ")");
@@ -200,9 +196,9 @@
}
/**
- * Disconnects the current headset. Currently this call blocks, it may soon
+ * Disconnects the current Pce. Currently this call blocks, it may soon
* be made asynchornous. Returns false if this proxy object is
- * not currently connected to the Headset service.
+ * not currently connected to the Pbap service.
*/
public boolean disconnectPce() {
if (DBG) log("disconnectPce()");
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 8b0b6ab..c0db01a 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -26,10 +26,14 @@
import java.util.HashMap;
public class ContentProviderOperation implements Parcelable {
- private final static int TYPE_INSERT = 1;
- private final static int TYPE_UPDATE = 2;
- private final static int TYPE_DELETE = 3;
- private final static int TYPE_COUNT = 4;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_INSERT = 1;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_UPDATE = 2;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_DELETE = 3;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_COUNT = 4;
private final int mType;
private final Uri mUri;
@@ -65,7 +69,7 @@
mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
mValuesBackReferences = source.readInt() != 0
-
+
? ContentValues.CREATOR.createFromParcel(source)
: null;
mSelectionArgsBackReferences = source.readInt() != 0
@@ -167,6 +171,11 @@
return mUri;
}
+ /** @hide exposed for unit tests */
+ public int getType() {
+ return mType;
+ }
+
public boolean isWriteOperation() {
return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
}
@@ -492,7 +501,7 @@
}
return this;
}
-
+
/**
* The selection and arguments to use. An occurrence of '?' in the selection will be
* replaced with the corresponding occurence of the selection argument. Any of the
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c6c9835..84449ef 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1293,7 +1293,8 @@
* Use with {@link #getSystemService} to retrieve an
* {@blink android.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
- *
+ * @hide
+ *
* @see #getSystemService
*/
public static final String BACKUP_SERVICE = "backup";
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 45a082a..15612ce 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -135,6 +135,7 @@
return mBase.getPackageCodePath();
}
+ /** @hide */
@Override
public File getSharedPrefsFile(String name) {
return mBase.getSharedPrefsFile(name);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 66b507d..64ee60e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2412,7 +2412,7 @@
/**
* Create an intent from a URI. This URI may encode the action,
* category, and other intent fields, if it was returned by
- * {@link #toUri}.. If the Intent was not generate by toUri(), its data
+ * {@link #toUri}. If the Intent was not generate by toUri(), its data
* will be the entire URI and its action will be ACTION_VIEW.
*
* <p>The URI given here must not be relative -- that is, it must include
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 4da49d9..0e4d984 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -52,6 +52,9 @@
* categories, and components, and same flags), it will receive a IntentSender
* representing the same token if that is still valid.
*
+ * <p>Instances of this class can not be made directly, but rather must be
+ * created from an existing {@link android.app.PendingIntent} with
+ * {@link android.app.PendingIntent#getIntentSender() PendingIntent.getIntentSender()}.
*/
public class IntentSender implements Parcelable {
private final IIntentSender mTarget;
@@ -245,11 +248,13 @@
return b != null ? new IntentSender(b) : null;
}
- protected IntentSender(IIntentSender target) {
+ /** @hide */
+ public IntentSender(IIntentSender target) {
mTarget = target;
}
- protected IntentSender(IBinder target) {
+ /** @hide */
+ public IntentSender(IBinder target) {
mTarget = IIntentSender.Stub.asInterface(target);
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9ca11cd..0a42a6f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -131,8 +131,9 @@
public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
/**
- * Value for {@link #flags}: this is set of the application has set
- * its android:targetSdkVersion to something >= the current SDK version.
+ * Value for {@link #flags}: this is set of the application has specified
+ * {@link android.R.styleable#AndroidManifestApplication_testOnly
+ * android:testOnly} to be true.
*/
public static final int FLAG_TEST_ONLY = 1<<8;
diff --git a/core/java/android/gesture/GestureLibrary.java b/core/java/android/gesture/GestureLibrary.java
index a29c2c8..ec2e78c 100644
--- a/core/java/android/gesture/GestureLibrary.java
+++ b/core/java/android/gesture/GestureLibrary.java
@@ -35,6 +35,7 @@
return false;
}
+ /** @hide */
public Learner getLearner() {
return mStore.getLearner();
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 5486920..188e7ff 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
void setPokeLock(int pokey, IBinder lock, String tag);
+ int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
long getScreenOnTime();
void preventScreenOn(boolean prevent);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index bfcf2fc..d5934102 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -114,12 +114,14 @@
private static final int WAKE_BIT_SCREEN_DIM = 4;
private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
+ private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
| WAKE_BIT_CPU_WEAK
| WAKE_BIT_SCREEN_DIM
| WAKE_BIT_SCREEN_BRIGHT
- | WAKE_BIT_KEYBOARD_BRIGHT;
+ | WAKE_BIT_KEYBOARD_BRIGHT
+ | WAKE_BIT_PROXIMITY_SCREEN_OFF;
/**
* Wake lock that ensures that the CPU is running. The screen might
@@ -147,6 +149,16 @@
public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
/**
+ * Wake lock that turns the screen off when the proximity sensor activates.
+ * Since not all devices have proximity sensors, use
+ * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
+ * this wake lock mode is supported.
+ *
+ * {@hide}
+ */
+ public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
+
+ /**
* Normally wake locks don't actually wake the device, they just cause
* it to remain on once it's already on. Think of the video player
* app as the normal behavior. Notifications that pop up and want
@@ -196,6 +208,7 @@
case SCREEN_DIM_WAKE_LOCK:
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
+ case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException();
@@ -365,7 +378,33 @@
} catch (RemoteException e) {
}
}
-
+
+ /**
+ * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
+ * that are supported on the device.
+ * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
+ * is supported:
+ *
+ * {@samplecode
+ * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ * int supportedFlags = pm.getSupportedWakeLockFlags();
+ * boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
+ * == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
+ * }
+ *
+ * @return the set of supported WakeLock flags.
+ *
+ * {@hide}
+ */
+ public int getSupportedWakeLockFlags()
+ {
+ try {
+ return mService.getSupportedWakeLockFlags();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
private PowerManager()
{
}
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index abdcd93..db25cfa 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -28,6 +28,7 @@
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -36,7 +37,7 @@
* @hide
*/
public class VolumePreference extends SeekBarPreference implements
- PreferenceManager.OnActivityStopListener {
+ PreferenceManager.OnActivityStopListener, View.OnKeyListener {
private static final String TAG = "VolumePreference";
@@ -66,6 +67,30 @@
mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
getPreferenceManager().registerOnActivityStopListener(this);
+
+ // grab focus and key events so that pressing the volume buttons in the
+ // dialog doesn't also show the normal volume adjust toast.
+ view.setOnKeyListener(this);
+ view.setFocusableInTouchMode(true);
+ view.requestFocus();
+ }
+
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ if (isdown) {
+ mSeekBarVolumizer.changeVolumeBy(-1);
+ }
+ return true;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ if (isdown) {
+ mSeekBarVolumizer.changeVolumeBy(1);
+ }
+ return true;
+ default:
+ return false;
+ }
}
@Override
@@ -158,7 +183,9 @@
}
mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
- mRingtone.setStreamType(mStreamType);
+ if (mRingtone != null) {
+ mRingtone.setStreamType(mStreamType);
+ }
}
public void stop() {
@@ -215,5 +242,12 @@
return mSeekBar;
}
+ public void changeVolumeBy(int amount) {
+ mSeekBar.incrementProgressBy(amount);
+ if (mRingtone != null && !mRingtone.isPlaying()) {
+ sample();
+ }
+ postSetVolume(mSeekBar.getProgress());
+ }
}
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index fce8630..01189fe 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -113,7 +113,7 @@
public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
}
- private interface AggregatesColumns {
+ private interface ContactsColumns {
/**
* The display name for the contact.
* <P>Type: TEXT</P>
@@ -140,7 +140,7 @@
/**
* Lookup value that reflects the {@link Groups#GROUP_VISIBLE} state of
- * any {@link GroupMembership} for this aggregate.
+ * any {@link GroupMembership} for this contact.
*/
public static final String IN_VISIBLE_GROUP = "in_visible_group";
@@ -171,32 +171,33 @@
/**
- * Constants for the aggregates table, which contains a record per group
- * of contact representing the same person.
+ * Constants for the contacts table, which contains a record per group
+ * of raw contact representing the same person.
*/
- public static final class Aggregates implements BaseColumns, AggregatesColumns,
+ // TODO make final once renaming is complete
+ public static /*final*/ class Contacts implements BaseColumns, ContactsColumns,
ContactOptionsColumns {
/**
* This utility class cannot be instantiated
*/
- private Aggregates() {}
+ private Contacts() {}
/**
* The content:// style URI for this table
*/
- public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "aggregates");
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
/**
* The content:// style URI for this table joined with useful data from
* {@link Data}.
*/
public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
- "aggregates_summary");
+ "contacts_summary");
/**
* The content:// style URI used for "type-to-filter" functionality on the
* {@link #CONTENT_SUMMARY_URI} URI. The filter string will be used to match
- * various parts of the aggregate name. The filter argument should be passed
+ * various parts of the contact name. The filter argument should be passed
* as an additional path segment after this URI.
*/
public static final Uri CONTENT_SUMMARY_FILTER_URI = Uri.withAppendedPath(
@@ -204,8 +205,8 @@
/**
* The content:// style URI for this table joined with useful data from
- * {@link Data}, filtered to include only starred aggregates
- * and the most frequently contacted aggregates.
+ * {@link Data}, filtered to include only starred contacts
+ * and the most frequently contacted contacts.
*/
public static final Uri CONTENT_SUMMARY_STREQUENT_URI = Uri.withAppendedPath(
CONTENT_SUMMARY_URI, "strequent");
@@ -213,7 +214,7 @@
/**
* The content:// style URI used for "type-to-filter" functionality on the
* {@link #CONTENT_SUMMARY_STREQUENT_URI} URI. The filter string will be used to match
- * various parts of the aggregate name. The filter argument should be passed
+ * various parts of the contact name. The filter argument should be passed
* as an additional path segment after this URI.
*/
public static final Uri CONTENT_SUMMARY_STREQUENT_FILTER_URI = Uri.withAppendedPath(
@@ -225,16 +226,16 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person_aggregate";
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* person.
*/
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person_aggregate";
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
/**
- * A sub-directory of a single contact aggregate that contains all of their
+ * A sub-directory of a single contact that contains all of the constituent raw contact
* {@link Data} rows.
*/
public static final class Data implements BaseColumns, DataColumns {
@@ -251,10 +252,10 @@
/**
* A sub-directory of a single contact aggregate that contains all aggregation suggestions
- * (other aggregates). The aggregation suggestions are computed based on approximate
- * data matches with this aggregate.
+ * (other contacts). The aggregation suggestions are computed based on approximate
+ * data matches with this contact.
*/
- public static final class AggregationSuggestions implements BaseColumns, AggregatesColumns {
+ public static final class AggregationSuggestions implements BaseColumns, ContactsColumns {
/**
* No public constructor since this is a utility class
*/
@@ -275,6 +276,9 @@
}
}
+ @Deprecated
+ public static final class Aggregates extends Contacts {}
+
/**
* Columns that appear when each row of a table belongs to a specific
* account, including sync information that an account may need.
@@ -317,10 +321,11 @@
private interface RawContactsColumns {
/**
- * A reference to the {@link Aggregates#_ID} that this data belongs to.
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} that this
+ * data belongs to.
* <P>Type: INTEGER</P>
*/
- public static final String AGGREGATE_ID = "aggregate_id";
+ public static final String CONTACT_ID = "contact_id";
/**
* Flag indicating that this {@link RawContacts} entry and its children has
@@ -340,11 +345,10 @@
/**
* The "deleted" flag: "0" by default, "1" if the row has been marked
* for deletion. When {@link android.content.ContentResolver#delete} is
- * called on a contact, it is marked for deletion and removed from its
- * aggregate. The sync adaptor deletes the contact on the server and
+ * called on a raw contact, it is marked for deletion and removed from its
+ * aggregate contact. The sync adaptor deletes the raw contact on the server and
* then calls ContactResolver.delete once more, this time passing the
- * {@link android.provider.ContactsContract.Contacts#DELETE_PERMANENTLY}
- * query parameter to finalize the data removal.
+ * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
* <P>Type: INTEGER</P>
*/
public static final String DELETED = "deleted";
@@ -355,8 +359,7 @@
* information per sync source. Sync adapters and contact management apps
* are the primary consumers of this API.
*/
- // TODO make final as soon as renaming is complete
- public static /*final*/ class RawContacts implements BaseColumns, RawContactsColumns,
+ public static final class RawContacts implements BaseColumns, RawContactsColumns,
SyncColumns, ContactOptionsColumns {
/**
* This utility class cannot be instantiated
@@ -367,7 +370,7 @@
/**
* The content:// style URI for this table
*/
- public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
/**
* The content:// style URL for filtering people by email address. The
@@ -383,13 +386,13 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* person.
*/
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
/**
* Query parameter that can be passed with the {@link #CONTENT_URI} URI
@@ -405,19 +408,19 @@
public static final int AGGREGATION_MODE_DEFAULT = 0;
/**
- * Aggregation mode: aggregate at the time the contact is inserted/updated.
+ * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
*/
public static final int AGGREGATION_MODE_IMMEDITATE = 1;
/**
- * Aggregation mode: never aggregate this contact (note that the contact will not
+ * Aggregation mode: never aggregate this raw contact (note that the raw contact will not
* have a corresponding Aggregate and therefore will not be included in Aggregates
* query results.)
*/
public static final int AGGREGATION_MODE_DISABLED = 2;
/**
- * A sub-directory of a single contact that contains all of their {@link Data} rows.
+ * A sub-directory of a single raw contact that contains all of their {@link Data} rows.
* To access this directory append
*/
public static final class Data implements BaseColumns, DataColumns {
@@ -434,13 +437,6 @@
}
}
- /**
- * TODO remove as soon as full renaming is complete.
- */
- @Deprecated
- public static final class Contacts extends RawContacts {
- }
-
private interface DataColumns {
/**
* The package name to use when creating {@link Resources} objects for
@@ -455,20 +451,21 @@
public static final String MIMETYPE = "mimetype";
/**
- * A reference to the {@link android.provider.ContactsContract.Contacts#_ID}
+ * A reference to the {@link RawContacts#_ID}
* that this data belongs to.
*/
- public static final String CONTACT_ID = "contact_id";
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
/**
- * Whether this is the primary entry of its kind for the contact it belongs to
+ * Whether this is the primary entry of its kind for the raw contact it belongs to
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
public static final String IS_PRIMARY = "is_primary";
/**
- * Whether this is the primary entry of its kind for the aggregate it belongs to. Any data
- * record that is "super primary" must also be "primary".
+ * Whether this is the primary entry of its kind for the aggregate
+ * contact it belongs to. Any data record that is "super primary" must
+ * also be "primary".
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
public static final String IS_SUPER_PRIMARY = "is_super_primary";
@@ -514,7 +511,7 @@
}
/**
- * Constants for the data table, which contains data points tied to a contact.
+ * Constants for the data table, which contains data points tied to a raw contact.
* For example, a phone number or email address. Each row in this table contains a type
* definition and some generic columns. Each data type can define the meaning for each of
* the generic columns.
@@ -539,10 +536,10 @@
/**
* A table that represents the result of looking up a phone number, for
* example for caller ID. The table joins that data row for the phone number
- * with the contact that owns the number. To perform a lookup you must
+ * with the raw contact that owns the number. To perform a lookup you must
* append the number you want to find to {@link #CONTENT_FILTER_URI}.
*/
- public static final class PhoneLookup implements BaseColumns, DataColumns, AggregatesColumns {
+ public static final class PhoneLookup implements BaseColumns, DataColumns, ContactsColumns {
/**
* This utility class cannot be instantiated
*/
@@ -562,7 +559,7 @@
/**
* Additional data mixed in with {@link Im.CommonPresenceColumns} to link
- * back to specific {@link ContactsContract.Aggregates#_ID} entries.
+ * back to specific {@link ContactsContract.Contacts#_ID} entries.
*/
private interface PresenceColumns {
@@ -573,11 +570,10 @@
public static final String _ID = "presence_id";
/**
- * Reference to the {@link android.provider.ContactsContract.Contacts#_ID} this presence
- * references.
+ * Reference to the {@link RawContacts#_ID} this presence references.
* <P>Type: INTEGER</P>
*/
- public static final String CONTACT_ID = "contact_id";
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
/**
* Reference to the {@link Data#_ID} entry that owns this presence.
@@ -694,9 +690,12 @@
public static final String MIMETYPE = "mimetype";
/**
- * The {@link Contacts#_ID} that this data belongs to.
+ * The {@link RawContacts#_ID} that this data belongs to.
*/
- public static final String CONTACT_ID = "contact_id";
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+
+ @Deprecated
+ public static final String CONTACT_ID = RAW_CONTACT_ID;
}
/**
@@ -835,7 +834,7 @@
/**
* The content:// style URI for all data records of the
* {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the
- * associated contact and aggregate data.
+ * associated raw contact and aggregate contact data.
*/
public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
"phones");
@@ -843,7 +842,7 @@
/**
* The content:// style URI for filtering data records of the
* {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the
- * associated contact and aggregate data. The filter argument should
+ * associated raw contact and aggregate contact data. The filter argument should
* be passed as an additional path segment after this URI.
*/
public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
@@ -1090,7 +1089,7 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
/**
- * Thumbnail photo of the contact. This is the raw bytes of an image
+ * Thumbnail photo of the raw contact. This is the raw bytes of an image
* that could be inflated using {@link BitmapFactory}.
* <p>
* Type: BLOB
@@ -1193,7 +1192,7 @@
public static final String SYSTEM_ID = "system_id";
/**
- * The total number of {@link Aggregates} that have
+ * The total number of {@link Contacts} that have
* {@link GroupMembership} in this group. Read-only value that is only
* present when querying {@link Groups#CONTENT_SUMMARY_URI}.
* <p>
@@ -1202,7 +1201,7 @@
public static final String SUMMARY_COUNT = "summ_count";
/**
- * The total number of {@link Aggregates} that have both
+ * The total number of {@link Contacts} that have both
* {@link GroupMembership} in this group, and also have phone numbers.
* Read-only value that is only present when querying
* {@link Groups#CONTENT_SUMMARY_URI}.
@@ -1290,31 +1289,33 @@
public static final String TYPE = "type";
/**
- * Allows the provider to automatically decide whether the aggregate should include
- * a particular contact or not.
+ * Allows the provider to automatically decide whether the aggregate
+ * contact should include a particular raw contact or not.
*/
public static final int TYPE_AUTOMATIC = 0;
/**
- * Makes sure that the specified contact is included in the specified aggregate.
+ * Makes sure that the specified raw contact is included in the
+ * specified aggregate contact.
*/
public static final int TYPE_KEEP_IN = 1;
/**
- * Makes sure that the specified contact is NOT included in the specified aggregate.
+ * Makes sure that the specified raw contact is NOT included in the
+ * specified aggregate contact.
*/
public static final int TYPE_KEEP_OUT = 2;
/**
- * A reference to the {@link Aggregates#_ID} of the aggregate that the rule applies to.
- */
- public static final String AGGREGATE_ID = "aggregate_id";
-
- /**
* A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the
- * contact that the rule applies to.
+ * aggregate contact that the rule applies to.
*/
public static final String CONTACT_ID = "contact_id";
+
+ /**
+ * A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
}
/**
diff --git a/core/java/android/provider/SocialContract.java b/core/java/android/provider/SocialContract.java
index a3b1d6e..d542774 100644
--- a/core/java/android/provider/SocialContract.java
+++ b/core/java/android/provider/SocialContract.java
@@ -19,7 +19,7 @@
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.net.Uri;
-import android.provider.ContactsContract.Aggregates;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
/**
@@ -165,7 +165,7 @@
/**
* The {@link Uri} for the latest social activity performed by any
- * contact aggregated under the specified {@link Aggregates#_ID}. Will
+ * contact aggregated under the specified {@link Contacts#_ID}. Will
* also join with most-present {@link Presence} for this aggregate.
*/
public static final Uri CONTENT_AGGREGATE_STATUS_URI =
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 0f0be79..81dd96e 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -124,10 +124,6 @@
"A List must have fewer than "
+ Byte.MAX_VALUE + " items in it.");
}
- if (items.length < 1) {
- throw new IllegalArgumentException(
- "A List must have at least one item in it.");
- }
for (int i = 0; i < items.length; i++) {
final Object item = items[i];
if (item == null) {
@@ -223,7 +219,7 @@
case LIST:
if (mBuffer.remaining() < 1) return null;
int length = mBuffer.get();
- if (length <= 0) return null;
+ if (length < 0) return null;
Object[] array = new Object[length];
for (int i = 0; i < length; ++i) {
array[i] = decodeObject();
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 9178131..c4bf642 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -107,8 +107,14 @@
public static final int SURFACE_HIDDEN = 0x01;
/** Freeze the surface. Equivalent to calling freeze() */
+ public static final int SURFACE_FROZEN = 0x02;
+
+ /**
+ * @deprecated use {@link #SURFACE_FROZEN} instead.
+ */
+ @Deprecated
public static final int SURACE_FROZEN = 0x02;
-
+
/** Enable dithering when compositing this surface */
public static final int SURFACE_DITHER = 0x04;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 46aea02..4baf612 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -16,6 +16,7 @@
package android.view;
+import android.util.Config;
import android.util.Log;
import android.util.DisplayMetrics;
import android.content.res.Resources;
@@ -140,7 +141,9 @@
public static boolean consistencyCheckEnabled = false;
static {
- Debug.setFieldsOn(ViewDebug.class, true);
+ if (Config.DEBUG) {
+ Debug.setFieldsOn(ViewDebug.class, true);
+ }
}
/**
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index a573983..e21824e 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -23,7 +23,9 @@
import android.media.AudioManager;
import android.media.AudioService;
import android.media.AudioSystem;
+import android.media.RingtoneManager;
import android.media.ToneGenerator;
+import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
@@ -44,7 +46,7 @@
public class VolumePanel extends Handler
{
private static final String TAG = "VolumePanel";
- private static boolean LOGD = false || Config.LOGD;
+ private static boolean LOGD = false;
/**
* The delay before playing a sound. This small period exists so the user
@@ -86,6 +88,7 @@
protected Context mContext;
private AudioManager mAudioManager;
protected AudioService mAudioService;
+ private boolean mRingIsSilent;
private final Toast mToast;
private final View mView;
@@ -138,7 +141,7 @@
onShowVolumeChanged(streamType, flags);
}
- if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
+ if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
removeMessages(MSG_PLAY_SOUND);
sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
}
@@ -157,6 +160,7 @@
int index = mAudioService.getStreamVolume(streamType);
int message = UNKNOWN_VOLUME_TEXT;
int additionalMessage = 0;
+ mRingIsSilent = false;
if (LOGD) {
Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
@@ -169,8 +173,15 @@
switch (streamType) {
case AudioManager.STREAM_RING: {
+ setRingerIcon();
message = RINGTONE_VOLUME_TEXT;
- setRingerIcon(index);
+ Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
+ mContext, RingtoneManager.TYPE_RINGTONE);
+ if (ringuri == null) {
+ additionalMessage =
+ com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
+ mRingIsSilent = true;
+ }
break;
}
@@ -208,6 +219,13 @@
case AudioManager.STREAM_NOTIFICATION: {
message = NOTIFICATION_VOLUME_TEXT;
setSmallIcon(index);
+ Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
+ mContext, RingtoneManager.TYPE_NOTIFICATION);
+ if (ringuri == null) {
+ additionalMessage =
+ com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
+ mRingIsSilent = true;
+ }
break;
}
@@ -254,7 +272,6 @@
mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
}
-
}
protected void onPlaySound(int streamType, int flags) {
@@ -337,17 +354,15 @@
/**
* Makes the ringer icon visible with an icon that is chosen
* based on the current ringer mode.
- *
- * @param index
*/
- private void setRingerIcon(int index) {
+ private void setRingerIcon() {
mSmallStreamIcon.setVisibility(View.GONE);
mLargeStreamIcon.setVisibility(View.VISIBLE);
int ringerMode = mAudioService.getRingerMode();
int icon;
- if (LOGD) Log.d(TAG, "setRingerIcon(index: " + index+ "), ringerMode: " + ringerMode);
+ if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode);
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
icon = com.android.internal.R.drawable.ic_volume_off;
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 3b67fb6..ed77ce8 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -72,38 +72,41 @@
private final Context mContext;
// Message Ids
- private static final int PAGE_STARTED = 100;
- private static final int RECEIVED_ICON = 101;
- private static final int RECEIVED_TITLE = 102;
- private static final int OVERRIDE_URL = 103;
- private static final int AUTH_REQUEST = 104;
- private static final int SSL_ERROR = 105;
- private static final int PROGRESS = 106;
- private static final int UPDATE_VISITED = 107;
- private static final int LOAD_RESOURCE = 108;
- private static final int CREATE_WINDOW = 109;
- private static final int CLOSE_WINDOW = 110;
- private static final int SAVE_PASSWORD = 111;
- private static final int JS_ALERT = 112;
- private static final int JS_CONFIRM = 113;
- private static final int JS_PROMPT = 114;
- private static final int JS_UNLOAD = 115;
- private static final int ASYNC_KEYEVENTS = 116;
- private static final int TOO_MANY_REDIRECTS = 117;
- private static final int DOWNLOAD_FILE = 118;
- private static final int REPORT_ERROR = 119;
- private static final int RESEND_POST_DATA = 120;
- private static final int PAGE_FINISHED = 121;
- private static final int REQUEST_FOCUS = 122;
- private static final int SCALE_CHANGED = 123;
- private static final int RECEIVED_CERTIFICATE = 124;
- private static final int SWITCH_OUT_HISTORY = 125;
- private static final int EXCEEDED_DATABASE_QUOTA = 126;
- private static final int JS_TIMEOUT = 127;
- private static final int ADD_MESSAGE_TO_CONSOLE = 128;
+ private static final int PAGE_STARTED = 100;
+ private static final int RECEIVED_ICON = 101;
+ private static final int RECEIVED_TITLE = 102;
+ private static final int OVERRIDE_URL = 103;
+ private static final int AUTH_REQUEST = 104;
+ private static final int SSL_ERROR = 105;
+ private static final int PROGRESS = 106;
+ private static final int UPDATE_VISITED = 107;
+ private static final int LOAD_RESOURCE = 108;
+ private static final int CREATE_WINDOW = 109;
+ private static final int CLOSE_WINDOW = 110;
+ private static final int SAVE_PASSWORD = 111;
+ private static final int JS_ALERT = 112;
+ private static final int JS_CONFIRM = 113;
+ private static final int JS_PROMPT = 114;
+ private static final int JS_UNLOAD = 115;
+ private static final int ASYNC_KEYEVENTS = 116;
+ private static final int TOO_MANY_REDIRECTS = 117;
+ private static final int DOWNLOAD_FILE = 118;
+ private static final int REPORT_ERROR = 119;
+ private static final int RESEND_POST_DATA = 120;
+ private static final int PAGE_FINISHED = 121;
+ private static final int REQUEST_FOCUS = 122;
+ private static final int SCALE_CHANGED = 123;
+ private static final int RECEIVED_CERTIFICATE = 124;
+ private static final int SWITCH_OUT_HISTORY = 125;
+ private static final int EXCEEDED_DATABASE_QUOTA = 126;
+ private static final int REACHED_APPCACHE_MAXSIZE = 127;
+ private static final int JS_TIMEOUT = 128;
+ private static final int ADD_MESSAGE_TO_CONSOLE = 129;
+ private static final int GEOLOCATION_PERMISSIONS_SHOW_PROMPT = 130;
+ private static final int GEOLOCATION_PERMISSIONS_HIDE_PROMPT = 131;
// Message triggered by the client to resume execution
- private static final int NOTIFY = 200;
+ private static final int NOTIFY = 200;
// Result transportation object for returning results across thread
// boundaries.
@@ -410,11 +413,49 @@
String url = (String) map.get("url");
long currentQuota =
((Long) map.get("currentQuota")).longValue();
+ long totalUsedQuota =
+ ((Long) map.get("totalUsedQuota")).longValue();
WebStorage.QuotaUpdater quotaUpdater =
(WebStorage.QuotaUpdater) map.get("quotaUpdater");
mWebChromeClient.onExceededDatabaseQuota(url,
- databaseIdentifier, currentQuota, quotaUpdater);
+ databaseIdentifier, currentQuota, totalUsedQuota,
+ quotaUpdater);
+ }
+ break;
+
+ case REACHED_APPCACHE_MAXSIZE:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ long spaceNeeded =
+ ((Long) map.get("spaceNeeded")).longValue();
+ long totalUsedQuota =
+ ((Long) map.get("totalUsedQuota")).longValue();
+ WebStorage.QuotaUpdater quotaUpdater =
+ (WebStorage.QuotaUpdater) map.get("quotaUpdater");
+
+ mWebChromeClient.onReachedMaxAppCacheSize(spaceNeeded,
+ totalUsedQuota, quotaUpdater);
+ }
+ break;
+
+ case GEOLOCATION_PERMISSIONS_SHOW_PROMPT:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String origin = (String) map.get("origin");
+ GeolocationPermissions.Callback callback =
+ (GeolocationPermissions.Callback)
+ map.get("callback");
+ mWebChromeClient.onGeolocationPermissionsShowPrompt(origin,
+ callback);
+ }
+ break;
+
+ case GEOLOCATION_PERMISSIONS_HIDE_PROMPT:
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onGeolocationPermissionsHidePrompt();
}
break;
@@ -1120,13 +1161,14 @@
* @param databaseIdentifier The identifier of the database that the
* transaction that caused the overflow was running on.
* @param currentQuota The current quota the origin is allowed.
+ * @param totalUsedQuota is the sum of all origins' quota.
* @param quotaUpdater An instance of a class encapsulating a callback
* to WebViewCore to run when the decision to allow or deny more
* quota has been made.
*/
public void onExceededDatabaseQuota(
String url, String databaseIdentifier, long currentQuota,
- WebStorage.QuotaUpdater quotaUpdater) {
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
if (mWebChromeClient == null) {
quotaUpdater.updateQuota(currentQuota);
return;
@@ -1137,12 +1179,78 @@
map.put("databaseIdentifier", databaseIdentifier);
map.put("url", url);
map.put("currentQuota", currentQuota);
+ map.put("totalUsedQuota", totalUsedQuota);
map.put("quotaUpdater", quotaUpdater);
exceededQuota.obj = map;
sendMessage(exceededQuota);
}
/**
+ * Called by WebViewCore to inform the Java side that the appcache has
+ * exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater An instance of a class encapsulating a callback
+ * to WebViewCore to run when the decision to allow or deny a bigger
+ * app cache size has been made.
+ * @hide pending API council approval.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded,
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ if (mWebChromeClient == null) {
+ quotaUpdater.updateQuota(0);
+ return;
+ }
+
+ Message msg = obtainMessage(REACHED_APPCACHE_MAXSIZE);
+ HashMap<String, Object> map = new HashMap();
+ map.put("spaceNeeded", spaceNeeded);
+ map.put("totalUsedQuota", totalUsedQuota);
+ map.put("quotaUpdater", quotaUpdater);
+ msg.obj = map;
+ sendMessage(msg);
+ }
+
+ /**
+ * Called by WebViewCore to instruct the browser to display a prompt to ask
+ * the user to set the Geolocation permission state for the given origin.
+ * @param origin The origin requesting Geolocation permsissions.
+ * @param callback The callback to call once a permission state has been
+ * obtained.
+ * @hide pending API council review.
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message showMessage =
+ obtainMessage(GEOLOCATION_PERMISSIONS_SHOW_PROMPT);
+ HashMap<String, Object> map = new HashMap();
+ map.put("origin", origin);
+ map.put("callback", callback);
+ showMessage.obj = map;
+ sendMessage(showMessage);
+ }
+
+ /**
+ * Called by WebViewCore to instruct the browser to hide the Geolocation
+ * permissions prompt.
+ * origin.
+ * @hide pending API council review.
+ */
+ public void onGeolocationPermissionsHidePrompt() {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message hideMessage = obtainMessage(GEOLOCATION_PERMISSIONS_HIDE_PROMPT);
+ sendMessage(hideMessage);
+ }
+
+ /**
* Called by WebViewCore when we have a message to be added to the JavaScript
* error console. Sends a message to the Java side with the details.
* @param message The message to add to the console.
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
new file mode 100755
index 0000000..d06d7e2
--- /dev/null
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.Set;
+
+
+/**
+ * Implements the Java side of GeolocationPermissions. Simply marshalls calls
+ * from the UI thread to the WebKit thread.
+ * @hide
+ */
+public final class GeolocationPermissions {
+ /**
+ * Callback interface used by the browser to report a Geolocation permission
+ * state set by the user in response to a permissions prompt.
+ */
+ public interface Callback {
+ public void invoke(String origin, boolean allow, boolean remember);
+ };
+
+ // Log tag
+ private static final String TAG = "geolocationPermissions";
+
+ // Global instance
+ private static GeolocationPermissions sInstance;
+
+ private Handler mHandler;
+
+ // Members used to transfer the origins and permissions between threads.
+ private Set<String> mOrigins;
+ private boolean mAllowed;
+ private static Lock mLock = new ReentrantLock();
+ private static boolean mUpdated;
+ private static Condition mUpdatedCondition = mLock.newCondition();
+
+ // Message ids
+ static final int GET_ORIGINS = 0;
+ static final int GET_ALLOWED = 1;
+ static final int CLEAR = 2;
+ static final int CLEAR_ALL = 3;
+
+ /**
+ * Gets the singleton instance of the class.
+ */
+ public static GeolocationPermissions getInstance() {
+ if (sInstance == null) {
+ sInstance = new GeolocationPermissions();
+ }
+ return sInstance;
+ }
+
+ /**
+ * Creates the message handler. Must be called on the WebKit thread.
+ */
+ public void createHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // Runs on the WebKit thread.
+ switch (msg.what) {
+ case GET_ORIGINS:
+ getOriginsImpl();
+ break;
+ case GET_ALLOWED:
+ getAllowedImpl((String) msg.obj);
+ break;
+ case CLEAR:
+ nativeClear((String) msg.obj);
+ break;
+ case CLEAR_ALL:
+ nativeClearAll();
+ break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * Utility function to send a message to our handler.
+ */
+ private void postMessage(Message msg) {
+ assert(mHandler != null);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Gets the set of origins for which Geolocation permissions are stored.
+ * Note that we represent the origins as strings. These are created using
+ * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
+ * (Database, Geolocation etc) do so, it's safe to match up origins for the
+ * purposes of displaying UI.
+ */
+ public Set getOrigins() {
+ // Called on the UI thread.
+ Set origins = null;
+ mLock.lock();
+ try {
+ mUpdated = false;
+ postMessage(Message.obtain(null, GET_ORIGINS));
+ while (!mUpdated) {
+ mUpdatedCondition.await();
+ }
+ origins = mOrigins;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting for update", e);
+ } finally {
+ mLock.unlock();
+ }
+ return origins;
+ }
+
+ /**
+ * Helper method to get the set of origins.
+ */
+ private void getOriginsImpl() {
+ // Called on the WebKit thread.
+ mLock.lock();
+ mOrigins = nativeGetOrigins();
+ mUpdated = true;
+ mUpdatedCondition.signal();
+ mLock.unlock();
+ }
+
+ /**
+ * Gets the permission state for the specified origin.
+ */
+ public boolean getAllowed(String origin) {
+ // Called on the UI thread.
+ boolean allowed = false;
+ mLock.lock();
+ try {
+ mUpdated = false;
+ postMessage(Message.obtain(null, GET_ALLOWED, origin));
+ while (!mUpdated) {
+ mUpdatedCondition.await();
+ }
+ allowed = mAllowed;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting for update", e);
+ } finally {
+ mLock.unlock();
+ }
+ return allowed;
+ }
+
+ /**
+ * Helper method to get the permission state.
+ */
+ private void getAllowedImpl(String origin) {
+ // Called on the WebKit thread.
+ mLock.lock();
+ mAllowed = nativeGetAllowed(origin);
+ mUpdated = true;
+ mUpdatedCondition.signal();
+ mLock.unlock();
+ }
+
+ /**
+ * Clears the permission state for the specified origin.
+ */
+ public void clear(String origin) {
+ // Called on the UI thread.
+ postMessage(Message.obtain(null, CLEAR, origin));
+ }
+
+ /**
+ * Clears the permission state for all origins.
+ */
+ public void clearAll() {
+ // Called on the UI thread.
+ postMessage(Message.obtain(null, CLEAR_ALL));
+ }
+
+ // Native functions, run on the WebKit thread.
+ private static native Set nativeGetOrigins();
+ private static native boolean nativeGetAllowed(String origin);
+ private static native void nativeClear(String origin);
+ private static native void nativeClearAll();
+}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index dd43b8b..d52406d 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -198,17 +198,48 @@
* @param databaseIdentifier The identifier of the database that caused the
* quota overflow.
* @param currentQuota The current quota for the origin.
+ * @param totalUsedQuota is the sum of all origins' quota.
* @param quotaUpdater A callback to inform the WebCore thread that a new
* quota is available. This callback must always be executed at some
* point to ensure that the sleeping WebCore thread is woken up.
*/
public void onExceededDatabaseQuota(String url, String databaseIdentifier,
- long currentQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ long currentQuota, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
// This default implementation passes the current quota back to WebCore.
// WebCore will interpret this that new quota was declined.
quotaUpdater.updateQuota(currentQuota);
}
+ /**
+ * Tell the client that the Application Cache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater A callback to inform the WebCore thread that a new
+ * app cache size is available. This callback must always be executed at
+ * some point to ensure that the sleeping WebCore thread is woken up.
+ * @hide pending API council approval.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ quotaUpdater.updateQuota(0);
+ }
+
+ /**
+ * Instructs the client to show a prompt to ask the user to set the
+ * Geolocation permission state for the specified origin.
+ * @hide pending API council approval.
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {}
+
+ /**
+ * Instructs the client to hide the Geolocation permissions prompt.
+ * @hide pending API council approval.
+ */
+ public void onGeolocationPermissionsHidePrompt() {}
+
/**
* Tell the client that a JavaScript execution timeout has occured. And the
* client may decide whether or not to interrupt the execution. If the
@@ -232,6 +263,5 @@
* @param sourceID The name of the source file that caused the error.
* @hide pending API council.
*/
- public void addMessageToConsole(String message, int lineNumber, String sourceID) {
- }
+ public void addMessageToConsole(String message, int lineNumber, String sourceID) {}
}
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 1a60dba..c3b359e 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -55,7 +55,8 @@
// that we protect via a lock and update in syncValues().
// This is needed to transfer this data across threads.
private static Lock mLock = new ReentrantLock();
- private static Condition mCacheUpdated = mLock.newCondition();
+ private static Condition mUpdateCondition = mLock.newCondition();
+ private static boolean mUpdateAvailable;
// Message ids
static final int UPDATE = 0;
@@ -133,8 +134,11 @@
Set ret = null;
mLock.lock();
try {
+ mUpdateAvailable = false;
update();
- mCacheUpdated.await();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.await();
+ }
ret = mOrigins;
} catch (InterruptedException e) {
Log.e(TAG, "Exception while waiting on the updated origins", e);
@@ -155,8 +159,11 @@
}
mLock.lock();
try {
+ mUpdateAvailable = false;
update();
- mCacheUpdated.await();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.await();
+ }
Long usage = mUsages.get(origin);
if (usage != null) {
ret = usage.longValue();
@@ -180,8 +187,11 @@
}
mLock.lock();
try {
+ mUpdateAvailable = false;
update();
- mCacheUpdated.await();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.await();
+ }
Long quota = mQuotas.get(origin);
if (quota != null) {
ret = quota.longValue();
@@ -286,7 +296,8 @@
mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
}
- mCacheUpdated.signal();
+ mUpdateAvailable = true;
+ mUpdateCondition.signal();
mLock.unlock();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 19df87f..358fc9e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -351,6 +351,9 @@
VelocityTracker mVelocityTracker;
private int mMaximumFling;
+ // use this flag to control whether enabling the new double tap zoom
+ static final boolean ENABLE_DOUBLETAP_ZOOM = true;
+
/**
* Touch mode
*/
@@ -370,6 +373,7 @@
private static final int SCROLL_ZOOM_OUT = 11;
private static final int LAST_SCROLL_ZOOM = 11;
// end of touch mode values specific to scale+scroll
+ private static final int TOUCH_DOUBLE_TAP_MODE = 12;
// Whether to forward the touch events to WebCore
private boolean mForwardTouchEvents = false;
@@ -394,6 +398,8 @@
*/
// pre-computed square of ViewConfiguration.getScaledTouchSlop()
private int mTouchSlopSquare;
+ // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
+ private int mDoubleTapSlopSquare;
// pre-computed density adjusted navigation slop
private int mNavSlop;
// This should be ViewConfiguration.getTapTimeout()
@@ -450,6 +456,7 @@
private static final int NEVER_REMEMBER_PASSWORD = 2;
private static final int SWITCH_TO_SHORTPRESS = 3;
private static final int SWITCH_TO_LONGPRESS = 4;
+ private static final int RELEASE_SINGLE_TAP = 5;
private static final int REQUEST_FORM_DATA = 6;
private static final int SWITCH_TO_CLICK = 7;
private static final int RESUME_WEBCORE_UPDATE = 8;
@@ -482,7 +489,7 @@
"NEVER_REMEMBER_PASSWORD", // = 2;
"SWITCH_TO_SHORTPRESS", // = 3;
"SWITCH_TO_LONGPRESS", // = 4;
- "5",
+ "RELEASE_SINGLE_TAP", // = 5;
"REQUEST_FORM_DATA", // = 6;
"SWITCH_TO_CLICK", // = 7;
"RESUME_WEBCORE_UPDATE", // = 8;
@@ -521,6 +528,16 @@
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
+ // while in the zoom overview mode, the page's width is fully fit to the
+ // current window. The page is alive, in another words, you can click to
+ // follow the links. Double tap will toggle between zoom overview mode and
+ // the last zoom scale.
+ boolean mInZoomOverview = false;
+ // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
+ // engadget always have wider mContentWidth no matter what viewport size is.
+ int mZoomOverviewWidth = 0;
+ float mLastScale;
+
// default scale. Depending on the display density.
static int DEFAULT_SCALE_PERCENT;
private float mDefaultScale;
@@ -762,9 +779,11 @@
setLongClickable(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- final int slop = configuration.getScaledTouchSlop();
+ int slop = configuration.getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = slop;
+ slop = configuration.getScaledDoubleTapSlop();
+ mDoubleTapSlopSquare = slop * slop;
final float density = getContext().getResources().getDisplayMetrics().density;
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
@@ -1124,6 +1143,9 @@
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
b.putFloat("scale", mActualScale);
+ if (mInZoomOverview) {
+ b.putFloat("lastScale", mLastScale);
+ }
return true;
}
return false;
@@ -1168,6 +1190,13 @@
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
+ float lastScale = b.getFloat("lastScale", -1.0f);
+ if (lastScale > 0) {
+ mInZoomOverview = true;
+ mLastScale = lastScale;
+ } else {
+ mInZoomOverview = false;
+ }
invalidate();
return true;
}
@@ -3060,6 +3089,11 @@
float y = mLastTouchY + (float) (mScrollY - lp.y);
mWebTextView.fakeTouchEvent(x, y);
}
+ if (mInZoomOverview) {
+ // if in zoom overview mode, call doDoubleTap() to bring it back
+ // to normal mode so that user can enter text.
+ doDoubleTap();
+ }
}
else { // used by plugins
imm.showSoftInput(this, 0);
@@ -3634,7 +3668,9 @@
// update mMinZoomScale if the minimum zoom scale is not fixed
if (!mMinZoomScaleFixed) {
mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
+ / Math.max(ZOOM_OUT_WIDTH, mDrawHistory ? mHistoryPicture
+ .getWidth() : (mZoomOverviewWidth > 0 ?
+ mZoomOverviewWidth : mContentWidth));
}
// we always force, in case our height changed, in which case we still
@@ -3755,6 +3791,15 @@
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
+ } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
+ mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
+ if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
+ mTouchMode = TOUCH_DOUBLE_TAP_MODE;
+ } else {
+ // commit the short press action for the previous tap
+ doShortPress();
+ // continue, mTouchMode should be still TOUCH_INIT_MODE
+ }
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
@@ -3764,7 +3809,8 @@
}
}
// Trigger the link
- if (mTouchMode == TOUCH_INIT_MODE) {
+ if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
@@ -3810,7 +3856,8 @@
if (mTouchMode == TOUCH_SHORTPRESS_MODE
|| mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- } else if (mTouchMode == TOUCH_INIT_MODE) {
+ } else if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
@@ -3836,7 +3883,7 @@
.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
}
WebSettings settings = getSettings();
- if (settings.supportZoom()
+ if (settings.supportZoom() && !mInZoomOverview
&& settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
&& (canZoomScrollOut() ||
@@ -3905,7 +3952,7 @@
mUserScroll = true;
}
- if (!getSettings().getBuiltInZoomControls()) {
+ if (!getSettings().getBuiltInZoomControls() && !mInZoomOverview) {
boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
boolean showMagnify = canZoomScrollOut();
if (mZoomControls != null && (showPlusMinus || showMagnify)) {
@@ -3929,7 +3976,22 @@
case MotionEvent.ACTION_UP: {
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
+ case TOUCH_DOUBLE_TAP_MODE: // double tap
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ doDoubleTap();
+ break;
case TOUCH_INIT_MODE: // tap
+ if (ENABLE_DOUBLETAP_ZOOM) {
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ if (!mPreventDrag) {
+ mPrivateHandler.sendMessageDelayed(
+ mPrivateHandler.obtainMessage(
+ RELEASE_SINGLE_TAP),
+ ViewConfiguration.getDoubleTapTimeout());
+ }
+ break;
+ }
+ // fall through
case TOUCH_SHORTPRESS_START_MODE:
case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -4365,6 +4427,9 @@
mInvInitialZoomScale = 1.0f / oldScale;
mInvFinalZoomScale = 1.0f / mActualScale;
mZoomScale = mActualScale;
+ if (!mInZoomOverview) {
+ mLastScale = scale;
+ }
invalidate();
return true;
} else {
@@ -4470,6 +4535,9 @@
public boolean zoomIn() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
return zoomWithPreview(mActualScale * 1.25f);
}
@@ -4480,6 +4548,9 @@
public boolean zoomOut() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
return zoomWithPreview(mActualScale * 0.8f);
}
@@ -4571,6 +4642,50 @@
}
}
+ private void doDoubleTap() {
+ if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
+ return;
+ }
+ mZoomCenterX = mLastTouchX;
+ mZoomCenterY = mLastTouchY;
+ mInZoomOverview = !mInZoomOverview;
+ if (mInZoomOverview) {
+ float newScale = (float) getViewWidth()
+ / (mZoomOverviewWidth > 0 ? mZoomOverviewWidth
+ : mContentWidth);
+ if (Math.abs(newScale - mActualScale) < 0.01) {
+ mInZoomOverview = !mInZoomOverview;
+ // as it is already full screen, do nothing.
+ return;
+ }
+ if (getSettings().getBuiltInZoomControls()) {
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
+ }
+ } else {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ }
+ zoomWithPreview(newScale);
+ } else {
+ // mLastTouchX and mLastTouchY are the point in the current viewport
+ int contentX = viewToContent((int) mLastTouchX + mScrollX);
+ int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int left = nativeGetBlockLeftEdge(contentX, contentY);
+ if (left != NO_LEFTEDGE) {
+ // add a 5pt padding to the left edge. Re-calculate the zoom
+ // center so that the new scroll x will be on the left edge.
+ mZoomCenterX = left < 5 ? 0 : (left - 5) * mLastScale
+ * mActualScale / (mLastScale - mActualScale);
+ }
+ zoomWithPreview(mLastScale);
+ }
+ }
+
// Called by JNI to handle a touch on a node representing an email address,
// address, or phone number
private void overrideLoading(String url) {
@@ -4791,6 +4906,8 @@
if (mTouchMode == TOUCH_INIT_MODE) {
mTouchMode = TOUCH_SHORTPRESS_START_MODE;
updateSelection();
+ } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
+ mTouchMode = TOUCH_DONE_MODE;
}
break;
}
@@ -4802,6 +4919,13 @@
}
break;
}
+ case RELEASE_SINGLE_TAP: {
+ if (!mPreventDrag) {
+ mTouchMode = TOUCH_DONE_MODE;
+ doShortPress();
+ }
+ break;
+ }
case SWITCH_TO_CLICK:
// The user clicked with the trackball, and did not click a
// second time, so perform the action of a trackball single
@@ -4854,6 +4978,7 @@
break;
case NEW_PICTURE_MSG_ID:
// called for new content
+ final int viewWidth = getViewWidth();
final WebViewCore.DrawData draw =
(WebViewCore.DrawData) msg.obj;
final Point viewSize = draw.mViewPoint;
@@ -4861,16 +4986,12 @@
// use the same logic in sendViewSizeZoom() to make sure
// the mZoomScale has matched the viewSize so that we
// can clear mZoomScale
- if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
+ if (Math.round(viewWidth / mZoomScale) == viewSize.x) {
mZoomScale = 0;
mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
0, 0);
}
}
- if (!mMinZoomScaleFixed) {
- mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
- }
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
// WebCore matches the view size of the picture we just
@@ -4888,6 +5009,25 @@
if (mPictureListener != null) {
mPictureListener.onNewPicture(WebView.this, capturePicture());
}
+ if (mWebViewCore.getSettings().getUseWideViewPort()) {
+ mZoomOverviewWidth = Math.max(draw.mMinPrefWidth,
+ draw.mViewPoint.x);
+ }
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) viewWidth
+ / Math.max(ZOOM_OUT_WIDTH,
+ mZoomOverviewWidth > 0 ? mZoomOverviewWidth
+ : mContentWidth);
+ }
+ if (!mDrawHistory && mInZoomOverview) {
+ // fit the content width to the current view. Ignore
+ // the rounding error case.
+ if (Math.abs((viewWidth * mInvActualScale)
+ - mZoomOverviewWidth) > 1) {
+ zoomWithPreview((float) viewWidth
+ / mZoomOverviewWidth);
+ }
+ }
break;
case WEBCORE_INITIALIZED_MSG_ID:
// nativeCreate sets mNativeClass to a non-zero value
@@ -4916,7 +5056,7 @@
}
}
break;
- case DID_FIRST_LAYOUT_MSG_ID:
+ case DID_FIRST_LAYOUT_MSG_ID: {
if (mNativeClass == 0) {
break;
}
@@ -4943,15 +5083,17 @@
if (width == 0) {
break;
}
+ final WebSettings settings = mWebViewCore.getSettings();
int initialScale = msg.arg1;
int viewportWidth = msg.arg2;
// start a new page with DEFAULT_SCALE zoom scale.
float scale = mDefaultScale;
+ mInZoomOverview = false;
if (mInitialScale > 0) {
scale = mInitialScale / 100.0f;
} else {
- if (initialScale < 0) break;
- if (mWebViewCore.getSettings().getUseWideViewPort()) {
+ if (initialScale == -1) break;
+ if (settings.getUseWideViewPort()) {
// force viewSizeChanged by setting mLastWidthSent
// to 0
mLastWidthSent = 0;
@@ -4961,11 +5103,21 @@
// than the view width, zoom in to fill the view
if (viewportWidth > 0 && viewportWidth < width) {
scale = (float) width / viewportWidth;
+ } else {
+ if (settings.getUseWideViewPort()) {
+ mInZoomOverview = ENABLE_DOUBLETAP_ZOOM;
+ }
}
+ } else if (initialScale < 0) {
+ // this should only happen when
+ // ENABLE_DOUBLETAP_ZOOM is true
+ mInZoomOverview = true;
+ scale = -initialScale / 100.0f;
} else {
scale = initialScale / 100.0f;
}
}
+ mLastScale = scale;
setNewZoomScale(scale, false);
// As we are on a new page, remove the WebTextView. This
// is necessary for page loads driven by webkit, and in
@@ -4973,6 +5125,7 @@
// the WebTextView was visible.
clearTextEntry();
break;
+ }
case MOVE_OUT_OF_PLUGIN:
if (nativePluginEatsNavKey()) {
navHandledKey(msg.arg1, 1, false, 0, true);
@@ -5542,4 +5695,7 @@
private native void nativeUpdateCachedTextfield(String updatedText,
int generation);
private native void nativeUpdatePluginReceivesEvents();
+ // return NO_LEFTEDGE means failure.
+ private static final int NO_LEFTEDGE = -1;
+ private native int nativeGetBlockLeftEdge(int x, int y);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4993fcf..4afc4cd 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -36,6 +36,7 @@
import android.view.SurfaceView;
import java.util.ArrayList;
+import java.util.Set;
import junit.framework.Assert;
@@ -96,7 +97,8 @@
private boolean mViewportUserScalable = true;
- private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
+ private int mRestoredScale = 0;
+ private int mRestoredScreenWidthScale = 0;
private int mRestoredX = 0;
private int mRestoredY = 0;
@@ -165,6 +167,8 @@
WebIconDatabase.getInstance().createHandler();
// Create the handler for WebStorage
WebStorage.getInstance().createHandler();
+ // Create the handler for GeolocationPermissions.
+ GeolocationPermissions.getInstance().createHandler();
// The transferMessages call will transfer all pending messages to the
// WebCore thread handler.
mEventHub.transferMessages();
@@ -246,7 +250,7 @@
}
/**
- * Notify the user that the origin has exceeded it's database quota.
+ * Notify the browser that the origin has exceeded it's database quota.
* @param url The URL that caused the overflow.
* @param databaseIdentifier The identifier of the database.
* @param currentQuota The current quota for the origin.
@@ -259,14 +263,55 @@
// awaken the sleeping webcore thread when a decision from the
// client to allow or deny quota is available.
mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier,
- currentQuota, new WebStorage.QuotaUpdater() {
+ currentQuota, getUsedQuota(), new WebStorage.QuotaUpdater() {
public void updateQuota(long quota) {
- nativeSetDatabaseQuota(quota);
+ nativeSetNewStorageLimit(quota);
}
});
}
/**
+ * Notify the browser that the appcache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ */
+ protected void reachedMaxAppCacheSize(long spaceNeeded) {
+ mCallbackProxy.onReachedMaxAppCacheSize(spaceNeeded, getUsedQuota(),
+ new WebStorage.QuotaUpdater() {
+ public void updateQuota(long quota) {
+ nativeSetNewStorageLimit(quota);
+ }
+ });
+ }
+
+ /**
+ * Shows a prompt to ask the user to set the Geolocation permission state
+ * for the given origin.
+ * @param origin The origin for which Geolocation permissions are
+ * requested.
+ */
+ protected void geolocationPermissionsShowPrompt(String origin) {
+ mCallbackProxy.onGeolocationPermissionsShowPrompt(origin,
+ new GeolocationPermissions.Callback() {
+ public void invoke(String origin, boolean allow, boolean remember) {
+ GeolocationPermissionsData data = new GeolocationPermissionsData();
+ data.mOrigin = origin;
+ data.mAllow = allow;
+ data.mRemember = remember;
+ // Marshall to WebCore thread.
+ sendMessage(EventHub.GEOLOCATION_PERMISSIONS_PROVIDE, data);
+ }
+ });
+ }
+
+ /**
+ * Hides the Geolocation permissions prompt.
+ */
+ protected void geolocationPermissionsHidePrompt() {
+ mCallbackProxy.onGeolocationPermissionsHidePrompt();
+ }
+
+ /**
* Invoke a javascript confirm dialog.
* @param message The message displayed in the dialog.
* @return True if the user confirmed or false if the user cancelled.
@@ -439,14 +484,24 @@
/*
* Inform webcore that the user has decided whether to allow or deny new
- * quota for the current origin and that the main thread should wake up
- * now.
- * @param quota The new quota.
+ * quota for the current origin or more space for the app cache, and that
+ * the main thread should wake up now.
+ * @param limit Is the new quota for an origin or new app cache max size.
*/
- private native void nativeSetDatabaseQuota(long quota);
+ private native void nativeSetNewStorageLimit(long limit);
private native void nativeUpdatePluginState(int framePtr, int nodePtr, int state);
+ /**
+ * Provide WebCore with a Geolocation permission state for the specified
+ * origin.
+ * @param origin The origin for which Geolocation permissions are provided.
+ * @param allow Whether Geolocation permissions are allowed.
+ * @param remember Whether this decision should be remembered beyond the
+ * life of the current page.
+ */
+ private native void nativeGeolocationPermissionsProvide(String origin, boolean allow, boolean remember);
+
// EventHub for processing messages
private final EventHub mEventHub;
// WebCore thread handler
@@ -590,6 +645,12 @@
int mState;
}
+ static class GeolocationPermissionsData {
+ String mOrigin;
+ boolean mAllow;
+ boolean mRemember;
+ }
+
static final String[] HandlerDebugString = {
"SCROLL_TEXT_INPUT", // = 99
"LOAD_URL", // = 100;
@@ -715,6 +776,8 @@
static final int DUMP_NAVTREE = 172;
static final int SET_JS_FLAGS = 173;
+ // Geolocation
+ static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
// private message ids
private static final int DESTROY = 200;
@@ -1101,6 +1164,12 @@
case SET_JS_FLAGS:
nativeSetJsFlags((String)msg.obj);
+
+ case GEOLOCATION_PERMISSIONS_PROVIDE:
+ GeolocationPermissionsData data =
+ (GeolocationPermissionsData) msg.obj;
+ nativeGeolocationPermissionsProvide(data.mOrigin,
+ data.mAllow, data.mRemember);
break;
case SYNC_SCROLL:
@@ -1340,9 +1409,8 @@
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
}
- if (mSettings.getUseWideViewPort()
- && (w < mViewportWidth || mViewportWidth == -1)) {
- int width = mViewportWidth;
+ if (mSettings.getUseWideViewPort()) {
+ int width;
if (mViewportWidth == -1) {
if (mSettings.getLayoutAlgorithm() ==
WebSettings.LayoutAlgorithm.NORMAL) {
@@ -1362,9 +1430,15 @@
*/
width = Math.max(w, nativeGetContentMinPrefWidth());
}
+ } else {
+ width = Math.max(w, mViewportWidth);
}
- nativeSetSize(width, Math.round((float) width * h / w), w, scale,
- w, h);
+ // while in zoom overview mode, the text are wrapped to the screen
+ // width matching mWebView.mLastScale. So that we don't trigger
+ // re-flow while toggling between overview mode and normal mode.
+ nativeSetSize(width, Math.round((float) width * h / w),
+ Math.round(mWebView.mInZoomOverview ? w * scale
+ / mWebView.mLastScale : w), scale, w, h);
} else {
nativeSetSize(w, h, w, scale, w, h);
}
@@ -1389,6 +1463,21 @@
}
}
+ // Utility method for exceededDatabaseQuota and reachedMaxAppCacheSize
+ // callbacks. Computes the sum of database quota for all origins.
+ private long getUsedQuota() {
+ WebStorage webStorage = WebStorage.getInstance();
+ Set<String> origins = webStorage.getOrigins();
+ if (origins == null) {
+ return 0;
+ }
+ long usedQuota = 0;
+ for (String origin : origins) {
+ usedQuota += webStorage.getQuotaForOrigin(origin);
+ }
+ return usedQuota;
+ }
+
// Used to avoid posting more than one draw message.
private boolean mDrawIsScheduled;
@@ -1409,6 +1498,7 @@
public Region mInvalRegion;
public Point mViewPoint;
public Point mWidthHeight;
+ public int mMinPrefWidth;
}
private void webkitDraw() {
@@ -1424,6 +1514,9 @@
// Send the native view size that was used during the most recent
// layout.
draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
+ if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
+ draw.mMinPrefWidth = nativeGetContentMinPrefWidth();
+ }
if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
Message.obtain(mWebView.mPrivateHandler,
WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
@@ -1734,9 +1827,10 @@
if (mRestoredScale > 0) {
Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
+ WebView.DID_FIRST_LAYOUT_MSG_ID,
+ mRestoredScreenWidthScale > 0 ?
+ -mRestoredScreenWidthScale : mRestoredScale, 0,
scaleLimit).sendToTarget();
- mRestoredScale = 0;
} else {
// if standardLoad is true, use mViewportInitialScale, otherwise
// pass -1 to the WebView to indicate no change of the scale.
@@ -1764,8 +1858,8 @@
}
}
- // reset restored offset
- mRestoredX = mRestoredY = 0;
+ // reset restored offset, scale
+ mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0;
}
}
@@ -1777,6 +1871,17 @@
}
// called by JNI
+ private void restoreScreenWidthScale(int scale) {
+ if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) {
+ return;
+ }
+
+ if (mBrowserFrame.firstLayoutDone() == false) {
+ mRestoredScreenWidthScale = scale;
+ }
+ }
+
+ // called by JNI
private void needTouchEvents(boolean need) {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index e613ec4..ea88b5b 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -104,6 +104,7 @@
private View mDropDownAnchorView; // view is retrieved lazily from id once needed
private int mDropDownWidth;
private int mDropDownHeight;
+ private final Rect mTempRect = new Rect();
private Drawable mDropDownListHighlight;
@@ -209,8 +210,7 @@
private void onClickImpl() {
// If the dropdown is showing, bring it back in front of the soft
// keyboard when the user touches the text field.
- if (mPopup.isShowing() &&
- mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED) {
+ if (mPopup.isShowing() && isInputMethodNotNeeded()) {
ensureImeVisible();
}
}
@@ -1089,6 +1089,13 @@
}
/**
+ * @hide internal used only here and SearchDialog
+ */
+ public boolean isInputMethodNotNeeded() {
+ return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+ }
+
+ /**
* <p>Displays the drop down on screen.</p>
*/
public void showDropDown() {
@@ -1097,7 +1104,7 @@
int widthSpec = 0;
int heightSpec = 0;
- boolean noInputMethod = mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+ boolean noInputMethod = isInputMethodNotNeeded();
if (mPopup.isShowing()) {
if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
@@ -1303,7 +1310,15 @@
getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
if (mDropDownAlwaysVisible) {
- return maxHeight;
+ // getMaxAvailableHeight() subtracts the padding, so we put it back,
+ // to get the available height for the whole window
+ int padding = 0;
+ Drawable background = mPopup.getBackground();
+ if (background != null) {
+ background.getPadding(mTempRect);
+ padding = mTempRect.top + mTempRect.bottom;
+ }
+ return maxHeight + padding;
}
return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 24c0e2a..e19a93d 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -432,7 +432,7 @@
width = resolveSize(width, widthMeasureSpec);
if (offsetHorizontalAxis) {
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
LayoutParams params = (LayoutParams) child.getLayoutParams();
@@ -486,10 +486,14 @@
View child = getChildAt(i);
if (child.getVisibility() != GONE && child != ignore) {
LayoutParams params = (LayoutParams) child.getLayoutParams();
- params.mLeft += horizontalOffset;
- params.mRight += horizontalOffset;
- params.mTop += verticalOffset;
- params.mBottom += verticalOffset;
+ if (horizontalGravity) {
+ params.mLeft += horizontalOffset;
+ params.mRight += horizontalOffset;
+ }
+ if (verticalGravity) {
+ params.mTop += verticalOffset;
+ params.mBottom += verticalOffset;
+ }
}
}
}
diff --git a/core/java/com/google/android/gdata/client/QueryParamsImpl.java b/core/java/com/google/android/gdata/client/QueryParamsImpl.java
index e27b36f..fbe0d22 100644
--- a/core/java/com/google/android/gdata/client/QueryParamsImpl.java
+++ b/core/java/com/google/android/gdata/client/QueryParamsImpl.java
@@ -60,6 +60,8 @@
sb.append('?');
}
for (String param : params) {
+ String value = mParams.get(param);
+ if (value == null) continue;
if (first) {
first = false;
} else {
@@ -67,7 +69,7 @@
}
sb.append(param);
sb.append('=');
- String value = mParams.get(param);
+
String encodedValue = null;
try {
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 6449147..65c0435 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -53,10 +53,11 @@
int STREAM_MUSIC; //... stream type constants
int STREAM_ALARM; //... stream type constants
int STREAM_NOTIFICATION; //... stream type constants
- int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_DTMF; //... stream type constants
int MODE_STREAM; //... memory mode
int MODE_STATIC; //... memory mode
- jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
+ jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
};
static fields_t javaAudioTrackFields;
@@ -203,6 +204,8 @@
atStreamType = AudioSystem::NOTIFICATION;
} else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
atStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (streamType == javaAudioTrackFields.STREAM_DTMF) {
+ atStreamType = AudioSystem::DTMF;
} else {
LOGE("Error creating AudioTrack: unknown stream type.");
return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
@@ -727,6 +730,8 @@
nativeStreamType = AudioSystem::NOTIFICATION;
} else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
nativeStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_DTMF) {
+ nativeStreamType = AudioSystem::DTMF;
} else {
nativeStreamType = AudioSystem::DEFAULT;
}
@@ -822,6 +827,7 @@
#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
+#define JAVA_CONST_STREAM_DTMF_NAME "STREAM_DTMF"
#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
@@ -943,8 +949,10 @@
JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION))
|| !android_media_getIntConstantFromClass(env, audioManagerClass,
JAVA_AUDIOMANAGER_CLASS_NAME,
- JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME,
- &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))) {
+ JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME, &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_DTMF_NAME, &(javaAudioTrackFields.STREAM_DTMF))) {
// error log performed in android_media_getIntConstantFromClass()
return -1;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 17704ae..6ad2441 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -863,7 +863,8 @@
android:protectionLevel="signature" />
<!-- Allows an application to call the activity manager shutdown() API
- to put the higher-level system there into a shutdown state. -->
+ to put the higher-level system there into a shutdown state.
+ @hide -->
<permission android:name="android.permission.SHUTDOWN"
android:label="@string/permlab_shutdown"
android:description="@string/permdesc_shutdown"
@@ -872,7 +873,8 @@
<!-- Allows an application to tell the activity manager to temporarily
stop application switches, putting it into a special mode that
prevents applications from immediately switching away from some
- critical UI such as the home screen. -->
+ critical UI such as the home screen.
+ @hide -->
<permission android:name="android.permission.STOP_APP_SWITCHES"
android:label="@string/permlab_stopAppSwitches"
android:description="@string/permdesc_stopAppSwitches"
diff --git a/core/res/res/drawable/expander_ic_maximized.9.png b/core/res/res/drawable/expander_ic_maximized.9.png
index 778255a..465cabd 100644
--- a/core/res/res/drawable/expander_ic_maximized.9.png
+++ b/core/res/res/drawable/expander_ic_maximized.9.png
Binary files differ
diff --git a/core/res/res/drawable/expander_ic_minimized.9.png b/core/res/res/drawable/expander_ic_minimized.9.png
index 5235c18..9967ecb 100644
--- a/core/res/res/drawable/expander_ic_minimized.9.png
+++ b/core/res/res/drawable/expander_ic_minimized.9.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0e848398..549b668 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1709,6 +1709,8 @@
<string name="volume_music">Media volume</string>
<!-- Hint shown in the volume toast to inform the user that the media audio is playing through Bluetooth. -->
<string name="volume_music_hint_playing_through_bluetooth">Playing through Bluetooth</string>
+ <!-- Hint shown in the volume toast to inform the user that the current ringtone is the silent ringtone. -->
+ <string name="volume_music_hint_silent_ringtone_selected">Silent ringtone selected</string>
<!-- Title of the dialog where the user is adjusting the phone call volume -->
<string name="volume_call">In-call volume</string>
<!-- Title of the dialog where the user is adjusting the phone call volume when connected on bluetooth-->
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index f829b08..2b9e448 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -96,6 +96,7 @@
native private int nAllocationCreatePredefSized(int predef, int count);
native private int nAllocationCreateSized(int elem, int count);
native private int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
+ native private int nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
native private void nAllocationUploadToTexture(int alloc, int baseMioLevel);
native private void nAllocationDestroy(int alloc);
@@ -529,7 +530,12 @@
}
public Allocation allocationCreateFromBitmap(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
- int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+ int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+ return new Allocation(id);
+ }
+
+ public Allocation allocationCreateFromBitmapBoxed(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
+ int id = nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
return new Allocation(id);
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 573610c..6f781a0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -291,6 +291,29 @@
return 0;
}
+static int
+nAllocationCreateFromBitmapBoxed(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+
+ RsElementPredefined e = SkBitmapToPredefined(config);
+
+ if (e != RS_ELEMENT_USER_U8) {
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* ptr = bitmap.getPixels();
+ jint id = (jint)rsAllocationCreateFromBitmapBoxed(w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
static void
nAllocationDestroy(JNIEnv *_env, jobject _this, jint a)
@@ -994,6 +1017,7 @@
{"nAllocationCreatePredefSized", "(II)I", (void*)nAllocationCreatePredefSized },
{"nAllocationCreateSized", "(II)I", (void*)nAllocationCreateSized },
{"nAllocationCreateFromBitmap", "(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap },
+{"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmapBoxed },
{"nAllocationUploadToTexture", "(II)V", (void*)nAllocationUploadToTexture },
{"nAllocationDestroy", "(I)V", (void*)nAllocationDestroy },
{"nAllocationData", "(I[I)V", (void*)nAllocationData_i },
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
index 0859457..e76fd4c 100644
--- a/include/media/stagefright/OMXDecoder.h
+++ b/include/media/stagefright/OMXDecoder.h
@@ -26,6 +26,8 @@
#include <utils/List.h>
#include <utils/threads.h>
+#include <OMX_Video.h>
+
namespace android {
class OMXMediaBuffer;
@@ -35,10 +37,8 @@
public MediaBufferObserver {
public:
static OMXDecoder *Create(
- OMXClient *client, const sp<MetaData> &data);
-
- static OMXDecoder *CreateEncoder(
- OMXClient *client, const sp<MetaData> &data);
+ OMXClient *client, const sp<MetaData> &data,
+ bool createEncoder = false);
virtual ~OMXDecoder();
@@ -68,10 +68,23 @@
};
enum PortStatus {
- kPortStatusActive = 0,
- kPortStatusDisabled = 1,
- kPortStatusShutdown = 2,
- kPortStatusFlushing = 3
+ kPortStatusActive = 0,
+ kPortStatusDisabled = 1,
+ kPortStatusShutdown = 2,
+ kPortStatusFlushing = 3,
+ kPortStatusFlushingToDisabled = 4,
+ kPortStatusFlushingToShutdown = 5,
+ };
+
+ enum Quirks {
+ kWantsRawNALFrames = 1,
+ kDoesntReturnBuffersOnDisable = 2,
+ kDoesntFlushOnExecutingToIdle = 4,
+ kDoesntProperlyFlushAllPortsAtOnce = 8,
+ kRequiresAllocateBufferOnInputPorts = 16,
+ kRequiresAllocateBufferOnOutputPorts = 32,
+ kRequiresLoadedToIdleAfterAllocation = 64,
+ kMeasuresTimeInMilliseconds = 128,
};
OMXClient *mClient;
@@ -79,6 +92,8 @@
IOMX::node_id mNode;
char *mComponentName;
bool mIsMP3;
+ bool mIsAVC;
+ uint32_t mQuirks;
MediaSource *mSource;
sp<MetaData> mOutputFormat;
@@ -116,7 +131,8 @@
bool mReachedEndOfInput;
OMXDecoder(OMXClient *client, IOMX::node_id node,
- const char *mime, const char *codec);
+ const char *mime, const char *codec,
+ uint32_t quirks);
void setPortStatus(OMX_U32 port_index, PortStatus status);
PortStatus getPortStatus(OMX_U32 port_index) const;
@@ -125,7 +141,13 @@
void setAMRFormat();
void setAACFormat();
- void setVideoOutputFormat(OMX_U32 width, OMX_U32 height);
+
+ status_t setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat);
+
+ void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
void setup();
void dumpPortDefinition(OMX_U32 port_index);
@@ -144,6 +166,7 @@
void freeInputBuffer(IOMX::buffer_id buffer);
void freeOutputBuffer(IOMX::buffer_id buffer);
+ void freePortBuffers(OMX_U32 port_index);
void postStart();
void postEmptyBufferDone(IOMX::buffer_id buffer);
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..f7fa81b
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+ TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~TIHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<Overlay> mOverlay;
+ Vector<void *> mOverlayAddresses;
+ size_t mIndex;
+
+ TIHardwareRenderer(const TIHardwareRenderer &);
+ TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // TI_HARDWARE_RENDERER_H_
+
diff --git a/keystore/jni/certtool.c b/keystore/jni/certtool.c
index 1ae8dab..b36b34a 100644
--- a/keystore/jni/certtool.c
+++ b/keystore/jni/certtool.c
@@ -30,13 +30,17 @@
android_security_CertTool_generateCertificateRequest(JNIEnv* env,
jobject thiz,
jint bits,
- jstring subject)
+ jstring jChallenge)
{
+ int ret = -1;
+ jboolean bIsCopy;
char csr[REPLY_MAX];
- if (gen_csr(bits, subject, csr) == 0) {
- return (*env)->NewStringUTF(env, csr);
- }
+ const char* challenge = (*env)->GetStringUTFChars(env, jChallenge, &bIsCopy);
+
+ ret = gen_csr(bits, challenge , csr);
+ (*env)->ReleaseStringUTFChars(env, jChallenge, challenge);
+ if (ret == 0) return (*env)->NewStringUTF(env, csr);
return NULL;
}
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index c10e02b..f5c03bb 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -107,6 +107,7 @@
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
+ LOCAL_SHARED_LIBRARIES += liba2dp
endif
ifeq ($(AUDIO_POLICY_TEST),true)
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 1336131..232ffb0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -3443,8 +3443,8 @@
srcThread->getTracks(tracks, activeTracks, stream);
if (tracks.size()) {
dstThread->putTracks(tracks, activeTracks);
- dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
}
+ dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
}
}
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 855ea63..1d14f70 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -146,26 +146,26 @@
};
enum RsBlendSrcFunc {
- RS_BLEND_SRC_ZERO,
- RS_BLEND_SRC_ONE,
- RS_BLEND_SRC_DST_COLOR,
- RS_BLEND_SRC_ONE_MINUS_DST_COLOR,
- RS_BLEND_SRC_SRC_ALPHA,
- RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,
- RS_BLEND_SRC_DST_ALPHA,
- RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,
- RS_BLEND_SRC_SRC_ALPHA_SATURATE
+ RS_BLEND_SRC_ZERO, // 0
+ RS_BLEND_SRC_ONE, // 1
+ RS_BLEND_SRC_DST_COLOR, // 2
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3
+ RS_BLEND_SRC_SRC_ALPHA, // 4
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_SRC_DST_ALPHA, // 6
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8
};
enum RsBlendDstFunc {
- RS_BLEND_DST_ZERO,
- RS_BLEND_DST_ONE,
- RS_BLEND_DST_SRC_COLOR,
- RS_BLEND_DST_ONE_MINUS_SRC_COLOR,
- RS_BLEND_DST_SRC_ALPHA,
- RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
- RS_BLEND_DST_DST_ALPHA,
- RS_BLEND_DST_ONE_MINUS_DST_ALPHA
+ RS_BLEND_DST_ZERO, // 0
+ RS_BLEND_DST_ONE, // 1
+ RS_BLEND_DST_SRC_COLOR, // 2
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3
+ RS_BLEND_DST_SRC_ALPHA, // 4
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_DST_DST_ALPHA, // 6
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7
};
enum RsTexEnvMode {
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 0789301..7a5556e 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -30,11 +30,3 @@
#define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16
#define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
-//typedef int (*rsc_RunScript)(uint32_t launchIndex, const rsc_FunctionTable *);
-
-
-/* EnableCap */
-#define GL_LIGHTING 0x0B50
-
-/* LightName */
-#define GL_LIGHT0 0x4000
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
index 6885251..495fe55 100644
--- a/libs/rs/java/Film/res/raw/filmstrip.c
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -11,29 +11,29 @@
int32_t triangleOffsets[64];
float triangleOffsetsTex[64];
int32_t triangleOffsetsCount;
-} FilmScriptUserEnv;
-*/
+} FilmScriptUserEnv;
+*/
+
+#define POS_TRANSLATE 0
+#define POS_ROTATE 1
+#define POS_FOCUS 2
+
+#define STATE_TRIANGLE_OFFSET_COUNT 0
+#define STATE_LAST_FOCUS 1
+
// The script enviroment has 3 env allocations.
// bank0: (r) The enviroment structure
// bank1: (r) The position information
// bank2: (rw) The temporary texture state
-int main(int index)
+int main(int index)
{
int f1,f2,f3,f4, f5,f6,f7,f8, f9,f10,f11,f12, f13,f14,f15,f16;
int g1,g2,g3,g4, g5,g6,g7,g8, g9,g10,g11,g12, g13,g14,g15,g16;
- float trans;
- float rot;
- int x;
- float focusPos; // float
- int focusID;
- int lastFocusID;
- int imgCount;
- trans = loadF(1, 0);
- rot = loadF(1, 1);
-
+ float trans = loadF(1, POS_TRANSLATE);
+ float rot = loadF(1, POS_ROTATE);
matrixLoadScale(&f16, 2.f, 2.f, 2.f);
matrixTranslate(&f16, 0.f, 0.f, trans);
matrixRotate(&f16, 90.f, 0.f, 0.f, 1.f);
@@ -46,24 +46,18 @@
drawTriangleMesh(NAMED_mesh);
-
- //int imgId = 0;
-
+ // Start of images.
bindProgramFragmentStore(NAMED_PFImages);
bindProgramFragment(NAMED_PFSImages);
bindProgramVertex(NAMED_PVImages);
- //focusPos = loadF(1, 2);
- //focusID = 0;
- //lastFocusID = loadI32(2, 0);
- //imgCount = 13;
+ float focusPos = loadF(1, POS_FOCUS);
+ int focusID = 0;
+ int lastFocusID = loadI32(2, STATE_LAST_FOCUS);
+ int imgCount = 13;
- /*
- disable(GL_LIGHTING);
-
-
- if (trans > (-.3)) {
- focusID = -1.0 - focusPos;
+ if (trans > (-.3f)) {
+ focusID = -1.0f - focusPos;
if (focusID >= imgCount) {
focusID = -1;
}
@@ -71,6 +65,7 @@
focusID = -1;
}
+ /*
if (focusID != lastFocusID) {
if (lastFocusID >= 0) {
uploadToTexture(con, env->tex[lastFocusID], 1);
@@ -79,36 +74,38 @@
uploadToTexture(con, env->tex[focusID], 0);
}
}
- storeEnvI32(con, 2, 0, focusID);
+ */
+ storeI32(2, STATE_LAST_FOCUS, focusID);
+ int triangleOffsetsCount = loadI32(2, STATE_TRIANGLE_OFFSET_COUNT);
+ int imgId = 0;
for (imgId=1; imgId <= imgCount; imgId++) {
- float pos = focusPos + imgId + .4f;
- int offset = (int)floor(pos*2);
- pos -= 0.75;
-
- offset += env->triangleOffsetsCount / 2;
-
- if ((offset < 0) || (offset >= env->triangleOffsetsCount)) {
- continue;
+ float pos = focusPos + imgId + 0.4f;
+ int offset = (int)floorf(pos * 2.f);
+ pos = pos - 0.75f;
+
+ offset = offset + triangleOffsetsCount / 2;
+
+ if (!((offset < 0) || (offset >= triangleOffsetsCount))) {
+ int start = offset -2;
+ int end = offset + 2;
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > triangleOffsetsCount) {
+ end = triangleOffsetsCount;
+ }
+
+ bindTexture(NAMED_PFImages, 0, loadI32(0, imgId - 1));
+ /*
+ matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
+ storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
+ renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
+ */
}
-
- int start = offset -2;
- int end = offset + 2;
-
- if (start < 0) {
- start = 0;
- }
- if (end > env->triangleOffsetsCount) {
- end = env->triangleOffsetsCount;
- }
-
- programFragmentBindTexture(con, env->fpImages, 0, env->tex[imgId - 1]);
- matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
- storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
- renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
- }
-*/
+ }
return 0;
}
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index fca0818..395bd35 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -38,6 +39,12 @@
import android.view.MotionEvent;
public class FilmRS {
+ private final int POS_TRANSLATE = 0;
+ private final int POS_ROTATE = 1;
+ private final int POS_FOCUS = 2;
+
+ private final int STATE_TRIANGLE_OFFSET_COUNT = 0;
+ private final int STATE_LAST_FOCUS = 1;
public FilmRS() {
}
@@ -56,11 +63,11 @@
if (x > 270) {
x = 270;
}
-
+
float anim = ((float)x-50) / 270.f;
- mBufferPos[0] = 2f * anim + 0.5f; // translation
- mBufferPos[1] = (anim * 40); // rotation
- mBufferPos[2] = ((float)y) / 16.f - 8; // focusPos
+ mBufferPos[POS_TRANSLATE] = 2f * anim + 0.5f; // translation
+ mBufferPos[POS_ROTATE] = (anim * 40); // rotation
+ mBufferPos[POS_FOCUS] = ((float)y) / 16.f - 8; // focusPos
mAllocPos.data(mBufferPos);
}
@@ -80,15 +87,19 @@
private RenderScript.ProgramVertex mPVImages;
private ProgramVertexAlloc mPVA;
- private RenderScript.Allocation mAllocEnv;
+ private RenderScript.Allocation mImages[];
+ private RenderScript.Allocation mAllocIDs;
private RenderScript.Allocation mAllocPos;
private RenderScript.Allocation mAllocState;
private RenderScript.Allocation mAllocPV;
private RenderScript.TriangleMesh mMesh;
private RenderScript.Light mLight;
- private float[] mBufferPos;
- private float[] mBufferPV;
+ private FilmStripMesh mFSM;
+
+ private int[] mBufferIDs;
+ private float[] mBufferPos = new float[3];
+ private int[] mBufferState;
private void initSamplers() {
mRS.samplerBegin();
@@ -112,7 +123,7 @@
mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.EQUAL);
mRS.programFragmentStoreDitherEnable(false);
mRS.programFragmentStoreDepthMask(false);
- mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
RenderScript.BlendDstFunc.ONE);
mPFSImages = mRS.programFragmentStoreCreate();
mPFSImages.setName("PFSImages");
@@ -148,7 +159,75 @@
}
- int mParams[] = new int[10];
+ private void loadImages() {
+ mBufferIDs = new int[13];
+ mImages = new RenderScript.Allocation[13];
+ mAllocIDs = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_FLOAT,
+ mBufferIDs.length);
+
+ Bitmap b;
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScaled = false;
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p01, opts);
+ mImages[0] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p02, opts);
+ mImages[1] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p03, opts);
+ mImages[2] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p04, opts);
+ mImages[3] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p05, opts);
+ mImages[4] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p06, opts);
+ mImages[5] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p07, opts);
+ mImages[6] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p08, opts);
+ mImages[7] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p09, opts);
+ mImages[8] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p10, opts);
+ mImages[9] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p11, opts);
+ mImages[10] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p12, opts);
+ mImages[11] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p13, opts);
+ mImages[12] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ for(int ct=0; ct < mImages.length; ct++) {
+ mImages[ct].uploadToTexture(1);
+ mBufferIDs[ct] = mImages[ct].getID();
+ }
+ mAllocIDs.data(mBufferIDs);
+ }
+
+ private void initState()
+ {
+ mBufferState = new int[10];
+ mAllocState = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_FLOAT,
+ mBufferState.length);
+
+ mBufferState[STATE_TRIANGLE_OFFSET_COUNT] = mFSM.mTriangleOffsetsCount;
+ mBufferState[STATE_LAST_FOCUS] = -1;
+
+ mAllocState.data(mBufferState);
+ }
private void initRS() {
mElementVertex = mRS.elementGetPredefined(
@@ -157,8 +236,8 @@
RenderScript.ElementPredefined.INDEX_16);
mRS.triangleMeshBegin(mElementVertex, mElementIndex);
- FilmStripMesh fsm = new FilmStripMesh();
- fsm.init(mRS);
+ mFSM = new FilmStripMesh();
+ mFSM.init(mRS);
mMesh = mRS.triangleMeshCreate();
mMesh.setName("mesh");
@@ -176,19 +255,22 @@
mRS.scriptCSetRoot(true);
mScriptStrip = mRS.scriptCCreate();
- mBufferPos = new float[3];
mAllocPos = mRS.allocationCreatePredefSized(
- RenderScript.ElementPredefined.USER_FLOAT,
+ RenderScript.ElementPredefined.USER_FLOAT,
mBufferPos.length);
+ loadImages();
+ initState();
+
mPVA = new ProgramVertexAlloc(mRS);
mPVBackground.bindAllocation(0, mPVA.mAlloc);
mPVImages.bindAllocation(0, mPVA.mAlloc);
mPVA.setupProjectionNormalized(320, 480);
+ mScriptStrip.bindAllocation(mAllocIDs, 0);
mScriptStrip.bindAllocation(mAllocPos, 1);
- //mScriptStrip.bindAllocation(gStateAlloc, 2);
+ mScriptStrip.bindAllocation(mAllocState, 2);
mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
diff --git a/libs/rs/java/Rollo/res/raw/calendar.png b/libs/rs/java/Rollo/res/raw/calendar.png
new file mode 100644
index 0000000..030ae73
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/calendar.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/g1155.png b/libs/rs/java/Rollo/res/raw/g1155.png
new file mode 100644
index 0000000..68e1843
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/g1155.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/g2140.png b/libs/rs/java/Rollo/res/raw/g2140.png
new file mode 100644
index 0000000..8c4e853
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/g2140.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path1920.png b/libs/rs/java/Rollo/res/raw/path1920.png
new file mode 100644
index 0000000..3510665
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path1920.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path1927.png b/libs/rs/java/Rollo/res/raw/path1927.png
new file mode 100644
index 0000000..fccc846
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path1927.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path3099.png b/libs/rs/java/Rollo/res/raw/path3099.png
new file mode 100644
index 0000000..527ebf6
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path3099.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path3950.png b/libs/rs/java/Rollo/res/raw/path3950.png
new file mode 100644
index 0000000..59a646a
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path3950.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path431.png b/libs/rs/java/Rollo/res/raw/path431.png
new file mode 100644
index 0000000..5d2ed75
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path431.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path4481.png b/libs/rs/java/Rollo/res/raw/path4481.png
new file mode 100644
index 0000000..78be0fc
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path4481.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path5168.png b/libs/rs/java/Rollo/res/raw/path5168.png
new file mode 100644
index 0000000..a7c3a19
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path5168.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path676.png b/libs/rs/java/Rollo/res/raw/path676.png
new file mode 100644
index 0000000..2099690
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path676.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path754.png b/libs/rs/java/Rollo/res/raw/path754.png
new file mode 100644
index 0000000..88aed5b
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path754.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path815.png b/libs/rs/java/Rollo/res/raw/path815.png
new file mode 100644
index 0000000..407570f
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path815.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/polygon2408.png b/libs/rs/java/Rollo/res/raw/polygon2408.png
new file mode 100644
index 0000000..4413954
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/polygon2408.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
index d338d0d..9e03a44 100644
--- a/libs/rs/java/Rollo/res/raw/rollo.c
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -19,6 +19,7 @@
#define STATE_COUNT 8
#define STATE_TOUCH 9
+
float filter(float val, float target, float str)
{
float delta = (target - val);
@@ -51,7 +52,7 @@
float touchCut = 1.f;
if (loadI32(0, STATE_TOUCH)) {
- touchCut = 5.f;
+ touchCut = 4.f;
}
@@ -60,20 +61,24 @@
storeF(2, SCRATCH_ZOOM, zoom);
float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
- float rot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
- storeF(2, SCRATCH_ROT, rot);
+ float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, drawRot);
- float diam = 8.f;// + curve * 2.f;
+ float diam = 8.f;
float scale = 1.0f / zoom;
- rot = rot * scale;
- float rotStep = 20.0f / 180.0f * 3.14f * scale;
+ // Bug makes 1.0f alpha fail.
+ color(1.0f, 1.0f, 1.0f, 0.99f);
+
+ float rot = drawRot * scale;
+ float rotStep = 16.0f / 180.0f * 3.14f * scale;
rowCount = 4;
int index = 0;
int iconCount = loadI32(0, STATE_COUNT);
while (iconCount) {
float tmpSin = sinf(rot);
float tmpCos = cosf(rot);
+ //debugF("rot", rot);
float tx1 = tmpSin * diam - (tmpCos * scale);
float tx2 = tx1 + (tmpCos * scale * 2.f);
@@ -82,24 +87,100 @@
int y;
for (y = rowCount -1; (y >= 0) && iconCount; y--) {
- float ty1 = ((y * 3.0f) - 4.5f) * scale;
+ float ty1 = ((y * 3.1f) - 5.f) * scale;
float ty2 = ty1 + scale * 2.f;
- bindTexture(NAMED_PF, 0, loadI32(1, y));
- color(1.0f, 1.0f, 1.0f, 1.0f);
- if (done && (index != selectedID)) {
- color(0.4f, 0.4f, 0.4f, 1.0f);
- }
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ //if (done && (index != selectedID)) {
+ //color(0.4f, 0.4f, 0.4f, 1.0f);
+ //}
drawQuad(tx1, ty1, tz1,
tx2, ty1, tz2,
tx2, ty2, tz2,
tx1, ty2, tz1);
+
iconCount--;
index++;
}
rot = rot + rotStep;
}
- return 0;
+ if ((zoom < 1.1f) && (zoom > 0.9f)) {
+ bindProgramVertex(NAMED_PVOrtho);
+ bindProgramFragment(NAMED_PFText);
+ bindProgramFragmentStore(NAMED_PFSText);
+
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+
+ float tx = 240.f + floorf(sinf(rot) * 430.f) - 64.f + 16.f;
+
+ float alpha = 2.4f - (fabsf(tx - 240.f + 48.f) / 76.f);
+ if (alpha > 0.99f) {
+ alpha = 0.99f;
+ }
+ alpha = alpha * (1.f - (fabsf(zoom - 1.f) * 10.f));
+
+ tx = tx + 0.25f;
+
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+
+ if (alpha > 0) {
+ color(1.0f, 1.0f, 1.0f, alpha);
+
+ float ty = 605.f - y * 150.f;
+
+ ty = ty + 0.25f;
+
+ bindTexture(NAMED_PFText, 0, loadI32(3, index));
+ drawRect(tx, ty, tx + 128.f, ty + 32.f, 0.5f);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+
+ bindProgramVertex(NAMED_PV);
+ bindProgramFragment(NAMED_PF);
+ bindProgramFragmentStore(NAMED_PFS);
+ }
+
+ // Draw the selected icon
+ color(1.0f, 1.0f, 1.0f, 0.9f);
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ if (index == selectedID) {
+
+ float tmpSin = sinf(rot) * scale;
+ float tmpCos = cosf(rot) * scale;
+ float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
+ float tx2 = tx1 + (tmpCos * 4.f);
+ float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
+ float tz2 = tz1 - (tmpSin * 4.f);
+
+ float ty1 = ((y * 3.1f) - 4.5f) * scale;
+ float ty2 = ty1 + scale * 4.f;
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ return 1;
}
diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c
index b04ea73..256fa3c 100644
--- a/libs/rs/java/Rollo/res/raw/rollo2.c
+++ b/libs/rs/java/Rollo/res/raw/rollo2.c
@@ -3,65 +3,153 @@
#pragma stateFragment(PF)
#pragma stateFragmentStore(PFS)
-void drawLoop(int x, int y, int z, int rot)
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+float filter(float val, float target, float str)
{
- int ct;
- int tx;
- int ty;
- int tmpSin;
- int tmpCos;
- int sz;
-
- for (ct = 0; ct < 10; ct ++) {
- tmpSin = sinx((ct * 36 + rot) * 0x10000);
- tmpCos = cosx((ct * 36 + rot) * 0x10000);
-
- ty = y + tmpCos * 4;
- tx = x + tmpSin * 4;
- pfBindTexture(NAMED_PF, 0, loadI32(1, ct & 3));
-
- sz = 0xc000;
- drawQuad(tx - sz, ty - sz, z,
- tx + sz, ty - sz, z,
- tx + sz, ty + sz, z,
- tx - sz, ty + sz, z);
- }
+ float delta = (target - val);
+ return val + delta * str;
}
+
int main(void* con, int ft, int launchID)
{
int rowCount;
- int x;
- int y;
- int row;
- int col;
int imageID;
- int tx1;
- int ty1;
- int tz1;
- int tx2;
- int ty2;
- int tz2;
- int tmpSin;
- int tmpCos;
- int iconCount;
- int pressure;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+ int iconCount = loadI32(0, STATE_COUNT);
- int ringCount;
+ float f = loadF(2, 0);
+ float iconSize = 1.f;
+ float iconSpacing = 0.2f;
+ float z = 4.f;
-
- rotStep = 16 * 0x10000;
- pressure = loadI32(0, 2);
- rowCount = 4;
-
- iconCount = loadI32(0, 1);
- rot = (-20 + loadI32(0, 0)) * 0x10000;
-
- for (ringCount = 0; ringCount < 5; ringCount++) {
- drawLoop(0, 0, 0x90000 + (ringCount * 0x80000));
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
}
- return 0;
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 5.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetPos = loadI32(0, STATE_FIRST_VISIBLE) / (-20.0f);
+ float pos = filter(loadF(2, SCRATCH_ROT), targetPos, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, pos);
+ pos = pos - 1.f;
+
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+
+
+ // Draw flat icons first
+ int index = ((int)pos) * 4;
+ int row;
+ int col;
+ float xoffset = -0.3f;
+ float gridSize = iconSize * 4.f + iconSpacing * 3.f;
+ float yoffset = (pos - ((int)pos));
+ for (row = 0; row < 4; row ++) {
+ float ty1 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + iconSize;
+
+ for (col = 0; (col < 4) && (index < iconCount); col ++) {
+ if (index >= 0) {
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ float fcol = col;
+ float tx1 = xoffset + (-gridSize / 2.f) + (fcol * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ drawQuad(tx1, ty1, z,
+ tx2, ty1, z,
+ tx2, ty2, z,
+ tx1, ty2, z);
+ }
+ index++;
+ }
+ }
+
+ // bottom roller
+ {
+ float roll = (1.f - yoffset) * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty2 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing);
+ float ty1 = ty2 - tmpCos * iconSize;
+
+ float tz1 = z + tmpSin * iconSize;
+ float tz2 = z;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+ // Top roller
+ {
+ index = (((int)pos) * 4) - 4;
+ float roll = yoffset * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty1 = (gridSize / 2.f) - ((float)-1.f - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + tmpCos * iconSize;
+
+ float tz1 = z;
+ float tz2 = z + tmpSin * iconSize;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+
+
+
+ return 1;
}
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
index 8f48335..520e3e4 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -18,6 +18,7 @@
import java.io.Writer;
+import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;
import android.renderscript.ProgramVertexAlloc;
@@ -25,8 +26,11 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.Typeface;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
@@ -56,6 +60,8 @@
public void init(RenderScript rs, Resources res, int width, int height) {
mRS = rs;
mRes = res;
+ mWidth = width;
+ mHeight = height;
initNamed();
initRS();
}
@@ -78,25 +84,34 @@
}
public void setSelected(int index) {
- Log.e("rs", "setSelected " + Integer.toString(index));
+ //Log.e("rs", "setSelected " + Integer.toString(index));
mAllocStateBuf[STATE_SELECTION] = index;
mAllocStateBuf[STATE_DONE] = 1;
mAllocState.data(mAllocStateBuf);
}
+ private int mWidth;
+ private int mHeight;
private Resources mRes;
private RenderScript mRS;
private RenderScript.Script mScript;
private RenderScript.Sampler mSampler;
+ private RenderScript.Sampler mSamplerText;
private RenderScript.ProgramFragmentStore mPFSBackground;
+ private RenderScript.ProgramFragmentStore mPFSText;
private RenderScript.ProgramFragment mPFBackground;
private RenderScript.ProgramFragment mPFImages;
+ private RenderScript.ProgramFragment mPFText;
private RenderScript.ProgramVertex mPV;
private ProgramVertexAlloc mPVAlloc;
+ private RenderScript.ProgramVertex mPVOrtho;
+ private ProgramVertexAlloc mPVOrthoAlloc;
private RenderScript.Allocation[] mIcons;
+ private RenderScript.Allocation[] mLabels;
private RenderScript.Allocation mIconPlate;
+ private RenderScript.Allocation mBackground;
private int[] mAllocStateBuf;
private RenderScript.Allocation mAllocState;
@@ -104,6 +119,9 @@
private int[] mAllocIconIDBuf;
private RenderScript.Allocation mAllocIconID;
+ private int[] mAllocLabelIDBuf;
+ private RenderScript.Allocation mAllocLabelID;
+
private int[] mAllocScratchBuf;
private RenderScript.Allocation mAllocScratch;
@@ -119,6 +137,17 @@
RenderScript.SamplerValue.CLAMP);
mSampler = mRS.samplerCreate();
+ mRS.samplerBegin();
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MIN,
+ RenderScript.SamplerValue.NEAREST);
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MAG,
+ RenderScript.SamplerValue.NEAREST);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_S,
+ RenderScript.SamplerValue.CLAMP);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_T,
+ RenderScript.SamplerValue.CLAMP);
+ mSamplerText = mRS.samplerCreate();
+
mRS.programFragmentBegin(null, null);
mRS.programFragmentSetTexEnable(0, true);
@@ -127,26 +156,47 @@
mPFImages.setName("PF");
mPFImages.bindSampler(mSampler, 0);
+ mRS.programFragmentBegin(null, null);
+ mRS.programFragmentSetTexEnable(0, true);
+ mRS.programFragmentSetTexEnvMode(0, RenderScript.EnvMode.MODULATE);
+ mPFText = mRS.programFragmentCreate();
+ mPFText.setName("PFText");
+ mPFText.bindSampler(mSamplerText, 0);
+
mRS.programFragmentStoreBegin(null, null);
mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.LESS);
mRS.programFragmentStoreDitherEnable(false);
- mRS.programFragmentStoreDepthMask(false);
- mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
- RenderScript.BlendDstFunc.ONE);
+ mRS.programFragmentStoreDepthMask(true);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA,
+ RenderScript.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
mPFSBackground = mRS.programFragmentStoreCreate();
mPFSBackground.setName("PFS");
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.ALWAYS);
+ mRS.programFragmentStoreDitherEnable(false);
+ mRS.programFragmentStoreDepthMask(false);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA,
+ RenderScript.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ mPFSText = mRS.programFragmentStoreCreate();
+ mPFSText.setName("PFSText");
+
mPVAlloc = new ProgramVertexAlloc(mRS);
mRS.programVertexBegin(null, null);
- mRS.programVertexSetTextureMatrixEnable(true);
+ mRS.programVertexSetTextureMatrixEnable(false);
mPV = mRS.programVertexCreate();
mPV.setName("PV");
mPV.bindAllocation(0, mPVAlloc.mAlloc);
+ mPVAlloc.setupProjectionNormalized(mWidth, mHeight);
+ mPVOrthoAlloc = new ProgramVertexAlloc(mRS);
+ mRS.programVertexBegin(null, null);
+ mRS.programVertexSetTextureMatrixEnable(true);
+ mPVOrtho = mRS.programVertexCreate();
+ mPVOrtho.setName("PVOrtho");
+ mPVOrtho.bindAllocation(0, mPVOrthoAlloc.mAlloc);
+ mPVOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
-
- mPVAlloc.setupProjectionNormalized(320, 480);
- //mPVAlloc.setupOrthoNormalized(320, 480);
mRS.contextBindProgramVertex(mPV);
mAllocScratchBuf = new int[32];
@@ -162,33 +212,175 @@
{
- mIcons = new RenderScript.Allocation[4];
+ mIcons = new RenderScript.Allocation[29];
mAllocIconIDBuf = new int[mIcons.length];
mAllocIconID = mRS.allocationCreatePredefSized(
RenderScript.ElementPredefined.USER_I32, mAllocIconIDBuf.length);
-
+ mLabels = new RenderScript.Allocation[29];
+ mAllocLabelIDBuf = new int[mLabels.length];
+ mAllocLabelID = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_I32, mLabels.length);
+
+
Bitmap b;
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;
+ b = BitmapFactory.decodeResource(mRes, R.raw.cf_background, opts);
+ mBackground = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mBackground.setName("TexBk");
+
+
b = BitmapFactory.decodeResource(mRes, R.raw.browser, opts);
- mIcons[0] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mIcons[0] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGBA_8888, true);
+ mLabels[0] = makeTextBitmap("browser");
b = BitmapFactory.decodeResource(mRes, R.raw.market, opts);
- mIcons[1] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mIcons[1] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGBA_8888, true);
+ mLabels[1] = makeTextBitmap("market");
b = BitmapFactory.decodeResource(mRes, R.raw.photos, opts);
- mIcons[2] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mIcons[2] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGBA_8888, true);
+ mLabels[2] = makeTextBitmap("photos");
b = BitmapFactory.decodeResource(mRes, R.raw.settings, opts);
- mIcons[3] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mIcons[3] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGBA_8888, true);
+ mLabels[3] = makeTextBitmap("settings");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.calendar, opts);
+ mIcons[4] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[4] = makeTextBitmap("creed");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.g1155, opts);
+ mIcons[5] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[5] = makeTextBitmap("BOA");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.g2140, opts);
+ mIcons[6] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[6] = makeTextBitmap("chess");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.maps, opts);
+ mIcons[7] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[7] = makeTextBitmap("Dictionary");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path431, opts);
+ mIcons[8] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[8] = makeTextBitmap("facebook");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path676, opts);
+ mIcons[9] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[9] = makeTextBitmap("Flash Light");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path754, opts);
+ mIcons[10] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[10] = makeTextBitmap("Flight Control");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path815, opts);
+ mIcons[11] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[11] = makeTextBitmap("google earth");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path1920, opts);
+ mIcons[12] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[12] = makeTextBitmap("Harry Potter");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path1927, opts);
+ mIcons[13] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[13] = makeTextBitmap("Movies");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path3099, opts);
+ mIcons[14] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[14] = makeTextBitmap("NY Times");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path3950, opts);
+ mIcons[15] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[15] = makeTextBitmap("Pandora");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path4481, opts);
+ mIcons[16] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[16] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.path5168, opts);
+ mIcons[17] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[17] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.polygon2408, opts);
+ mIcons[18] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[18] = makeTextBitmap("Public Radio");
+
+ /*
+ b = BitmapFactory.decodeResource(mRes, R.raw.solitaire, opts);
+ mIcons[19] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[19] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.sudoku, opts);
+ mIcons[20] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[20] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.taptaprevenge, opts);
+ mIcons[21] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[21] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.tetris, opts);
+ mIcons[22] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[22] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.tictactoe, opts);
+ mIcons[23] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[23] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.tweetie, opts);
+ mIcons[24] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[24] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.urbanspoon, opts);
+ mIcons[25] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[25] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.waterslide_extreme, opts);
+ mIcons[26] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[26] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.weather_channel, opts);
+ mIcons[27] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[27] = makeTextBitmap("Public Radio");
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.zippo, opts);
+ mIcons[28] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mLabels[28] = makeTextBitmap("Public Radio");
+*/
+
+ mIcons[19] = mIcons[0];
+ mIcons[20] = mIcons[1];
+ mIcons[21] = mIcons[2];
+ mIcons[22] = mIcons[3];
+ mIcons[23] = mIcons[2];
+ mIcons[24] = mIcons[1];
+ mIcons[25] = mIcons[0];
+ mIcons[26] = mIcons[1];
+ mIcons[27] = mIcons[2];
+ mIcons[28] = mIcons[3];
+
+ mLabels[19] = mLabels[0];
+ mLabels[20] = mLabels[1];
+ mLabels[21] = mLabels[2];
+ mLabels[22] = mLabels[3];
+ mLabels[23] = mLabels[2];
+ mLabels[24] = mLabels[1];
+ mLabels[25] = mLabels[0];
+ mLabels[26] = mLabels[1];
+ mLabels[27] = mLabels[2];
+ mLabels[28] = mLabels[3];
+
for(int ct=0; ct < mIcons.length; ct++) {
mIcons[ct].uploadToTexture(0);
+ mLabels[ct].uploadToTexture(0);
mAllocIconIDBuf[ct] = mIcons[ct].getID();
+ mAllocLabelIDBuf[ct] = mLabels[ct].getID();
}
mAllocIconID.data(mAllocIconIDBuf);
+ mAllocLabelID.data(mAllocLabelIDBuf);
RenderScript.Element e = mRS.elementGetPredefined(RenderScript.ElementPredefined.RGB_565);
mRS.typeBegin(e);
@@ -221,6 +413,16 @@
}
+ RenderScript.Allocation makeTextBitmap(String t) {
+ Bitmap b = Bitmap.createBitmap(128, 32, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ Paint p = new Paint();
+ p.setTypeface(Typeface.DEFAULT_BOLD);
+ p.setTextSize(16);
+ p.setColor(0xffffffff);
+ c.drawText(t, 2, 20, p);
+ return mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGBA_8888, true);
+ }
private void initRS() {
@@ -232,12 +434,13 @@
//mRS.scriptCSetClearDepth(0);
mScript = mRS.scriptCCreate();
- mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, 0, 0, 38, 0, 0};
+ mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
mAllocState = mRS.allocationCreatePredefSized(
RenderScript.ElementPredefined.USER_I32, mAllocStateBuf.length);
mScript.bindAllocation(mAllocState, 0);
mScript.bindAllocation(mAllocIconID, 1);
mScript.bindAllocation(mAllocScratch, 2);
+ mScript.bindAllocation(mAllocLabelID, 3);
setPosition(0);
setZoom(1);
@@ -248,4 +451,3 @@
}
-
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
index b5e02af..71d6c7e 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -76,7 +76,7 @@
float mOldColumn;
float mZoom = 1;
- int mIconCount = 38;
+ int mIconCount = 29;
int mRows = 4;
int mColumns = (mIconCount + mRows - 1) / mRows;
@@ -90,8 +90,8 @@
if(c > (mColumns -2)) {
c = (mColumns -2);
}
- if(c < 1) {
- c = 1;
+ if(c < 0) {
+ c = 0;
}
mRender.setPosition(c);
if(clamp) {
@@ -101,11 +101,11 @@
void computeSelection(float x, float y)
{
- float col = mColumn + (x - 0.5f) * 3;
+ float col = mColumn + (x - 0.5f) * 4 + 1.25f;
int iCol = (int)(col + 0.25f);
float row = (y / 0.8f) * mRows;
- int iRow = (int)(row - 0.25f);
+ int iRow = (int)(row - 0.5f);
mRender.setSelected(iCol * mRows + iRow);
}
@@ -122,6 +122,9 @@
float nx = ev.getX() / getWidth();
float ny = ev.getY() / getHeight();
+ //Log.e("rs", "width=" + Float.toString(getWidth()));
+ //Log.e("rs", "height=" + Float.toString(getHeight()));
+
mRender.setTouch(ret);
if((ny > 0.85f) || mControlMode) {
@@ -158,13 +161,14 @@
mZoom = zoom;
mFlingX = nx;
mRender.setZoom(zoom);
- } else {
- if(mControlMode && (mZoom < 1.01f)) {
+ if(mZoom < 1.01f) {
computeSelection(nx, ny);
}
+ } else {
mControlMode = false;
mColumn = mOldColumn;
mRender.setZoom(1.f);
+ mRender.setSelected(-1);
}
} else {
// Do something with corners here....
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 2f99808..45e6d1b 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -99,6 +99,16 @@
ret RsAllocation
}
+AllocationCreateFromBitmapBoxed {
+ param uint32_t width
+ param uint32_t height
+ param RsElementPredefined dstFmt
+ param RsElementPredefined srcFmt
+ param bool genMips
+ param const void * data
+ ret RsAllocation
+ }
+
AllocationUploadToTexture {
param RsAllocation alloc
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index c143307..c6a9149 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -204,12 +204,12 @@
uint32_t w = out.getDimX();
uint32_t h = out.getDimY();
- for (uint32_t y=0; y < w; y++) {
+ for (uint32_t y=0; y < h; y++) {
uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
- for (uint32_t x=0; x < h; x++) {
+ for (uint32_t x=0; x < w; x++) {
*oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
oPtr ++;
i1 += 2;
@@ -223,21 +223,33 @@
uint32_t w = out.getDimX();
uint32_t h = out.getDimY();
- for (uint32_t y=0; y < w; y++) {
+ for (uint32_t y=0; y < h; y++) {
uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
- for (uint32_t x=0; x < h; x++) {
+ for (uint32_t x=0; x < w; x++) {
*oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
oPtr ++;
i1 += 2;
i2 += 2;
}
}
-
}
+static void mip(const Adapter2D &out, const Adapter2D &in)
+{
+ switch(out.getBaseType()->getElement()->getSizeBits()) {
+ case 32:
+ mip8888(out, in);
+ break;
+ case 16:
+ mip565(out, in);
+ break;
+
+ }
+
+}
typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
@@ -301,14 +313,18 @@
return elementConverter_cpy_32;
}
- LOGE("pickConverter, unsuported combo");
+ LOGE("pickConverter, unsuported combo, src %i, dst %i", srcFmt, dstFmt);
return 0;
}
RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
{
- rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ rsAssert(!(w & (w-1)));
+ rsAssert(!(h & (h-1)));
+
+ //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, dstFmt));
rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
if (genMips) {
@@ -333,13 +349,49 @@
for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
adapt.setLOD(lod);
adapt2.setLOD(lod + 1);
- mip565(adapt2, adapt);
+ mip(adapt2, adapt);
}
}
return texAlloc;
}
+static uint32_t fmtToBits(RsElementPredefined fmt)
+{
+ return 16;
+}
+
+RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ uint32_t w2 = rsHigherPow2(w);
+ uint32_t h2 = rsHigherPow2(h);
+
+ if ((w2 == w) && (h2 == h)) {
+ return rsi_AllocationCreateFromBitmap(rsc, w, h, dstFmt, srcFmt, genMips, data);
+ }
+
+ uint32_t bpp = fmtToBits(srcFmt) >> 3;
+ size_t size = w2 * h2 * bpp;
+ uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
+ memset(tmp, 0, size);
+
+ const uint8_t * src = static_cast<const uint8_t *>(data);
+ for (uint32_t y = 0; y < h; y++) {
+ uint8_t * ydst = &tmp[y + ((h2 - h) >> 1)];
+ memcpy(&ydst[(w2 - w) >> 1], src, w * bpp);
+ src += h * bpp;
+ }
+
+ RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, dstFmt, srcFmt, genMips, tmp);
+ free(tmp);
+ return ret;
+
+
+
+
+}
+
+
RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips)
{
bool use32bpp = false;
@@ -442,11 +494,7 @@
for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
adapt.setLOD(lod);
adapt2.setLOD(lod + 1);
- if (use32bpp) {
- mip8888(adapt2, adapt);
- } else {
- mip565(adapt2, adapt);
- }
+ mip(adapt2, adapt);
}
}
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 78b8bf8..e52b0e0 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -79,8 +79,7 @@
mFragment.set(frag);
mVertex.set(vtx);
mFragmentStore.set(store);
- return true;
-
+ return ret;
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 497dbcf..a00b8e8 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -83,6 +83,7 @@
const ProgramFragment * getFragment() {return mFragment.get();}
const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+ const ProgramVertex * getVertex() {return mVertex.get();}
void setupCheck();
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 417ba6a..792135d 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -55,8 +55,6 @@
glLoadIdentity();
}
-
- LOGE("lights %i ", mLightCount);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (mLightCount) {
@@ -103,6 +101,25 @@
}
}
+void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+
ProgramVertexState::ProgramVertexState()
{
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index ac15b70..da5ed81 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -41,6 +41,10 @@
void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
void addLight(const Light *);
+ void setProjectionMatrix(const rsc_Matrix *) const;
+ void setModelviewMatrix(const rsc_Matrix *) const;
+ void setTextureMatrix(const rsc_Matrix *) const;
+
protected:
bool mDirty;
uint32_t mLightCount;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 129b19f..41219064 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -135,7 +135,6 @@
-
//////////////////////////////////////////////////////////////////////////////
// Matrix routines
//////////////////////////////////////////////////////////////////////////////
@@ -257,6 +256,24 @@
}
//////////////////////////////////////////////////////////////////////////////
+// VP
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setModelviewMatrix(m);
+}
+
+static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setTextureMatrix(m);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
// Drawing
//////////////////////////////////////////////////////////////////////////////
@@ -339,24 +356,25 @@
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
+static void SC_drawRect(float x1, float y1,
+ float x2, float y2, float z)
+{
+ SC_drawQuad(x1, y2, z,
+ x2, y2, z,
+ x2, y1, z,
+ x1, y1, z);
+}
+
//////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////
-extern "C" const void * loadVp(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- return &static_cast<const uint8_t *>(sc->mSlots[bank]->getPtr())[offset];
-}
-
-
-
static void SC_color(float r, float g, float b, float a)
{
glColor4f(r, g, b, a);
}
-
+/*
extern "C" void materialDiffuse(float r, float g, float b, float a)
{
float v[] = {r, g, b, a};
@@ -369,35 +387,18 @@
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
}
-extern "C" void lightPosition(float x, float y, float z, float w)
-{
- float v[] = {x, y, z, w};
- glLightfv(GL_LIGHT0, GL_POSITION, v);
-}
-
extern "C" void materialShininess(float s)
{
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
}
+*/
-extern "C" void uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
{
GET_TLS();
rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
}
-extern "C" void enable(uint32_t p)
-{
- glEnable(p);
-}
-
-extern "C" void disable(uint32_t p)
-{
- glDisable(p);
-}
-
-
-
static void SC_ClearColor(float r, float g, float b, float a)
{
//LOGE("c %f %f %f %f", r, g, b, a);
@@ -408,6 +409,16 @@
sc->mEnviroment.mClearColor[3] = a;
}
+static void SC_debugF(const char *s, float f)
+{
+ LOGE("%s %f", s, f);
+}
+
+static void SC_debugI32(const char *s, int32_t i)
+{
+ LOGE("%s %i", s, i);
+}
+
//////////////////////////////////////////////////////////////////////////////
@@ -440,10 +451,14 @@
"float", "(float)" },
{ "cosf", (void *)&cosf,
"float", "(float)" },
- { "fabs", (void *)&fabs,
+ { "fabsf", (void *)&fabsf,
"float", "(float)" },
{ "randf", (void *)&SC_randf,
"float", "(float)" },
+ { "floorf", (void *)&floorf,
+ "float", "(float)" },
+ { "ceilf", (void *)&ceilf,
+ "float", "(float)" },
// matrix
{ "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
@@ -481,7 +496,17 @@
{ "bindTexture", (void *)&SC_bindTexture,
"void", "(int, int, int)" },
+ // vp
+ { "vpLoadModelMatrix", (void *)&SC_bindProgramFragment,
+ "void", "(void *)" },
+ { "vpLoadTextureMatrix", (void *)&SC_bindProgramFragmentStore,
+ "void", "(void *)" },
+
+
+
// drawing
+ { "drawRect", (void *)&SC_drawRect,
+ "void", "(float x1, float y1, float x2, float y2, float z)" },
{ "drawQuad", (void *)&SC_drawQuad,
"void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
{ "drawTriangleArray", (void *)&SC_drawTriangleArray,
@@ -495,10 +520,19 @@
// misc
{ "pfClearColor", (void *)&SC_ClearColor,
"void", "(float, float, float, float)" },
-
{ "color", (void *)&SC_color,
"void", "(float, float, float, float)" },
+ { "uploadToTexture", (void *)&SC_uploadToTexture,
+ "void", "(int, int)" },
+
+
+ { "debugF", (void *)&SC_debugF,
+ "void", "(void *, float)" },
+ { "debugI32", (void *)&SC_debugI32,
+ "void", "(void *, int)" },
+
+
{ NULL, NULL, NULL, NULL }
};
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 9fffbbf..ff49c87 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -177,22 +177,17 @@
sp<Buffer> LayerBitmap::allocate()
{
Mutex::Autolock _l(mLock);
- sp<Buffer> buffer(mBuffer);
- const uint32_t w = mWidth;
- const uint32_t h = mHeight;
- if (buffer!=0 && (w != buffer->getWidth() || h != buffer->getHeight())) {
- surface_info_t* info = mInfo;
- buffer = new Buffer(w, h, mFormat, mFlags);
- status_t err = buffer->initCheck();
- if (LIKELY(err == NO_ERROR)) {
- info->flags = surface_info_t::eBufferDirty;
- info->status = NO_ERROR;
- } else {
- memset(info, 0, sizeof(surface_info_t));
- info->status = NO_MEMORY;
- }
- mBuffer = buffer;
+ surface_info_t* info = mInfo;
+ sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, mFlags);
+ status_t err = buffer->initCheck();
+ if (LIKELY(err == NO_ERROR)) {
+ info->flags = surface_info_t::eBufferDirty;
+ info->status = NO_ERROR;
+ } else {
+ memset(info, 0, sizeof(surface_info_t));
+ info->status = NO_MEMORY;
}
+ mBuffer = buffer;
return buffer;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 7a7574f..102899c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -650,6 +650,7 @@
if (currentLayers.indexOf( layer ) < 0) {
// this layer is not visible anymore
ditchedLayers.add(layer);
+ mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
}
}
}
@@ -685,17 +686,15 @@
layer->validateVisibility(planeTransform);
// start with the whole surface at its current location
- const Layer::State& s = layer->drawingState();
- const Rect bounds(layer->visibleBounds());
+ const Layer::State& s(layer->drawingState());
// handle hidden surfaces by setting the visible region to empty
Region opaqueRegion;
Region visibleRegion;
Region coveredRegion;
- if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) {
- visibleRegion.clear();
- } else {
+ if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
const bool translucent = layer->needsBlending();
+ const Rect bounds(layer->visibleBounds());
visibleRegion.set(bounds);
coveredRegion = visibleRegion;
@@ -742,12 +741,16 @@
layer->setVisibleRegion(visibleRegion);
layer->setCoveredRegion(coveredRegion);
- // If a secure layer is partially visible, lock down the screen!
+ // If a secure layer is partially visible, lock-down the screen!
if (layer->isSecure() && !visibleRegion.isEmpty()) {
secureFrameBuffer = true;
}
}
+ // invalidate the areas where a layer was removed
+ dirtyRegion.orSelf(mDirtyRegionRemovedLayer);
+ mDirtyRegionRemovedLayer.clear();
+
mSecureFrameBuffer = secureFrameBuffer;
opaqueRegion = aboveOpaqueLayers;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index e8687a7..2569a0f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -334,6 +334,7 @@
// Can only accessed from the main thread, these members
// don't need synchronization
Region mDirtyRegion;
+ Region mDirtyRegionRemovedLayer;
Region mInvalidRegion;
Region mWormholeRegion;
wp<Client> mLastScheduledBroadcast;
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index be04777..c51d989 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -196,6 +196,7 @@
} else { \
m_status = errno; \
} \
+ LOGD("CHECK_SIZE failed with at line %d m_status='%s'", __LINE__, strerror(m_status)); \
return m_status; \
} \
} while(0)
@@ -203,6 +204,7 @@
do { \
status_t err = skip_padding(); \
if (err != NO_ERROR) { \
+ LOGD("SKIP_PADDING FAILED at line %d", __LINE__); \
m_status = err; \
return err; \
} \
@@ -218,10 +220,19 @@
int amt;
- // No error checking here, in case we're at the end of the stream. Just let read() fail.
- skip_padding();
+ amt = skip_padding();
+ if (amt == EIO) {
+ *done = true;
+ return NO_ERROR;
+ }
+ else if (amt != NO_ERROR) {
+ return amt;
+ }
amt = read(m_fd, &m_header, sizeof(m_header));
*done = m_done = (amt == 0);
+ if (*done) {
+ return NO_ERROR;
+ }
CHECK_SIZE(amt, sizeof(m_header));
m_pos += sizeof(m_header);
if (type) {
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 9e1a72c..aaac192 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -197,6 +197,10 @@
// properties loaded from PROPERTIES_FILE
private Properties mProperties;
private String mNtpServer;
+ private String mSuplServerHost;
+ private int mSuplServerPort;
+ private String mC2KServerHost;
+ private int mC2KServerPort;
private final Context mContext;
private final ILocationManager mLocationManager;
@@ -348,23 +352,21 @@
stream.close();
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
- String host = mProperties.getProperty("SUPL_HOST");
+ mSuplServerHost = mProperties.getProperty("SUPL_HOST");
String portString = mProperties.getProperty("SUPL_PORT");
- if (host != null && portString != null) {
+ if (mSuplServerHost != null && portString != null) {
try {
- int port = Integer.parseInt(portString);
- native_set_agps_server(AGPS_TYPE_SUPL, host, port);
+ mSuplServerPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
}
}
- host = mProperties.getProperty("C2K_HOST");
+ mC2KServerHost = mProperties.getProperty("C2K_HOST");
portString = mProperties.getProperty("C2K_PORT");
- if (host != null && portString != null) {
+ if (mC2KServerHost != null && portString != null) {
try {
- int port = Integer.parseInt(portString);
- native_set_agps_server(AGPS_TYPE_C2K, host, port);
+ mC2KServerPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse C2K_PORT: " + portString);
}
@@ -494,6 +496,13 @@
mEnabled = native_init();
if (mEnabled) {
+ if (mSuplServerHost != null) {
+ native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+ }
+ if (mC2KServerHost != null) {
+ native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
+ }
+
// run event listener thread while we are enabled
mEventThread = new GpsEventThread();
mEventThread.start();
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 040d4bc..60fc0e0 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -649,10 +649,11 @@
* <var>false</var> to turn it off
*/
public void setSpeakerphoneOn(boolean on){
- if (on) {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
- } else {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ IAudioService service = getService();
+ try {
+ service.setSpeakerphoneOn(on);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setSpeakerphoneOn", e);
}
}
@@ -662,9 +663,11 @@
* @return true if speakerphone is on, false if it's off
*/
public boolean isSpeakerphoneOn() {
- if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_SPEAKER) {
- return true;
- } else {
+ IAudioService service = getService();
+ try {
+ return service.isSpeakerphoneOn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isSpeakerphoneOn", e);
return false;
}
}
@@ -676,10 +679,11 @@
* <var>false</var> to not use bluetooth SCO for communications
*/
public void setBluetoothScoOn(boolean on){
- if (on) {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
- } else {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ IAudioService service = getService();
+ try {
+ service.setBluetoothScoOn(on);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setBluetoothScoOn", e);
}
}
@@ -690,9 +694,11 @@
* false if otherwise
*/
public boolean isBluetoothScoOn() {
- if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) {
- return true;
- } else {
+ IAudioService service = getService();
+ try {
+ return service.isBluetoothScoOn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isBluetoothScoOn", e);
return false;
}
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 30640c3..1f9e3af 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -47,7 +47,10 @@
import java.io.IOException;
import java.util.ArrayList;
-
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
/**
* The implementation of the volume manager service.
@@ -210,6 +213,12 @@
private int mHeadsetState;
+ // Devices currently connected
+ private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+
+ // Forced device usage for communications
+ private int mForcedUseForComm;
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -220,7 +229,9 @@
mContentResolver = context.getContentResolver();
mVolumePanel = new VolumePanel(context, this);
mSettingsObserver = new SettingsObserver();
-
+ mMode = AudioSystem.MODE_NORMAL;
+ mHeadsetState = 0;
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
createAudioSystemThread();
readPersistedSettings();
createStreamStates();
@@ -721,6 +732,46 @@
setRingerModeInt(getRingerMode(), false);
}
+ /** @see AudioManager#setSpeakerphoneOn() */
+ public void setSpeakerphoneOn(boolean on){
+ if (on) {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
+ mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+ } else {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+
+ /** @see AudioManager#isSpeakerphoneOn() */
+ public boolean isSpeakerphoneOn() {
+ if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /** @see AudioManager#setBluetoothScoOn() */
+ public void setBluetoothScoOn(boolean on){
+ if (on) {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
+ mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+ } else {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+
+ /** @see AudioManager#isBluetoothScoOn() */
+ public boolean isBluetoothScoOn() {
+ if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Internal methods
///////////////////////////////////////////////////////////////////////////
@@ -1188,16 +1239,33 @@
Log.e(TAG, "Media server died.");
// Force creation of new IAudioflinger interface
mMediaServerOk = false;
- AudioSystem.getMode();
+ AudioSystem.isMusicActive();
break;
case MSG_MEDIA_SERVER_STARTED:
Log.e(TAG, "Media server started.");
+ // Restore device connection states
+ Set set = mConnectedDevices.entrySet();
+ Iterator i = set.iterator();
+ while(i.hasNext()){
+ Map.Entry device = (Map.Entry)i.next();
+ AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ (String)device.getValue());
+ }
+
+ // Restore call state
+ AudioSystem.setPhoneState(mMode);
+
+ // Restore forced usage for communcations
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
+
// Restore stream volumes
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
int index;
VolumeStreamState streamState = mStreamStates[streamType];
+ AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
if (streamState.muteCount() == 0) {
index = streamState.mIndex;
} else {
@@ -1205,7 +1273,10 @@
}
setStreamVolumeIndex(streamType, index);
}
- setRingerMode(mRingerMode);
+
+ // Restore ringer mode
+ setRingerModeInt(getRingerMode(), false);
+
mMediaServerOk = true;
break;
@@ -1276,10 +1347,12 @@
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
address);
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
} else if (state == BluetoothA2dp.STATE_CONNECTED){
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE,
address);
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address);
}
} else if (action.equals(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothIntent.HEADSET_AUDIO_STATE,
@@ -1289,10 +1362,12 @@
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
address);
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
} else if (state == BluetoothHeadset.AUDIO_STATE_CONNECTED) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
AudioSystem.DEVICE_STATE_AVAILABLE,
address);
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO), address);
}
} else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", 0);
@@ -1301,55 +1376,65 @@
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
"");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
} else if ((state & BIT_HEADSET) != 0 &&
(mHeadsetState & BIT_HEADSET) == 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
AudioSystem.DEVICE_STATE_AVAILABLE,
"");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), "");
}
if ((state & BIT_HEADSET_NO_MIC) == 0 &&
(mHeadsetState & BIT_HEADSET_NO_MIC) != 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
"");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
} else if ((state & BIT_HEADSET_NO_MIC) != 0 &&
(mHeadsetState & BIT_HEADSET_NO_MIC) == 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
AudioSystem.DEVICE_STATE_AVAILABLE,
"");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
}
if ((state & BIT_TTY) == 0 &&
(mHeadsetState & BIT_TTY) != 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
"");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_TTY);
} else if ((state & BIT_TTY) != 0 &&
(mHeadsetState & BIT_TTY) == 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
AudioSystem.DEVICE_STATE_AVAILABLE,
"");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_TTY), "");
}
if ((state & BIT_FM_HEADSET) == 0 &&
(mHeadsetState & BIT_FM_HEADSET) != 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
"");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_HEADPHONE);
} else if ((state & BIT_FM_HEADSET) != 0 &&
(mHeadsetState & BIT_FM_HEADSET) == 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
AudioSystem.DEVICE_STATE_AVAILABLE,
"");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_HEADPHONE), "");
}
if ((state & BIT_FM_SPEAKER) == 0 &&
(mHeadsetState & BIT_FM_SPEAKER) != 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
"");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_SPEAKER);
} else if ((state & BIT_FM_SPEAKER) != 0 &&
(mHeadsetState & BIT_FM_SPEAKER) == 0) {
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
AudioSystem.DEVICE_STATE_AVAILABLE,
"");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_SPEAKER), "");
}
mHeadsetState = state;
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index bb4252b..d3d2d29 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -60,4 +60,12 @@
oneway void unloadSoundEffects();
oneway void reloadAudioSettings();
+
+ void setSpeakerphoneOn(boolean on);
+
+ boolean isSpeakerphoneOn();
+
+ void setBluetoothScoOn(boolean on);
+
+ boolean isBluetoothScoOn();
}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 44026e4..8481410 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -605,21 +605,6 @@
Log.e(TAG, "Failed to open ringtone " + ringtoneUri);
}
- // Ringtone doesn't exist, use the fallback ringtone.
- try {
- AssetFileDescriptor afd = context.getResources().openRawResourceFd(
- com.android.internal.R.raw.fallbackring);
- if (afd != null) {
- Ringtone r = new Ringtone(context);
- r.open(afd);
- afd.close();
- return r;
- }
- } catch (Exception ex) {
- }
-
- // we should never get here
- Log.e(TAG, "unable to find a usable ringtone");
return null;
}
@@ -638,8 +623,8 @@
public static Uri getActualDefaultRingtoneUri(Context context, int type) {
String setting = getSettingForType(type);
if (setting == null) return null;
- final String uriString = Settings.System.getString(context.getContentResolver(), setting);
- return uriString != null ? Uri.parse(uriString) : getValidRingtoneUri(context);
+ final String uriString = Settings.System.getString(context.getContentResolver(), setting);
+ return uriString != null ? Uri.parse(uriString) : null;
}
/**
@@ -655,7 +640,8 @@
public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
String setting = getSettingForType(type);
if (setting == null) return;
- Settings.System.putString(context.getContentResolver(), setting, ringtoneUri.toString());
+ Settings.System.putString(context.getContentResolver(), setting,
+ ringtoneUri != null ? ringtoneUri.toString() : null);
}
private static String getSettingForType(int type) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1d960c5..95d61cd 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -59,6 +59,8 @@
#include <media/PVPlayer.h>
#include "TestPlayerStub.h"
+//#undef USE_STAGEFRIGHT
+
#if USE_STAGEFRIGHT
#include "StagefrightPlayer.h"
#endif
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5944d9c..5be9224 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -26,6 +26,7 @@
SurfaceRenderer.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
+ TIHardwareRenderer.cpp \
Utils.cpp \
AudioPlayer.cpp \
ESDS.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 17c72b9..d547556 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -87,7 +87,10 @@
} else {
mAudioTrack = new AudioTrack(
AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
- numChannels, 8192, 0, &AudioCallback, this, 0);
+ (numChannels == 2)
+ ? AudioSystem::CHANNEL_OUT_STEREO
+ : AudioSystem::CHANNEL_OUT_MONO,
+ 8192, 0, &AudioCallback, this, 0);
assert(mAudioTrack->initCheck() == OK);
@@ -217,8 +220,10 @@
Mutex::Autolock autoLock(mLock);
mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
mPositionTimeRealUs =
- ((mNumFramesPlayed + size_done / 4) * 1000000) / mSampleRate; // XXX
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
}
if (mInputBuffer->range_length() == 0) {
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 6b47a38..01cb2d9 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -73,8 +73,6 @@
if (bitrate_index == 0 || bitrate_index == 0x0f) {
// Disallow "free" bitrate.
-
- LOGE("We disallow 'free' bitrate for now.");
return false;
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index caaec06..4c883c6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -73,6 +73,8 @@
bool mNeedsNALFraming;
+ uint8_t *mSrcBuffer;
+
MPEG4Source(const MPEG4Source &);
MPEG4Source &operator=(const MPEG4Source &);
};
@@ -743,7 +745,8 @@
mBuffer(NULL),
mBufferOffset(0),
mBufferSizeRemaining(0),
- mNeedsNALFraming(false) {
+ mNeedsNALFraming(false),
+ mSrcBuffer(NULL) {
const char *mime;
bool success = mFormat->findCString(kKeyMIMEType, &mime);
assert(success);
@@ -777,8 +780,13 @@
status_t err = mSampleTable->getMaxSampleSize(&max_size);
assert(err == OK);
- // Add padding for de-framing of AVC content just in case.
- mGroup->add_buffer(new MediaBuffer(max_size + 2));
+ // Assume that a given buffer only contains at most 10 fragments,
+ // each fragment originally prefixed with a 2 byte length will
+ // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+ // and thus will grow by 2 bytes per fragment.
+ mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+ mSrcBuffer = new uint8_t[max_size];
mStarted = true;
@@ -793,6 +801,9 @@
mBuffer = NULL;
}
+ delete[] mSrcBuffer;
+ mSrcBuffer = NULL;
+
delete mGroup;
mGroup = NULL;
@@ -832,33 +843,31 @@
// fall through
}
- if (mBuffer == NULL) {
- off_t offset;
- size_t size;
- status_t err = mSampleTable->getSampleOffsetAndSize(
- mCurrentSampleIndex, &offset, &size);
+ off_t offset;
+ size_t size;
+ status_t err = mSampleTable->getSampleOffsetAndSize(
+ mCurrentSampleIndex, &offset, &size);
- if (err != OK) {
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
- uint32_t dts;
- err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+ uint32_t dts;
+ err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
- if (err != OK) {
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
- err = mGroup->acquire_buffer(&mBuffer);
- if (err != OK) {
- assert(mBuffer == NULL);
- return err;
- }
+ err = mGroup->acquire_buffer(&mBuffer);
+ if (err != OK) {
+ assert(mBuffer == NULL);
+ return err;
+ }
- assert(mBuffer->size() + 2 >= size);
-
+ if (!mIsAVC || !mNeedsNALFraming) {
ssize_t num_bytes_read =
- mDataSource->read_at(offset, (uint8_t *)mBuffer->data() + 2, size);
+ mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
@@ -867,50 +876,62 @@
return err;
}
- mBuffer->set_range(2, size);
+ mBuffer->set_range(0, size);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
-
++mCurrentSampleIndex;
- mBufferOffset = 2;
- mBufferSizeRemaining = size;
- }
-
- if (!mIsAVC) {
*out = mBuffer;
mBuffer = NULL;
return OK;
}
- uint8_t *data = (uint8_t *)mBuffer->data() + mBufferOffset;
- assert(mBufferSizeRemaining >= 2);
+ ssize_t num_bytes_read =
+ mDataSource->read_at(offset, mSrcBuffer, size);
- size_t nal_length = (data[0] << 8) | data[1];
- assert(mBufferSizeRemaining >= 2 + nal_length);
-
- if (mNeedsNALFraming) {
- // Insert marker.
- data[-2] = data[-1] = data[0] = 0;
- data[1] = 1;
-
- mBuffer->set_range(mBufferOffset - 2, nal_length + 4);
- } else {
- mBuffer->set_range(mBufferOffset + 2, nal_length);
- }
-
- mBufferOffset += nal_length + 2;
- mBufferSizeRemaining -= nal_length + 2;
-
- if (mBufferSizeRemaining > 0) {
- *out = mBuffer->clone();
- } else {
- *out = mBuffer;
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
mBuffer = NULL;
+
+ return err;
}
+ uint8_t *dstData = (uint8_t *)mBuffer->data();
+ size_t srcOffset = 0;
+ size_t dstOffset = 0;
+ while (srcOffset < size) {
+ assert(srcOffset + 1 < size);
+ size_t nalLength =
+ (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+ assert(srcOffset + 1 + nalLength < size);
+ srcOffset += 2;
+
+ if (nalLength == 0) {
+ continue;
+ }
+
+ assert(dstOffset + 4 <= mBuffer->size());
+
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 1;
+ memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+ srcOffset += nalLength;
+ dstOffset += nalLength;
+ }
+
+ mBuffer->set_range(0, dstOffset);
+ mBuffer->meta_data()->clear();
+ mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+ mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ ++mCurrentSampleIndex;
+
+ *out = mBuffer;
+ mBuffer = NULL;
+
return OK;
}
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 78fcdee..04c9a11 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -40,6 +40,7 @@
#include <media/stagefright/SoftwareRenderer.h>
#include <media/stagefright/SurfaceRenderer.h>
#include <media/stagefright/TimeSource.h>
+#include <media/stagefright/TIHardwareRenderer.h>
#include <ui/PixelFormat.h>
#include <ui/Surface.h>
@@ -311,6 +312,9 @@
{
Mutex::Autolock autoLock(mLock);
mVideoPosition = pts_us;
+
+ LOGV("now_video = %.2f secs (%lld ms)",
+ pts_us / 1E6, (pts_us + 500) / 1000);
}
if (seeking && mAudioPlayer != NULL) {
@@ -344,6 +348,7 @@
if (mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
mTimeSourceDeltaUs = realtime_us - mediatime_us;
+ LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
}
int64_t now_us = mTimeSource->getRealTimeUs();
@@ -436,6 +441,7 @@
}
void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+ LOGI("setAudioSource");
mAudioSource = source;
sp<MetaData> meta = source->getFormat();
@@ -646,17 +652,28 @@
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
assert(success);
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
if (mSurface.get() != NULL) {
+ LOGW("Using SurfaceRenderer.");
mRenderer =
new SurfaceRenderer(
mSurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
- } else if (format == OMX_COLOR_FormatYUV420Planar
- && !strncasecmp(component, "OMX.qcom.video.decoder.", 23)) {
+ } else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+ && !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
+ LOGW("Using QComHardwareRenderer.");
mRenderer =
new QComHardwareRenderer(
mISurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
+ } else if (format == OMX_COLOR_FormatCbYCrY
+ && !strcmp(component, "OMX.TI.Video.Decoder")) {
+ LOGW("Using TIHardwareRenderer.");
+ mRenderer =
+ new TIHardwareRenderer(
+ mISurface, mVideoWidth, mVideoHeight,
+ decodedWidth, decodedHeight);
} else {
LOGW("Using software renderer.");
mRenderer = new SoftwareRenderer(
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index c059a9d..5e44999 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -20,6 +20,7 @@
#undef NDEBUG
#include <assert.h>
+#include <ctype.h>
#include <OMX_Component.h>
@@ -54,14 +55,20 @@
};
static const CodecInfo kDecoderInfo[] = {
+ { "audio/mpeg", "OMX.TI.MP3.decode" },
{ "audio/mpeg", "OMX.PV.mp3dec" },
+ { "audio/3gpp", "OMX.TI.AMR.decode" },
{ "audio/3gpp", "OMX.PV.amrdec" },
+ { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
{ "audio/mp4a-latm", "OMX.PV.aacdec" },
{ "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+ { "video/mp4v-es", "OMX.TI.Video.Decoder" },
{ "video/mp4v-es", "OMX.PV.mpeg4dec" },
{ "video/3gpp", "OMX.qcom.video.decoder.h263" },
+ { "video/3gpp", "OMX.TI.Video.Decoder" },
{ "video/3gpp", "OMX.PV.h263dec" },
{ "video/avc", "OMX.qcom.video.decoder.avc" },
+ { "video/avc", "OMX.TI.Video.Decoder" },
{ "video/avc", "OMX.PV.avcdec" },
};
@@ -92,7 +99,9 @@
}
// static
-OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
+OMXDecoder *OMXDecoder::Create(
+ OMXClient *client, const sp<MetaData> &meta,
+ bool createEncoder) {
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
assert(success);
@@ -102,9 +111,15 @@
const char *codec = NULL;
IOMX::node_id node = 0;
for (int index = 0;; ++index) {
- codec = GetCodec(
- kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
+ if (createEncoder) {
+ codec = GetCodec(
+ kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+ mime, index);
+ } else {
+ codec = GetCodec(
+ kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+ mime, index);
+ }
if (!codec) {
return NULL;
@@ -118,7 +133,33 @@
}
}
- OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec);
+ uint32_t quirks = 0;
+ if (!strcmp(codec, "OMX.PV.avcdec")) {
+ quirks |= kWantsRawNALFrames;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")
+ || !strcmp(codec, "OMX.TI.MP3.decode")) {
+ quirks |= kDoesntReturnBuffersOnDisable;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")) {
+ quirks |= kDoesntFlushOnExecutingToIdle;
+ quirks |= kDoesntProperlyFlushAllPortsAtOnce;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.", 15)) {
+ quirks |= kRequiresLoadedToIdleAfterAllocation;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")
+ || !strcmp(codec, "OMX.TI.MP3.decode")) {
+ quirks |= kMeasuresTimeInMilliseconds;
+ }
+
+ OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
uint32_t type;
const void *data;
@@ -169,52 +210,22 @@
return decoder;
}
-// static
-OMXDecoder *OMXDecoder::CreateEncoder(
- OMXClient *client, const sp<MetaData> &meta) {
- const char *mime;
- bool success = meta->findCString(kKeyMIMEType, &mime);
- assert(success);
-
- sp<IOMX> omx = client->interface();
-
- const char *codec = NULL;
- IOMX::node_id node = 0;
- for (int index = 0;; ++index) {
- codec = GetCodec(
- kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
-
- if (!codec) {
- return NULL;
- }
-
- LOGI("Attempting to allocate OMX node '%s'", codec);
-
- status_t err = omx->allocate_node(codec, &node);
- if (err == OK) {
- break;
- }
- }
-
- OMXDecoder *encoder = new OMXDecoder(client, node, mime, codec);
-
- return encoder;
-}
-
OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
- const char *mime, const char *codec)
+ const char *mime, const char *codec,
+ uint32_t quirks)
: mClient(client),
mOMX(mClient->interface()),
mNode(node),
mComponentName(strdup(codec)),
mIsMP3(!strcasecmp(mime, "audio/mpeg")),
+ mIsAVC(!strcasecmp(mime, "video/avc")),
+ mQuirks(quirks),
mSource(NULL),
mCodecSpecificDataIterator(mCodecSpecificData.begin()),
mState(OMX_StateLoaded),
mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
mShutdownInitiated(false),
- mDealer(new MemoryDealer(3 * 1024 * 1024)),
+ mDealer(new MemoryDealer(5 * 1024 * 1024)),
mSeeking(false),
mStarted(false),
mErrorCondition(OK),
@@ -261,7 +272,7 @@
// mDealer->dump("Decoder Dealer");
sp<MetaData> params = new MetaData;
- if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+ if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
params->setInt32(kKeyNeedsNALFraming, true);
}
@@ -297,7 +308,7 @@
}
int attempt = 1;
- while (mState != OMX_StateLoaded && attempt < 10) {
+ while (mState != OMX_StateLoaded && attempt < 20) {
usleep(100000);
++attempt;
@@ -366,7 +377,11 @@
mOutputBuffers.erase(mOutputBuffers.begin());
}
- status_t err = mOMX->send_command(mNode, OMX_CommandFlush, -1);
+ // XXX One of TI's decoders appears to ignore a flush if it doesn't
+ // currently hold on to any buffers on the port in question and
+ // never sends the completion event... FIXME
+
+ status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
assert(err == OK);
// Once flushing is completed buffers will again be scheduled to be
@@ -472,9 +487,121 @@
assert(err == NO_ERROR);
}
-void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
+status_t OMXDecoder::setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat) {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = portIndex;
+ format.nIndex = 0;
+ bool found = false;
+
+ OMX_U32 index = 0;
+ for (;;) {
+ format.nIndex = index;
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ if (err != OK) {
+ return err;
+ }
+
+ // The following assertion is violated by TI's video decoder.
+ // assert(format.nIndex == index);
+
+ if (format.eCompressionFormat == compressionFormat
+ && format.eColorFormat == colorFormat) {
+ found = true;
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!found) {
+ return UNKNOWN_ERROR;
+ }
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ return err;
+}
+
+#if 1
+void OMXDecoder::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+#if 1
+ // Enabling this code appears to be the right thing(tm), but,...
+ // the TI decoder then loses the ability to output YUV420 and only outputs
+ // YCbYCr (16bit)
+ if (!strcasecmp("video/avc", mime)) {
+ OMX_PARAM_COMPONENTROLETYPE role;
+ role.nSize = sizeof(role);
+ role.nVersion.s.nVersionMajor = 1;
+ role.nVersion.s.nVersionMinor = 1;
+ strncpy((char *)role.cRole, "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamStandardComponentRole,
+ &role, sizeof(role));
+ assert(err == OK);
+ }
+#endif
+
+ OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+ if (!strcasecmp("video/avc", mime)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ compressionFormat = OMX_VIDEO_CodingH263;
+ } else {
+ assert(!"Should not be here. Not a supported video mime type.");
+ }
+
+ setVideoPortFormatType(
+ kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+
+ assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+ || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+ }
+#endif
+
OMX_PARAM_PORTDEFINITIONTYPE def;
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
@@ -502,7 +629,7 @@
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
- // video_def.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
video_def->eColorFormat = OMX_COLOR_FormatUnused;
err = mOMX->set_parameter(
@@ -522,21 +649,189 @@
assert(def.eDomain == OMX_PortDomainVideo);
+#if 0
def.nBufferSize =
(((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
+#endif
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
- video_def->nStride = width;
- // video_def->nSliceHeight = height;
- video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
-// video_def->eColorFormat = OMX_COLOR_FormatYUV420Planar;
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == NO_ERROR);
}
+#else
+static void hexdump(const void *_data, size_t size) {
+ char line[256];
+ char tmp[16];
+
+ const uint8_t *data = (const uint8_t *)_data;
+ size_t offset = 0;
+ while (offset < size) {
+ sprintf(line, "0x%04x ", offset);
+
+ size_t n = size - offset;
+ if (n > 16) {
+ n = 16;
+ }
+
+ for (size_t i = 0; i < 16; ++i) {
+ if (i == 8) {
+ strcat(line, " ");
+ }
+
+ if (offset + i < size) {
+ sprintf(tmp, "%02x ", data[offset + i]);
+ strcat(line, tmp);
+ } else {
+ strcat(line, " ");
+ }
+ }
+
+ strcat(line, " ");
+
+ for (size_t i = 0; i < n; ++i) {
+ if (isprint(data[offset + i])) {
+ sprintf(tmp, "%c", data[offset + i]);
+ strcat(line, tmp);
+ } else {
+ strcat(line, ".");
+ }
+ }
+
+ LOGI(line);
+
+ offset += 16;
+ }
+}
+
+static void DumpPortDefinitionType(const void *_param) {
+ OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;
+
+ LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
+ param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);
+
+ if (param->eDomain == OMX_PortDomainVideo) {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video = ¶m->format.video;
+ LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
+ video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
+ } else {
+ hexdump(param, param->nSize);
+ }
+}
+
+void OMXDecoder::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 0
+ // Enabling this code appears to be the right thing(tm), but,...
+ // the decoder then loses the ability to output YUV420 and only outputs
+ // YCbYCr (16bit)
+ {
+ OMX_PARAM_COMPONENTROLETYPE role;
+ role.nSize = sizeof(role);
+ role.nVersion.s.nVersionMajor = 1;
+ role.nVersion.s.nVersionMinor = 1;
+ strncpy((char *)role.cRole, "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamStandardComponentRole,
+ &role, sizeof(role));
+ assert(err == OK);
+ }
+#endif
+
+ setVideoPortFormatType(
+ kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
+
+#if 1
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
+ hexdump(&format, format.nSize);
+
+ assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+ assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY);
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+ }
+#endif
+
+ OMX_PORT_PARAM_TYPE ptype;
+ ptype.nSize = sizeof(ptype);
+ ptype.nVersion.s.nVersionMajor = 1;
+ ptype.nVersion.s.nVersionMinor = 1;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
+ hexdump(&ptype, ptype.nSize);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+ DumpPortDefinitionType(&def);
+
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ def.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+ DumpPortDefinitionType(&def);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+}
+
+#endif
+
void OMXDecoder::setup() {
const sp<MetaData> &meta = mSource->getFormat();
@@ -554,7 +849,7 @@
success = success && meta->findInt32(kKeyHeight, &height);
assert(success);
- setVideoOutputFormat(width, height);
+ setVideoOutputFormat(mime, width, height);
}
// dumpPortDefinition(0);
@@ -644,10 +939,7 @@
}
void OMXDecoder::onStart() {
- bool needs_qcom_hack =
- !strncmp(mComponentName, "OMX.qcom.video.", 15);
-
- if (!needs_qcom_hack) {
+ if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
assert(err == NO_ERROR);
@@ -656,7 +948,7 @@
allocateBuffers(kPortIndexInput);
allocateBuffers(kPortIndexOutput);
- if (needs_qcom_hack) {
+ if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
// XXX this should happen before AllocateBuffers, but qcom's
// h264 vdec disagrees.
status_t err =
@@ -691,13 +983,17 @@
for (OMX_U32 i = 0; i < num_buffers; ++i) {
sp<IMemory> mem = mDealer->allocate(buffer_size);
+ if (mem.get() == NULL) {
+ LOGE("[%s] allocating IMemory of size %ld FAILED.",
+ mComponentName, buffer_size);
+ }
assert(mem.get() != NULL);
IOMX::buffer_id buffer;
status_t err;
if (port_index == kPortIndexInput
- && !strncmp(mComponentName, "OMX.qcom.video.encoder.", 23)) {
+ && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
// qcom's H.263 encoder appears to want to allocate its own input
// buffers.
err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
@@ -706,7 +1002,7 @@
mComponentName, err);
}
} else if (port_index == kPortIndexOutput
- && !strncmp(mComponentName, "OMX.qcom.video.decoder.", 23)) {
+ && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
#if 1
err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
#else
@@ -817,18 +1113,59 @@
case OMX_CommandFlush: {
OMX_U32 port_index = data;
LOGV("Port %ld flush complete.", port_index);
- assert(getPortStatus(port_index) == kPortStatusFlushing);
- setPortStatus(port_index, kPortStatusActive);
- BufferList *buffers = &mBuffers.editItemAt(port_index);
- while (!buffers->empty()) {
- IOMX::buffer_id buffer = *buffers->begin();
- buffers->erase(buffers->begin());
+ PortStatus status = getPortStatus(port_index);
- if (port_index == kPortIndexInput) {
- postEmptyBufferDone(buffer);
- } else {
- postInitialFillBuffer(buffer);
+ assert(status == kPortStatusFlushing
+ || status == kPortStatusFlushingToDisabled
+ || status == kPortStatusFlushingToShutdown);
+
+ switch (status) {
+ case kPortStatusFlushing:
+ {
+ // This happens when we're flushing before a seek.
+ setPortStatus(port_index, kPortStatusActive);
+ BufferList *buffers = &mBuffers.editItemAt(port_index);
+ while (!buffers->empty()) {
+ IOMX::buffer_id buffer = *buffers->begin();
+ buffers->erase(buffers->begin());
+
+ if (port_index == kPortIndexInput) {
+ postEmptyBufferDone(buffer);
+ } else {
+ postInitialFillBuffer(buffer);
+ }
+ }
+ break;
+ }
+
+ case kPortStatusFlushingToDisabled:
+ {
+ // Port settings have changed and the (buggy) OMX component
+ // does not properly return buffers on disabling, we need to
+ // do a flush first and _then_ disable the port in question.
+
+ setPortStatus(port_index, kPortStatusDisabled);
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandPortDisable, port_index);
+ assert(err == OK);
+
+ freePortBuffers(port_index);
+ break;
+ }
+
+ default:
+ {
+ assert(status == kPortStatusFlushingToShutdown);
+
+ setPortStatus(port_index, kPortStatusShutdown);
+ if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
+ && getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateIdle);
+ assert(err == OK);
+ }
+ break;
}
}
break;
@@ -841,10 +1178,22 @@
void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
assert(getPortStatus(port_index) == kPortStatusActive);
- setPortStatus(port_index, kPortStatusDisabled);
- status_t err =
- mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+ status_t err;
+
+ if (mQuirks & kDoesntReturnBuffersOnDisable) {
+ // Decoder does not properly return our buffers when disabled...
+ // Need to flush port instead and _then_ disable.
+
+ setPortStatus(port_index, kPortStatusFlushingToDisabled);
+
+ err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
+ } else {
+ setPortStatus(port_index, kPortStatusDisabled);
+
+ err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+ }
+
assert(err == NO_ERROR);
}
@@ -894,19 +1243,8 @@
mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
assert(err == NO_ERROR);
- BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
- for (BufferList::iterator it = ibuffers->begin();
- it != ibuffers->end(); ++it) {
- freeInputBuffer(*it);
- }
- ibuffers->clear();
-
- BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
- for (BufferList::iterator it = obuffers->begin();
- it != obuffers->end(); ++it) {
- freeOutputBuffer(*it);
- }
- obuffers->clear();
+ freePortBuffers(kPortIndexInput);
+ freePortBuffers(kPortIndexOutput);
}
}
@@ -925,26 +1263,41 @@
mShutdownInitiated = true;
- status_t err =
- mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
- assert(err == NO_ERROR);
+ status_t err;
+ if (mQuirks & kDoesntFlushOnExecutingToIdle) {
+ if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
+ err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
+ assert(err == OK);
- setPortStatus(kPortIndexInput, kPortStatusShutdown);
- setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+ err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
+ } else {
+ err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+ }
+
+ setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
+ setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
+ } else {
+ err = mClient->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateIdle);
+
+ setPortStatus(kPortIndexInput, kPortStatusShutdown);
+ setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+ }
+ assert(err == OK);
}
void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
- int shift = 2 * port_index;
+ int shift = 3 * port_index;
- mPortStatusMask &= ~(3 << shift);
+ mPortStatusMask &= ~(7 << shift);
mPortStatusMask |= status << shift;
}
OMXDecoder::PortStatus OMXDecoder::getPortStatus(
OMX_U32 port_index) const {
- int shift = 2 * port_index;
+ int shift = 3 * port_index;
- return static_cast<PortStatus>((mPortStatusMask >> shift) & 3);
+ return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
}
void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
@@ -964,6 +1317,8 @@
break;
case kPortStatusFlushing:
+ case kPortStatusFlushingToDisabled:
+ case kPortStatusFlushingToShutdown:
LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
err = NO_ERROR;
@@ -980,7 +1335,9 @@
void OMXDecoder::onFillBufferDone(const omx_message &msg) {
IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
- LOGV("[%s] onFillBufferDone (%p)", mComponentName, buffer);
+ LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
+ msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
+ buffer, msg.u.extended_buffer_data.range_length);
status_t err;
switch (getPortStatus(kPortIndexOutput)) {
@@ -995,6 +1352,8 @@
break;
case kPortStatusFlushing:
+ case kPortStatusFlushingToDisabled:
+ case kPortStatusFlushingToShutdown:
LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
err = NO_ERROR;
@@ -1035,7 +1394,7 @@
size_t range_length = 0;
- if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+ if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
memcpy(mem->pointer(), kNALStartCode, 4);
@@ -1142,15 +1501,18 @@
OMX_TICKS timestamp = 0;
if (success) {
- // XXX units should be microseconds but PV treats them as milliseconds.
- timestamp = ((OMX_S64)units * 1000) / scale;
+ if (mQuirks & kMeasuresTimeInMilliseconds) {
+ timestamp = ((OMX_S64)units * 1000) / scale;
+ } else {
+ timestamp = ((OMX_S64)units * 1000000) / scale;
+ }
}
input_buffer->release();
input_buffer = NULL;
- LOGV("[%s] Calling EmptyBuffer on buffer %p",
- mComponentName, buffer);
+ LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
+ mComponentName, buffer, src_length, flags);
status_t err2 = mClient->emptyBuffer(
mNode, buffer, 0, src_length, flags, timestamp);
@@ -1169,8 +1531,16 @@
media_buffer->meta_data()->clear();
- media_buffer->meta_data()->setInt32(
- kKeyTimeUnits, msg.u.extended_buffer_data.timestamp);
+ if (mQuirks & kMeasuresTimeInMilliseconds) {
+ media_buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ msg.u.extended_buffer_data.timestamp);
+ } else {
+ media_buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+ }
+
media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
@@ -1198,7 +1568,9 @@
PortStatus outputStatus = getPortStatus(kPortIndexOutput);
if (outputStatus == kPortStatusShutdown
- || outputStatus == kPortStatusFlushing) {
+ || outputStatus == kPortStatusFlushing
+ || outputStatus == kPortStatusFlushingToDisabled
+ || outputStatus == kPortStatusFlushingToShutdown) {
mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
} else {
LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
@@ -1326,4 +1698,18 @@
postMessage(msg);
}
+void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
+ BufferList *buffers = &mBuffers.editItemAt(port_index);
+ while (!buffers->empty()) {
+ IOMX::buffer_id buffer = *buffers->begin();
+ buffers->erase(buffers->begin());
+
+ if (port_index == kPortIndexInput) {
+ freeInputBuffer(buffer);
+ } else {
+ freeOutputBuffer(buffer);
+ }
+ }
+}
+
} // namespace android
diff --git a/media/libstagefright/TIHardwareRenderer.cpp b/media/libstagefright/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ba42ef4
--- /dev/null
+++ b/media/libstagefright/TIHardwareRenderer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+ assert(mISurface.get() != NULL);
+ assert(mDecodedWidth > 0);
+ assert(mDecodedHeight > 0);
+
+ sp<OverlayRef> ref = mISurface->createOverlay(
+ mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+ if (ref.get() == NULL) {
+ LOGE("Unable to create the overlay!");
+ return;
+ }
+
+ mOverlay = new Overlay(ref);
+
+ for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
+ mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+ }
+ mIndex = mOverlayAddresses.size() - 1;
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+ if (mOverlay.get() != NULL) {
+ mOverlay->destroy();
+ mOverlay.clear();
+
+ // XXX apparently destroying an overlay is an asynchronous process...
+ sleep(1);
+ }
+}
+
+void TIHardwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ // assert(size == mFrameSize);
+
+ if (mOverlay.get() == NULL) {
+ return;
+ }
+
+#if 0
+ overlay_buffer_t buffer;
+ if (mOverlay->dequeueBuffer(&buffer) == OK) {
+ void *addr = mOverlay->getBufferAddress(buffer);
+
+ memcpy(addr, data, size);
+
+ mOverlay->queueBuffer(buffer);
+ }
+#else
+ memcpy(mOverlayAddresses[mIndex], data, size);
+ mOverlay->queueBuffer((void *)mIndex);
+
+ if (mIndex-- == 0) {
+ mIndex = mOverlayAddresses.size() - 1;
+ }
+#endif
+}
+
+} // namespace android
+
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 7f3f114..445e681 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -149,7 +149,7 @@
hnd = new driver_t(dso);
} else {
// Always load EGL first
- snprintf(path, PATH_MAX, "lib%s_%s.so", "EGL", tag);
+ snprintf(path, PATH_MAX, format, "EGL", tag);
dso = load_driver(path, hooks, EGL);
if (dso) {
hnd = new driver_t(dso);
diff --git a/packages/SettingsProvider/res/values-cs/defaults.xml b/packages/SettingsProvider/res/values-cs/defaults.xml
deleted file mode 100644
index a7c01b3..0000000
--- a/packages/SettingsProvider/res/values-cs/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"mobil,bluetooth,wifi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-cs/strings.xml b/packages/SettingsProvider/res/values-cs/strings.xml
index dc75a92..2b089d9 100644
--- a/packages/SettingsProvider/res/values-cs/strings.xml
+++ b/packages/SettingsProvider/res/values-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Paměť pro nastavení"</string>
+ <string name="app_label" msgid="4567566098528588863">"Paměť pro nastavení"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-de/defaults.xml b/packages/SettingsProvider/res/values-de/defaults.xml
deleted file mode 100644
index f85d3f0..0000000
--- a/packages/SettingsProvider/res/values-de/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"Mobilfunk, Bluetooth, WLAN"</string>
- <string name="def_location_providers_allowed">"GPS"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-de/strings.xml b/packages/SettingsProvider/res/values-de/strings.xml
index 50c8a14..a293522 100644
--- a/packages/SettingsProvider/res/values-de/strings.xml
+++ b/packages/SettingsProvider/res/values-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Einstellungsspeicher"</string>
+ <string name="app_label" msgid="4567566098528588863">"Einstellungsspeicher"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-es/defaults.xml b/packages/SettingsProvider/res/values-es/defaults.xml
deleted file mode 100644
index a64805a..0000000
--- a/packages/SettingsProvider/res/values-es/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"móvil,bluetooth,wifi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-es/strings.xml b/packages/SettingsProvider/res/values-es/strings.xml
index d30d195..de3958b 100644
--- a/packages/SettingsProvider/res/values-es/strings.xml
+++ b/packages/SettingsProvider/res/values-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Almacenamiento de configuración"</string>
+ <string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-fr/defaults.xml b/packages/SettingsProvider/res/values-fr/defaults.xml
deleted file mode 100644
index 56334cc..0000000
--- a/packages/SettingsProvider/res/values-fr/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"cellulaire, Bluetooth, Wi-Fi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-fr/strings.xml b/packages/SettingsProvider/res/values-fr/strings.xml
index 686ec8b..7a1386a 100644
--- a/packages/SettingsProvider/res/values-fr/strings.xml
+++ b/packages/SettingsProvider/res/values-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Stockage des paramètres"</string>
+ <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-it/defaults.xml b/packages/SettingsProvider/res/values-it/defaults.xml
deleted file mode 100644
index 19c0896..0000000
--- a/packages/SettingsProvider/res/values-it/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"cellulare,bluetooth,wifi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-it/strings.xml b/packages/SettingsProvider/res/values-it/strings.xml
index 29e462f..f88a654 100644
--- a/packages/SettingsProvider/res/values-it/strings.xml
+++ b/packages/SettingsProvider/res/values-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Archiviazione impostazioni"</string>
+ <string name="app_label" msgid="4567566098528588863">"Archiviazione impostazioni"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-nl/defaults.xml b/packages/SettingsProvider/res/values-nl/defaults.xml
deleted file mode 100644
index 625235a..0000000
--- a/packages/SettingsProvider/res/values-nl/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"mobiel,bluetooth,wifi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-nl/strings.xml b/packages/SettingsProvider/res/values-nl/strings.xml
index b37b535..7a0e416 100644
--- a/packages/SettingsProvider/res/values-nl/strings.xml
+++ b/packages/SettingsProvider/res/values-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Opslagruimte voor instellingen"</string>
+ <string name="app_label" msgid="4567566098528588863">"Opslagruimte voor instellingen"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-pl/defaults.xml b/packages/SettingsProvider/res/values-pl/defaults.xml
deleted file mode 100644
index b60832e..0000000
--- a/packages/SettingsProvider/res/values-pl/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"komórka,bluetooth,wifi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-pl/strings.xml b/packages/SettingsProvider/res/values-pl/strings.xml
index 4ab1e91..ccff82e3 100644
--- a/packages/SettingsProvider/res/values-pl/strings.xml
+++ b/packages/SettingsProvider/res/values-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"Pamięć ustawień"</string>
+ <string name="app_label" msgid="4567566098528588863">"Pamięć ustawień"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml b/packages/SettingsProvider/res/values-zh-rTW/defaults.xml
deleted file mode 100644
index fdbba88..0000000
--- a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="def_airplane_mode_radios">"手機,藍牙,wifi"</string>
- <string name="def_location_providers_allowed">"gps"</string>
- <!-- no translation found for def_backup_transport (6764822064303377157) -->
- <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rTW/strings.xml b/packages/SettingsProvider/res/values-zh-rTW/strings.xml
index b24144a..0700a76 100644
--- a/packages/SettingsProvider/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsProvider/res/values-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label">"設定儲存空間"</string>
+ <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index af02741..c33bdd7 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -21,7 +21,7 @@
<integer name="def_screen_off_timeout">60000</integer>
<bool name="def_airplane_mode_on">false</bool>
<!-- Comma-separated list of bluetooth, wifi, and cell. -->
- <string name="def_airplane_mode_radios">cell,bluetooth,wifi</string>
+ <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string>
<bool name="def_auto_time">true</bool>
<bool name="def_accelerometer_rotation">true</bool>
<!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
@@ -35,7 +35,7 @@
Network location is off by default because it requires
user opt-in via Setup Wizard or Settings.
-->
- <string name="def_location_providers_allowed">gps</string>
+ <string name="def_location_providers_allowed" translatable="false">gps</string>
<bool name="assisted_gps_enabled">true</bool>
<!-- 0 == mobile, 1 == wifi. -->
<integer name="def_network_preference">1</integer>
@@ -44,5 +44,5 @@
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
- <string name="def_backup_transport"></string>
+ <string name="def_backup_transport" translatable="false"></string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1451682..9877342 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -24,9 +24,11 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
+import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
@@ -397,12 +399,8 @@
// Get the current value for the default sound
Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
- if (soundUri == null) {
- // Fallback on any valid ringtone Uri
- soundUri = RingtoneManager.getValidRingtoneUri(context);
- }
- if (soundUri != null) {
+ if (soundUri != null) {
// Only proxy the openFile call to drm or media providers
String authority = soundUri.getAuthority();
boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
@@ -426,4 +424,64 @@
return super.openFile(uri, mode);
}
+
+ @Override
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
+
+ /*
+ * When a client attempts to openFile the default ringtone or
+ * notification setting Uri, we will proxy the call to the current
+ * default ringtone's Uri (if it is in the DRM or media provider).
+ */
+ int ringtoneType = RingtoneManager.getDefaultType(uri);
+ // Above call returns -1 if the Uri doesn't match a default type
+ if (ringtoneType != -1) {
+ Context context = getContext();
+
+ // Get the current value for the default sound
+ Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
+
+ if (soundUri != null) {
+ // Only proxy the openFile call to drm or media providers
+ String authority = soundUri.getAuthority();
+ boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
+ if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
+
+ if (isDrmAuthority) {
+ try {
+ // Check DRM access permission here, since once we
+ // do the below call the DRM will be checking our
+ // permission, not our caller's permission
+ DrmStore.enforceAccessDrmPermission(context);
+ } catch (SecurityException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = context.getContentResolver().openFileDescriptor(soundUri, mode);
+ return new AssetFileDescriptor(pfd, 0, -1);
+ } catch (FileNotFoundException ex) {
+ // fall through and open the fallback ringtone below
+ }
+ }
+
+ try {
+ return super.openAssetFile(soundUri, mode);
+ } catch (FileNotFoundException ex) {
+ // Since a non-null Uri was specified, but couldn't be opened,
+ // fall back to the built-in ringtone.
+ return context.getResources().openRawResourceFd(
+ com.android.internal.R.raw.fallbackring);
+ }
+ }
+ // no need to fall through and have openFile() try again, since we
+ // already know that will fail.
+ throw new FileNotFoundException(); // or return null ?
+ }
+
+ // Note that this will end up calling openFile() above.
+ return super.openAssetFile(uri, mode);
+ }
}
diff --git a/preloaded-classes b/preloaded-classes
index 3858883..6eb3cf2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -845,16 +845,18 @@
java.util.HashMap
java.util.HashMap$1
java.util.HashMap$2
-java.util.HashMap$2$1
+java.util.HashMap$AbstractMapIterator
java.util.HashMap$Entry
+java.util.HashMap$EntryIterator
java.util.HashMap$HashMapEntrySet
-java.util.HashMap$HashMapEntrySet$1
+java.util.HashMap$KeyIterator
+java.util.HashMap$ValueIterator
java.util.HashSet
java.util.Hashtable
-java.util.Hashtable$4
-java.util.Hashtable$4$1
+java.util.Hashtable$6
+java.util.Hashtable$6$1
java.util.Hashtable$Entry
-java.util.Hashtable$HashEnumerator
+java.util.Hashtable$HashEnumIterator
java.util.Hashtable$HashIterator
java.util.IdentityHashMap
java.util.LinkedHashMap
@@ -869,7 +871,7 @@
java.util.SimpleTimeZone
java.util.TimeZone
java.util.TreeMap
-java.util.TreeMap$Entry
+java.util.TreeMap$MapEntry
java.util.TreeSet
java.util.Vector
java.util.WeakHashMap
@@ -952,14 +954,11 @@
org.apache.harmony.luni.internal.net.www.protocol.jar.Handler
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$1
-org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$CacheEntry
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$JarURLConnectionInputStream
-org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$LRUComparator
org.apache.harmony.luni.internal.util.TimezoneGetter
org.apache.harmony.luni.internal.util.ZoneInfo
org.apache.harmony.luni.internal.util.ZoneInfoDB
org.apache.harmony.luni.net.PlainSocketImpl
-org.apache.harmony.luni.net.PlainSocketImpl2
org.apache.harmony.luni.platform.PlatformAddress
org.apache.harmony.luni.util.TwoKeyHashMap
org.apache.harmony.nio.internal.FileChannelImpl$RepositioningLock
@@ -1176,4 +1175,3 @@
org.xmlpull.v1.XmlPullParserFactory
org.xmlpull.v1.sax2.Driver
sun.misc.Unsafe
-
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 4643115..67f3816 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -46,6 +46,8 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
@@ -91,6 +93,20 @@
private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4;
+ // Event tags -- see system/core/logcat/event-log-tags
+ private static final int BACKUP_DATA_CHANGED_EVENT = 2820;
+ private static final int BACKUP_START_EVENT = 2821;
+ private static final int BACKUP_TRANSPORT_FAILURE_EVENT = 2822;
+ private static final int BACKUP_AGENT_FAILURE_EVENT = 2823;
+ private static final int BACKUP_PACKAGE_EVENT = 2824;
+ private static final int BACKUP_SUCCESS_EVENT = 2825;
+
+ private static final int RESTORE_START_EVENT = 2830;
+ private static final int RESTORE_TRANSPORT_FAILURE_EVENT = 2831;
+ private static final int RESTORE_AGENT_FAILURE_EVENT = 2832;
+ private static final int RESTORE_PACKAGE_EVENT = 2833;
+ private static final int RESTORE_SUCCESS_EVENT = 2834;
+
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -787,7 +803,7 @@
class ClearDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(String packageName, boolean succeeded)
- throws android.os.RemoteException {
+ throws RemoteException {
synchronized(mClearDataLock) {
mClearingData = false;
mClearDataLock.notifyAll();
@@ -820,43 +836,49 @@
@Override
public void run() {
+ long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
// Backups run at background priority
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- // The package manager doesn't have a proper <application> etc, but since
- // it's running here in the system process we can just set up its agent
- // directly and use a synthetic BackupRequest. We always run this pass
- // because it's cheap and this way we guarantee that we don't get out of
- // step even if we're selecting among various transports at run time.
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentPackages());
- BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
- pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
- processOneBackup(pmRequest,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()),
- mTransport);
-
- // Now run all the backups in our queue
- doQueuedBackups(mTransport);
-
- // Finally, tear down the transport
try {
- if (!mTransport.finishBackup()) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in finishBackup()");
+ EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
+
+ // The package manager doesn't have a proper <application> etc, but since
+ // it's running here in the system process we can just set up its agent
+ // directly and use a synthetic BackupRequest. We always run this pass
+ // because it's cheap and this way we guarantee that we don't get out of
+ // step even if we're selecting among various transports at run time.
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentPackages());
+ BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+ pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneBackup(pmRequest,
+ IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
+
+ // Now run all the backups in our queue
+ int count = mQueue.size();
+ doQueuedBackups(mTransport);
+
+ // Finally, tear down the transport
+ if (mTransport.finishBackup()) {
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(BACKUP_SUCCESS_EVENT, count, millis);
+ } else {
+ EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
+ Log.e(TAG, "Transport error in finishBackup()");
}
- } catch (RemoteException e) {
- Log.e(TAG, "Error in finishBackup()", e);
- }
- if (!mJournal.delete()) {
- Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
+ if (!mJournal.delete()) {
+ Log.e(TAG, "Unable to remove backup journal file " + mJournal);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error in backup thread", e);
+ } finally {
+ // Only once we're entirely finished do we release the wakelock
+ mWakelock.release();
}
-
- // Only once we're entirely finished do we release the wakelock
- mWakelock.release();
}
private void doQueuedBackups(IBackupTransport transport) {
@@ -882,19 +904,27 @@
Log.v(TAG, "bind/backup threw");
e.printStackTrace();
}
-
}
}
void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) {
final String packageName = request.appInfo.packageName;
- Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ if (DEBUG) Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ // !!! TODO: get the state file dir from the transport
+ File savedStateName = new File(mStateDir, packageName);
+ File backupDataName = new File(mDataDir, packageName + ".data");
+ File newStateName = new File(mStateDir, packageName + ".new");
+
+ ParcelFileDescriptor savedState = null;
+ ParcelFileDescriptor backupData = null;
+ ParcelFileDescriptor newState = null;
+
+ PackageInfo packInfo;
try {
// Look up the package info & signatures. This is first so that if it
// throws an exception, there's no file setup yet that would need to
// be unraveled.
- PackageInfo packInfo;
if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
// The metadata 'package' is synthetic
packInfo = new PackageInfo();
@@ -904,69 +934,65 @@
PackageManager.GET_SIGNATURES);
}
- // !!! TODO: get the state file dir from the transport
- File savedStateName = new File(mStateDir, packageName);
- File backupDataName = new File(mDataDir, packageName + ".data");
- File newStateName = new File(mStateDir, packageName + ".new");
-
// In a full backup, we pass a null ParcelFileDescriptor as
// the saved-state "file"
- ParcelFileDescriptor savedState = (request.fullBackup) ? null
- : ParcelFileDescriptor.open(savedStateName,
+ if (!request.fullBackup) {
+ savedState = ParcelFileDescriptor.open(savedStateName,
ParcelFileDescriptor.MODE_READ_ONLY |
- ParcelFileDescriptor.MODE_CREATE);
+ ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
+ }
- backupDataName.delete();
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
- newStateName.delete();
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ newState = ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
// Run the target's backup pass
- boolean success = false;
- try {
- agent.doBackup(savedState, backupData, newState);
- logBackupComplete(packageName);
- success = true;
- } finally {
- if (savedState != null) {
- savedState.close();
- }
- backupData.close();
- newState.close();
- }
-
- // Now propagate the newly-backed-up data to the transport
- if (success) {
- if (DEBUG) Log.v(TAG, "doBackup() success");
- if (backupDataName.length() > 0) {
- backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_ONLY);
- if (!transport.performBackup(packInfo, backupData)) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in performBackup()");
- }
- } else {
- if (DEBUG) {
- Log.i(TAG, "no backup data written; not calling transport");
- }
- }
-
- // After successful transport, delete the now-stale data
- // and juggle the files so that next time we supply the agent
- // with the new state file it just created.
- backupDataName.delete();
- newStateName.renameTo(savedStateName);
- }
+ agent.doBackup(savedState, backupData, newState);
+ logBackupComplete(packageName);
+ if (DEBUG) Log.v(TAG, "doBackup() success");
} catch (Exception e) {
Log.e(TAG, "Error backing up " + packageName, e);
+ EventLog.writeEvent(BACKUP_AGENT_FAILURE_EVENT, packageName, e.toString());
+ backupDataName.delete();
+ newStateName.delete();
+ return;
+ } finally {
+ try { if (savedState != null) savedState.close(); } catch (IOException e) {}
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
+ try { if (newState != null) newState.close(); } catch (IOException e) {}
+ savedState = backupData = newState = null;
+ }
+
+ // Now propagate the newly-backed-up data to the transport
+ try {
+ int size = (int) backupDataName.length();
+ if (size > 0) {
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ if (!transport.performBackup(packInfo, backupData)) throw new Exception();
+ } else {
+ if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
+ }
+
+ // After successful transport, delete the now-stale data
+ // and juggle the files so that next time we supply the agent
+ // with the new state file it just created.
+ backupDataName.delete();
+ newStateName.renameTo(savedStateName);
+ EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
+ } catch (Exception e) {
+ Log.e(TAG, "Transport error backing up " + packageName, e);
+ EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
+ return;
+ } finally {
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
}
}
}
@@ -1012,7 +1038,6 @@
private IBackupTransport mTransport;
private IRestoreObserver mObserver;
private long mToken;
- private RestoreSet mImage;
private File mStateDir;
class RestoreRequest {
@@ -1042,6 +1067,7 @@
@Override
public void run() {
+ long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
+ " mObserver=" + mObserver + " mToken=" + mToken);
/**
@@ -1049,7 +1075,7 @@
*
* 1. get the restore set description for our identity
* 2. for each app in the restore set:
- * 3.a. if it's restorable on this device, add it to the restore queue
+ * 2.a. if it's restorable on this device, add it to the restore queue
* 3. for each app in the restore queue:
* 3.a. clear the app data
* 3.b. get the restore data for the app from the transport
@@ -1057,25 +1083,18 @@
* 3.d. agent.doRestore() with the data from the server
* 3.e. unbind the agent [and kill the app?]
* 4. shut down the transport
+ *
+ * On errors, we try our best to recover and move on to the next
+ * application, but if necessary we abort the whole operation --
+ * the user is waiting, after al.
*/
int error = -1; // assume error
// build the set of apps to restore
try {
- RestoreSet[] images = mTransport.getAvailableRestoreSets();
- if (images == null) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Error getting restore sets");
- return;
- }
-
- if (images.length == 0) {
- Log.i(TAG, "No restore sets available");
- return;
- }
-
- mImage = images[0];
+ // TODO: Log this before getAvailableRestoreSets, somehow
+ EventLog.writeEvent(RESTORE_START_EVENT, mTransport.transportDirName());
// Get the list of all packages which have backup enabled.
// (Include the Package Manager metadata pseudo-package first.)
@@ -1100,22 +1119,26 @@
}
if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error starting restore operation");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
}
String packageName = mTransport.nextRestorePackage();
if (packageName == null) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error getting first restore package");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
} else if (packageName.equals("")) {
Log.i(TAG, "No restore data available");
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(RESTORE_SUCCESS_EVENT, 0, millis);
return;
} else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ "\", found only \"" + packageName + "\"");
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ "Package manager data missing");
return;
}
@@ -1128,23 +1151,25 @@
// signature/version verification etc, so we simply do not proceed with
// the restore operation.
if (!pmAgent.hasMetadata()) {
- Log.i(TAG, "No restore metadata available, so not restoring settings");
+ Log.e(TAG, "No restore metadata available, so not restoring settings");
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ "Package manager restore metadata missing");
return;
}
int count = 0;
for (;;) {
packageName = mTransport.nextRestorePackage();
+
if (packageName == null) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error getting next restore package");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
} else if (packageName.equals("")) {
break;
}
if (mObserver != null) {
- ++count;
try {
mObserver.onUpdate(count);
} catch (RemoteException e) {
@@ -1156,21 +1181,34 @@
Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
if (metaInfo == null) {
Log.e(TAG, "Missing metadata for " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Package metadata missing");
continue;
}
- int flags = PackageManager.GET_SIGNATURES;
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ PackageInfo packageInfo;
+ try {
+ int flags = PackageManager.GET_SIGNATURES;
+ packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Invalid package restoring data", e);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Package missing on device");
+ continue;
+ }
+
if (metaInfo.versionCode > packageInfo.versionCode) {
- Log.w(TAG, "Package " + packageName
- + " restore version [" + metaInfo.versionCode
- + "] is too new for installed version ["
- + packageInfo.versionCode + "]");
+ String message = "Version " + metaInfo.versionCode
+ + " > installed version " + packageInfo.versionCode;
+ Log.w(TAG, "Package " + packageName + ": " + message);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, message);
continue;
}
if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
Log.w(TAG, "Signature mismatch restoring " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Signature mismatch");
continue;
}
@@ -1186,11 +1224,14 @@
IApplicationThread.BACKUP_MODE_RESTORE);
if (agent == null) {
Log.w(TAG, "Can't find backup agent for " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Restore agent missing");
continue;
}
try {
processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ ++count;
} finally {
// unbind even on timeout or failure, just in case
mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
@@ -1199,21 +1240,19 @@
// if we get this far, report success to the observer
error = 0;
- } catch (NameNotFoundException e) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Invalid paackage restoring data", e);
- } catch (RemoteException e) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Error restoring data", e);
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(RESTORE_SUCCESS_EVENT, count, millis);
+ } catch (Exception e) {
+ Log.e(TAG, "Error in restore thread", e);
} finally {
+ if (DEBUG) Log.d(TAG, "finishing restore mObserver=" + mObserver);
+
try {
mTransport.finishRestore();
} catch (RemoteException e) {
Log.e(TAG, "Error finishing restore", e);
}
- Log.d(TAG, "finishing restore mObserver=" + mObserver);
-
if (mObserver != null) {
try {
mObserver.restoreFinished(error);
@@ -1232,57 +1271,58 @@
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
- Log.d(TAG, "processOneRestore packageName=" + packageName);
+ if (DEBUG) Log.d(TAG, "processOneRestore packageName=" + packageName);
// !!! TODO: get the dirs from the transport
File backupDataName = new File(mDataDir, packageName + ".restore");
- backupDataName.delete();
- try {
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ File newStateName = new File(mStateDir, packageName + ".new");
+ File savedStateName = new File(mStateDir, packageName);
+ ParcelFileDescriptor backupData = null;
+ ParcelFileDescriptor newState = null;
+
+ try {
// Run the transport's restore pass
- // Run the target's backup pass
- try {
- if (!mTransport.getRestoreData(backupData)) {
- // STOPSHIP TODO: Handle this error somehow?
- Log.e(TAG, "Error getting restore data for " + packageName);
- return;
- }
- } finally {
- backupData.close();
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
+
+ if (!mTransport.getRestoreData(backupData)) {
+ Log.e(TAG, "Error getting restore data for " + packageName);
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ return;
}
// Okay, we have the data. Now have the agent do the restore.
- File newStateName = new File(mStateDir, packageName + ".new");
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
-
+ backupData.close();
backupData = ParcelFileDescriptor.open(backupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- try {
- agent.doRestore(backupData, appVersionCode, newState);
- } finally {
- newState.close();
- backupData.close();
- }
+ newState = ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
+
+ agent.doRestore(backupData, appVersionCode, newState);
// if everything went okay, remember the recorded state now
- File savedStateName = new File(mStateDir, packageName);
newStateName.renameTo(savedStateName);
+ int size = (int) backupDataName.length();
+ EventLog.writeEvent(RESTORE_PACKAGE_EVENT, packageName, size);
} catch (Exception e) {
+ Log.e(TAG, "Error restoring data for " + packageName, e);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, e.toString());
+
// If the agent fails restore, it might have put the app's data
// into an incoherent state. For consistency we wipe its data
// again in this case before propagating the exception
- Log.e(TAG, "Error restoring data for " + packageName, e);
clearApplicationDataSynchronous(packageName);
} finally {
backupDataName.delete();
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
+ try { if (newState != null) newState.close(); } catch (IOException e) {}
+ backupData = newState = null;
}
}
}
@@ -1328,6 +1368,7 @@
// Record that we need a backup pass for the caller. Since multiple callers
// may share a uid, we need to note all candidates within that uid and schedule
// a backup pass for each of them.
+ EventLog.writeEvent(BACKUP_DATA_CHANGED_EVENT, packageName);
// If the caller does not hold the BACKUP permission, it can only request a
// backup of its own data.
@@ -1625,57 +1666,66 @@
}
// --- Binder interface ---
- public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
+ public synchronized RestoreSet[] getAvailableRestoreSets() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
try {
- synchronized(this) {
if (mRestoreTransport == null) {
Log.w(TAG, "Null transport getting restore sets");
- } else if (mRestoreSets == null) { // valid transport; do the one-time fetch
+ return null;
+ }
+ if (mRestoreSets == null) { // valid transport; do the one-time fetch
mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
+ if (mRestoreSets == null) EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
}
return mRestoreSets;
- }
- } catch (RuntimeException e) {
- Log.d(TAG, "getAvailableRestoreSets exception");
- e.printStackTrace();
- throw e;
+ } catch (Exception e) {
+ Log.e(TAG, "Error in getAvailableRestoreSets", e);
+ return null;
}
}
- public int performRestore(long token, IRestoreObserver observer)
- throws android.os.RemoteException {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "performRestore");
+ public synchronized int performRestore(long token, IRestoreObserver observer) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
- Log.d(TAG, "performRestore token=" + token + " observer=" + observer);
+ if (DEBUG) Log.d(TAG, "performRestore token=" + token + " observer=" + observer);
- if (mRestoreSets != null) {
- for (int i = 0; i < mRestoreSets.length; i++) {
- if (token == mRestoreSets[i].token) {
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token);
- mBackupHandler.sendMessage(msg);
- return 0;
- }
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Log.e(TAG, "Ignoring performRestore() with no restore set");
+ return -1;
+ }
+
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token);
+ mBackupHandler.sendMessage(msg);
+ return 0;
}
- } else {
- if (DEBUG) Log.v(TAG, "No current restore set, not doing restore");
}
return -1;
}
- public void endRestoreSession() throws android.os.RemoteException {
+ public synchronized void endRestoreSession() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"endRestoreSession");
- Log.d(TAG, "endRestoreSession");
+ if (DEBUG) Log.d(TAG, "endRestoreSession");
- mRestoreTransport.finishRestore();
- mRestoreTransport = null;
- synchronized(BackupManagerService.this) {
+ synchronized (this) {
+ try {
+ if (mRestoreTransport != null) mRestoreTransport.finishRestore();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in finishRestore", e);
+ } finally {
+ mRestoreTransport = null;
+ }
+ }
+
+ synchronized (BackupManagerService.this) {
if (BackupManagerService.this.mActiveRestoreSession == this) {
BackupManagerService.this.mActiveRestoreSession = null;
} else {
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index a682fcb..45c1e5c 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -44,6 +44,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import com.android.internal.app.ShutdownThread;
/**
@@ -182,6 +183,11 @@
boolean logOutlier = false;
long dischargeDuration = 0;
+
+ // shut down gracefully if our battery is critically low and we are not powered
+ if (mBatteryLevel == 0 && isPowered(0xffffffff)) {
+ ShutdownThread.shutdown(mContext, false);
+ }
mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index d6cd4ef..134fb6f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -60,7 +60,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Debug;
import android.os.HandlerThread;
import android.os.Parcel;
import android.os.RemoteException;
@@ -1829,6 +1828,11 @@
ps = mSettings.peekPackageLP(pkg.packageName);
updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
}
+ // Verify certificates first
+ if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
+ Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
+ return null;
+ }
if (updatedPkg != null) {
// An updated system app will not have the PARSE_IS_SYSTEM flag set initially
parseFlags |= PackageParser.PARSE_IS_SYSTEM;
@@ -1846,16 +1850,19 @@
return null;
} else {
// Delete the older apk pointed to by ps
+ // 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
+ synchronized (mPackages) {
+ // Just remove the loaded entries from package lists.
+ mPackages.remove(ps.name);
+ }
deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
mSettings.enableSystemPackageLP(ps.name);
}
}
}
}
- if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
- Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
- return null;
- }
// The apk is forward locked (not public) if its code and resources
// are kept in different files.
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
@@ -2135,7 +2142,7 @@
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
- pkg.applicationInfo.publicSourceDir = pkgSetting.resourcePathString;
+ pkg.applicationInfo.publicSourceDir = destResourceFile.toString();
File dataPath;
if (mPlatformPackage == pkg) {
@@ -2262,15 +2269,26 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
+ // We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
pkg.mPath = destCodeFile.getAbsolutePath();
mAppDirs.put(pkg.mPath, pkg);
}
+ // Request the ActivityManager to kill the process(only for existing packages)
+ // so that we do not end up in a confused state while the user is still using the older
+ // version of the application while the new one gets installed.
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if ((am != null) && ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING ) != 0)) {
+ try {
+ am.killApplicationWithUid(pkg.applicationInfo.packageName,
+ pkg.applicationInfo.uid);
+ } catch (RemoteException e) {
+ }
+ }
synchronized (mPackages) {
- // We don't expect installation to fail beyond this point
// Add the new setting to mSettings
- mSettings.insertPackageSettingLP(pkgSetting, pkg.packageName, suid);
+ mSettings.insertPackageSettingLP(pkgSetting, pkg, destCodeFile, destResourceFile);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
int N = pkg.providers.size();
@@ -2958,7 +2976,8 @@
}
if ((addedPermission || replace) && !ps.permissionsFixed &&
- (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) ||
+ ((ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)){
// This is the first that we have heard about this package, so the
// permissions we have now selected are fixed until explicitly
// changed.
@@ -4159,7 +4178,9 @@
private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
int flags) {
String packageName = p.packageName;
- outInfo.removedPackage = packageName;
+ if (outInfo != null) {
+ outInfo.removedPackage = packageName;
+ }
removePackageLI(p, true);
// Retrieve object to delete permissions for shared user later on
PackageSetting deletedPs;
@@ -4181,7 +4202,9 @@
dataDir.delete();
}
synchronized (mPackages) {
- outInfo.removedUid = mSettings.removePackageLP(packageName);
+ if (outInfo != null) {
+ outInfo.removedUid = mSettings.removePackageLP(packageName);
+ }
}
}
synchronized (mPackages) {
@@ -4256,7 +4279,7 @@
}
return true;
}
-
+
private void deletePackageResourcesLI(String packageName,
String sourceDir, String publicSourceDir) {
File sourceFile = new File(sourceDir);
@@ -4286,7 +4309,9 @@
Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
return false;
}
- outInfo.uid = applicationInfo.uid;
+ if (outInfo != null) {
+ outInfo.uid = applicationInfo.uid;
+ }
// Delete package data from internal structures and also remove data if flag is set
removePackageDataLI(p, outInfo, flags);
@@ -5463,7 +5488,7 @@
String resourcePathString;
private long timeStamp;
private String timeStampString = "0";
- final int versionCode;
+ int versionCode;
PackageSignatures signatures = new PackageSignatures();
@@ -5701,10 +5726,6 @@
final String name = pkg.packageName;
PackageSetting p = getPackageLP(name, sharedUser, codePath,
resourcePath, pkg.mVersionCode, pkgFlags, create, add);
-
- if (p != null) {
- p.pkg = pkg;
- }
return p;
}
@@ -5852,22 +5873,18 @@
if (p != null) {
if (!p.codePath.equals(codePath)) {
// Check to see if its a disabled system app
- PackageSetting ps = mDisabledSysPackages.get(name);
- if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ if((p != null) && ((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.
- return p;
+ Log.w(TAG, "Trying to update system app code path from " +
+ p.codePathString + " to " + codePath.toString());
} else {
// Let the app continue with previous uid if code path changes.
reportSettingsProblem(Log.WARN,
"Package " + name + " codePath changed from " + p.codePath
+ " to " + codePath + "; Retaining data and using new code from " +
codePath);
- p.codePath = codePath;
- p.resourcePath = resourcePath;
- p.codePathString = codePath.toString();
- p.resourcePathString = resourcePath.toString();
}
} else if (p.sharedUser != sharedUser) {
reportSettingsProblem(Log.WARN,
@@ -5891,8 +5908,29 @@
if (sharedUser != null) {
p.userId = sharedUser.userId;
} else if (MULTIPLE_APPLICATION_UIDS) {
- // Assign new user id
- p.userId = newUserIdLP(p);
+ // 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);
+ p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
+ // 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;
}
@@ -5904,15 +5942,39 @@
if (add) {
// Finish adding new package by adding it and updating shared
// user preferences
- insertPackageSettingLP(p, name, sharedUser);
+ addPackageSettingLP(p, name, sharedUser);
}
}
return p;
}
-
+
+ private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg,
+ File codePath, File resourcePath) {
+ p.pkg = pkg;
+ // Update code path if needed
+ if (!codePath.toString().equalsIgnoreCase(p.codePathString)) {
+ Log.w(TAG, "Code path for pkg : " + p.pkg.packageName +
+ " changing form " + p.codePathString + " to " + codePath);
+ p.codePath = codePath;
+ p.codePathString = codePath.toString();
+ }
+ //Update resource path if needed
+ if (!resourcePath.toString().equalsIgnoreCase(p.resourcePathString)) {
+ Log.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
+ " changing form " + p.resourcePathString + " to " + resourcePath);
+ p.resourcePath = resourcePath;
+ p.resourcePathString = resourcePath.toString();
+ }
+ // Update version code if needed
+ if (pkg.mVersionCode != p.versionCode) {
+ p.versionCode = pkg.mVersionCode;
+ }
+ addPackageSettingLP(p, pkg.packageName, p.sharedUser);
+ }
+
// Utility method that adds a PackageSetting to mPackages and
// completes updating the shared user attributes
- private void insertPackageSettingLP(PackageSetting p, String name,
+ private void addPackageSettingLP(PackageSetting p, String name,
SharedUserSetting sharedUser) {
mPackages.put(name, p);
if (sharedUser != null) {
@@ -6005,7 +6067,7 @@
}
if (mUserIds.get(index) != null) {
reportSettingsProblem(Log.ERROR,
- "Adding duplicate shared id: " + uid
+ "Adding duplicate user id: " + uid
+ " name=" + name);
return false;
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 79d78ad1..a3c3436 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -29,6 +29,10 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
@@ -58,7 +62,8 @@
import java.util.Observable;
import java.util.Observer;
-class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
+class PowerManagerService extends IPowerManager.Stub
+ implements LocalPowerManager,Watchdog.Monitor, SensorEventListener {
private static final String TAG = "PowerManagerService";
static final String PARTIAL_NAME = "PowerManagerService";
@@ -72,7 +77,8 @@
private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.SCREEN_DIM_WAKE_LOCK
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.FULL_WAKE_LOCK;
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
// time since last state: time since last event:
// The short keylight delay comes from Gservices; this is the default.
@@ -138,6 +144,7 @@
private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private int[] mBroadcastWhy = new int[3];
private int mPartialCount = 0;
+ private int mProximityCount = 0;
private int mPowerState;
private boolean mOffBecauseOfUser;
private int mUserState;
@@ -175,6 +182,8 @@
private IActivityManager mActivityService;
private IBatteryStats mBatteryStats;
private BatteryService mBatteryService;
+ private SensorManager mSensorManager;
+ private Sensor mProximitySensor;
private boolean mDimScreen = true;
private long mNextTimeout;
private volatile int mPokey = 0;
@@ -536,6 +545,7 @@
wl.minState = SCREEN_DIM;
break;
case PowerManager.PARTIAL_WAKE_LOCK:
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
// just log and bail. we're in the server, so don't
@@ -583,6 +593,11 @@
}
}
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
+ } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount++;
+ if (mProximityCount == 1) {
+ enableProximityLockLocked();
+ }
}
if (newlock) {
acquireUid = wl.uid;
@@ -639,6 +654,11 @@
if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
Power.releaseWakeLock(PARTIAL_NAME);
}
+ } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount--;
+ if (mProximityCount == 0) {
+ disableProximityLockLocked();
+ }
}
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
@@ -1996,4 +2016,47 @@
public void monitor() {
synchronized (mLocks) { }
}
+
+ public int getSupportedWakeLockFlags() {
+ int result = PowerManager.PARTIAL_WAKE_LOCK
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.SCREEN_DIM_WAKE_LOCK;
+
+ // call getSensorManager() to make sure mProximitySensor is initialized
+ getSensorManager();
+ if (mProximitySensor != null) {
+ result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
+ }
+
+ return result;
+ }
+
+ private SensorManager getSensorManager() {
+ if (mSensorManager == null) {
+ mSensorManager = new SensorManager(mHandlerThread.getLooper());
+ mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ }
+ return mSensorManager;
+ }
+
+ private void enableProximityLockLocked() {
+ mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ private void disableProximityLockLocked() {
+ mSensorManager.unregisterListener(this);
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ long milliseconds = event.timestamp / 1000000;
+ if (event.values[0] == 0.0) {
+ goToSleep(milliseconds);
+ } else {
+ userActivity(milliseconds, false);
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // ignore
+ }
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 78ca831..edba5b6 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8231,7 +8231,9 @@
// This has changed the visibility of windows, so perform
// a new layout to get them all up-to-date.
mLayoutNeeded = true;
- moveInputMethodWindowsIfNeededLocked(true);
+ if (!moveInputMethodWindowsIfNeededLocked(true)) {
+ assignLayersLocked();
+ }
performLayoutLockedInner();
updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8a4b8f9..7bd2532 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4742,7 +4742,30 @@
Binder.restoreCallingIdentity(callingId);
}
}
-
+
+ /*
+ * The pkg name and uid have to be specified.
+ * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
+ */
+ public void killApplicationWithUid(String pkg, int uid) {
+ if (pkg == null) {
+ return;
+ }
+ // Make sure the uid is valid.
+ if (uid < 0) {
+ Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
+ return;
+ }
+ int callerUid = Binder.getCallingUid();
+ // Only the system server can kill an application
+ if (callerUid == Process.SYSTEM_UID) {
+ uninstallPackageLocked(pkg, uid, false);
+ } else {
+ throw new SecurityException(callerUid + " cannot kill pkg: " +
+ pkg);
+ }
+ }
+
private void restartPackageLocked(final String packageName, int uid) {
uninstallPackageLocked(packageName, uid, false);
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 775b034..fc491d7 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -278,8 +278,8 @@
public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
int activePhone = TelephonyManager.getDefault().getPhoneType();
TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
- com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly) :
- com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly);
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly) :
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
int ret[] = new int[4];
ret[0] = ted.msgCount;
ret[1] = ted.codeUnitCount;
@@ -299,8 +299,8 @@
public static ArrayList<String> fragmentText(String text) {
int activePhone = TelephonyManager.getDefault().getPhoneType();
TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
- com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false) :
- com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false);
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) :
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);
// TODO(cleanup): The code here could be rolled into the logic
// below cleanly if these MAX_* constants were defined more
@@ -321,11 +321,8 @@
while (pos < textLen) {
int nextPos = 0; // Counts code units.
if (ted.codeUnitSize == ENCODING_7BIT) {
- if (PHONE_TYPE_CDMA == activePhone) {
- nextPos = pos + Math.min(limit, textLen - pos);
- } else {
- nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit);
- }
+ // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
+ nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit);
} else { // Assume unicode.
nextPos = pos + Math.min(limit / 2, textLen - pos);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index aec7aee..dda0187 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1057,6 +1057,7 @@
onComplete.sendToTarget();
}
}
+ break;
default:{
throw new RuntimeException("unexpected event not handled");
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index cc456c5..7788c75 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -668,8 +668,8 @@
// the hangup reason is user ignoring or timing out. So conn.onDisconnect()
// is not called here. Instead, conn.onLocalDisconnect() is called.
conn.onLocalDisconnect();
- phone.notifyPreciseCallStateChanged();
updatePhoneState();
+ phone.notifyPreciseCallStateChanged();
return;
} else {
try {
@@ -957,6 +957,7 @@
if (ar.exception == null) {
// Assume 3 way call is connected
pendingMO.onConnectedInOrOut();
+ pendingMO = null;
}
break;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 13cea99..c71003b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -798,23 +798,34 @@
return null;
}
- private static void decodeMessageId(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 3) {
- throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 3 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.messageType = inStream.read(4);
+ bData.messageId = inStream.read(8) << 8;
+ bData.messageId |= inStream.read(8);
+ bData.hasUserDataHeader = (inStream.read(1) == 1);
+ inStream.skip(3);
}
- bData.messageType = inStream.read(4);
- bData.messageId = inStream.read(8) << 8;
- bData.messageId |= inStream.read(8);
- bData.hasUserDataHeader = (inStream.read(1) == 1);
- inStream.skip(3);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeUserData(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException
{
- int paramBytes = inStream.read(8);
+ int paramBits = inStream.read(8) * 8;
bData.userData = new UserData();
bData.userData.msgEncoding = inStream.read(5);
bData.userData.msgEncodingSet = true;
@@ -827,8 +838,9 @@
}
bData.userData.numFields = inStream.read(8);
consumedBits += 8;
- int dataBits = (paramBytes * 8) - consumedBits;
+ int dataBits = paramBits - consumedBits;
bData.userData.payload = inStream.readByteArray(dataBits);
+ return true;
}
private static String decodeUtf16(byte[] data, int offset, int numFields)
@@ -1081,36 +1093,68 @@
}
}
- private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- int paramBytes = inStream.read(8);
- if (paramBytes != 1) {
- throw new CodingException("REPLY_OPTION subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.userAckReq = (inStream.read(1) == 1);
+ bData.deliveryAckReq = (inStream.read(1) == 1);
+ bData.readAckReq = (inStream.read(1) == 1);
+ bData.reportReq = (inStream.read(1) == 1);
+ inStream.skip(4);
}
- bData.userAckReq = (inStream.read(1) == 1);
- bData.deliveryAckReq = (inStream.read(1) == 1);
- bData.readAckReq = (inStream.read(1) == 1);
- bData.reportReq = (inStream.read(1) == 1);
- inStream.skip(4);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "REPLY_OPTION decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("NUMBER_OF_MESSAGES subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.numberOfMessages = inStream.read(8);
}
- bData.numberOfMessages = inStream.read(8);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 2) {
- throw new CodingException("MESSAGE_DEPOSIT_INDEX subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 2 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
}
- bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
@@ -1144,10 +1188,10 @@
}
}
- private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- int paramBytes = inStream.read(8);
+ int paramBits = inStream.read(8) * 8;
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.digitMode = inStream.read(1);
byte fieldBits = 4;
@@ -1160,140 +1204,274 @@
}
addr.numberOfDigits = inStream.read(8);
consumedBits += 8;
- int remainingBits = (paramBytes * 8) - consumedBits;
+ int remainingBits = paramBits - consumedBits;
int dataBits = addr.numberOfDigits * fieldBits;
int paddingBits = remainingBits - dataBits;
if (remainingBits < dataBits) {
throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
- "remainingBits " + remainingBits + ", dataBits " +
- dataBits + ", paddingBits " + paddingBits + ")");
+ "remainingBits + " + remainingBits + ", dataBits + " +
+ dataBits + ", paddingBits + " + paddingBits + ")");
}
addr.origBytes = inStream.readByteArray(dataBits);
inStream.skip(paddingBits);
decodeSmsAddress(addr);
bData.callbackNumber = addr;
+ return true;
}
- private static void decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("MESSAGE_STATUS subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.errorClass = inStream.read(2);
+ bData.messageStatus = inStream.read(6);
}
- bData.errorClass = inStream.read(2);
- bData.messageStatus = inStream.read(6);
- bData.messageStatusSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_STATUS decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.messageStatusSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("VALIDITY_PERIOD_ABSOLUTE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("DEFERRED_DELIVERY_TIME_ABSOLUTE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
+ inStream.readByteArray(6 * 8));
}
- bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("VALIDITY_PERIOD_RELATIVE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.deferredDeliveryTimeRelative = inStream.read(8);
}
- bData.deferredDeliveryTimeRelative = inStream.read(8);
- bData.deferredDeliveryTimeRelativeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.deferredDeliveryTimeRelativeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("DEFERRED_DELIVERY_TIME_RELATIVE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.validityPeriodRelative = inStream.read(8);
}
- bData.validityPeriodRelative = inStream.read(8);
- bData.validityPeriodRelativeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.validityPeriodRelativeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("PRIVACY_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.privacy = inStream.read(2);
+ inStream.skip(6);
}
- bData.privacy = inStream.read(2);
- inStream.skip(6);
- bData.privacyIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.privacyIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("LANGUAGE_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.language = inStream.read(8);
}
- bData.language = inStream.read(8);
- bData.languageIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.languageIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("DISPLAY_MODE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.displayMode = inStream.read(2);
+ inStream.skip(6);
}
- bData.displayMode = inStream.read(2);
- inStream.skip(6);
- bData.displayModeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DISPLAY_MODE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.displayModeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("PRIORITY_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.priority = inStream.read(2);
+ inStream.skip(6);
}
- bData.priority = inStream.read(2);
- inStream.skip(6);
- bData.priorityIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.priorityIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("ALERT_ON_MESSAGE_DELIVERY subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.alert = inStream.read(2);
+ inStream.skip(6);
}
- bData.alert = inStream.read(2);
- inStream.skip(6);
- bData.alertIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.alertIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("USER_REPONSE_CODE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.userResponseCode = inStream.read(8);
}
- bData.userResponseCode = inStream.read(8);
- bData.userResponseCodeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "USER_REPONSE_CODE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.userResponseCodeSet = decodeSuccess;
+ return decodeSuccess;
}
/**
@@ -1310,72 +1488,73 @@
BearerData bData = new BearerData();
int foundSubparamMask = 0;
while (inStream.available() > 0) {
+ boolean decodeSuccess = false;
int subparamId = inStream.read(8);
int subparamIdBit = 1 << subparamId;
if ((foundSubparamMask & subparamIdBit) != 0) {
throw new CodingException("illegal duplicate subparameter (" +
subparamId + ")");
}
- foundSubparamMask |= subparamIdBit;
switch (subparamId) {
case SUBPARAM_MESSAGE_IDENTIFIER:
- decodeMessageId(bData, inStream);
+ decodeSuccess = decodeMessageId(bData, inStream);
break;
case SUBPARAM_USER_DATA:
- decodeUserData(bData, inStream);
+ decodeSuccess = decodeUserData(bData, inStream);
break;
case SUBPARAM_USER_REPONSE_CODE:
- decodeUserResponseCode(bData, inStream);
+ decodeSuccess = decodeUserResponseCode(bData, inStream);
break;
case SUBPARAM_REPLY_OPTION:
- decodeReplyOption(bData, inStream);
+ decodeSuccess = decodeReplyOption(bData, inStream);
break;
case SUBPARAM_NUMBER_OF_MESSAGES:
- decodeMsgCount(bData, inStream);
+ decodeSuccess = decodeMsgCount(bData, inStream);
break;
case SUBPARAM_CALLBACK_NUMBER:
- decodeCallbackNumber(bData, inStream);
+ decodeSuccess = decodeCallbackNumber(bData, inStream);
break;
case SUBPARAM_MESSAGE_STATUS:
- decodeMsgStatus(bData, inStream);
+ decodeSuccess = decodeMsgStatus(bData, inStream);
break;
case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
- decodeMsgCenterTimeStamp(bData, inStream);
+ decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
- decodeValidityAbs(bData, inStream);
+ decodeSuccess = decodeValidityAbs(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
- decodeValidityRel(bData, inStream);
+ decodeSuccess = decodeValidityRel(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
- decodeDeferredDeliveryAbs(bData, inStream);
+ decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
- decodeDeferredDeliveryRel(bData, inStream);
+ decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
break;
case SUBPARAM_PRIVACY_INDICATOR:
- decodePrivacyIndicator(bData, inStream);
+ decodeSuccess = decodePrivacyIndicator(bData, inStream);
break;
case SUBPARAM_LANGUAGE_INDICATOR:
- decodeLanguageIndicator(bData, inStream);
+ decodeSuccess = decodeLanguageIndicator(bData, inStream);
break;
case SUBPARAM_MESSAGE_DISPLAY_MODE:
- decodeDisplayMode(bData, inStream);
+ decodeSuccess = decodeDisplayMode(bData, inStream);
break;
case SUBPARAM_PRIORITY_INDICATOR:
- decodePriorityIndicator(bData, inStream);
+ decodeSuccess = decodePriorityIndicator(bData, inStream);
break;
case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
- decodeMsgDeliveryAlert(bData, inStream);
+ decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
break;
case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
- decodeDepositIndex(bData, inStream);
+ decodeSuccess = decodeDepositIndex(bData, inStream);
break;
default:
throw new CodingException("unsupported bearer data subparameter ("
+ subparamId + ")");
}
+ if (decodeSuccess) foundSubparamMask |= subparamIdBit;
}
if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
diff --git a/test-runner/android/test/ProviderTestCase2.java b/test-runner/android/test/ProviderTestCase2.java
index ac17ebf..a923d2a 100644
--- a/test-runner/android/test/ProviderTestCase2.java
+++ b/test-runner/android/test/ProviderTestCase2.java
@@ -3,6 +3,7 @@
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.test.mock.MockContext;
import android.test.mock.MockContentResolver;
import android.database.DatabaseUtils;
@@ -26,6 +27,14 @@
private IsolatedContext mProviderContext;
private MockContentResolver mResolver;
+ private class MockContext2 extends MockContext {
+
+ @Override
+ public Resources getResources() {
+ return getContext().getResources();
+ }
+ }
+
public ProviderTestCase2(Class<T> providerClass, String providerAuthority) {
mProviderClass = providerClass;
mProviderAuthority = providerAuthority;
@@ -47,7 +56,7 @@
mResolver = new MockContentResolver();
final String filenamePrefix = "test.";
RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
- new MockContext(), // The context that most methods are delegated to
+ new MockContext2(), // The context that most methods are delegated to
getContext(), // The context that file methods are delegated to
filenamePrefix);
mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index b83a44d6..9fb1e61 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -110,6 +110,7 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
public File getSharedPrefsFile(String name) {
throw new UnsupportedOperationException();
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 90a2917..528545c 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -637,6 +637,16 @@
BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4));
assertEquals(bd4.alert, 3);
assertEquals(bd4.userData.payloadStr, "Test Alert 3");
+ String pdu5 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" +
+ "69ED979794187665E5D1028EFA7A6840E1062D3D39A900C028000";
+ BearerData bd5 = BearerData.decode(HexDump.hexStringToByteArray(pdu5));
+ assertEquals(bd5.alert, BearerData.ALERT_MEDIUM_PRIO);
+ assertEquals(bd5.userData.payloadStr, "test message delivery alert (with 8 bits)");
+ String pdu6 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" +
+ "69ED979794187665E5D1028EFA7A6840C1062D3D39A900C00";
+ BearerData bd6 = BearerData.decode(HexDump.hexStringToByteArray(pdu6));
+ assertEquals(bd6.userData.payloadStr, "test message delivery alert (with 0 bits)");
+ assertEquals(bd6.alertIndicatorSet, false);
}
@SmallTest
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a03490d..2eecef8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,6 +16,9 @@
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.AdbUtils;
+import com.android.dumprendertree.forwarder.ForwardServer;
+
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
@@ -42,7 +45,7 @@
private BufferedOutputStream mBufferedOutputFailedStream;
private BufferedOutputStream mBufferedOutputNoresultStream;
private BufferedOutputStream mBufferedOutputTimedoutStream;
-
+
public void passed(String layout_file) {
try {
mBufferedOutputPassedStream.write(layout_file.getBytes());
@@ -52,7 +55,7 @@
e.printStackTrace();
}
}
-
+
public void failed(String layout_file) {
try {
mBufferedOutputFailedStream.write(layout_file.getBytes());
@@ -62,7 +65,7 @@
e.printStackTrace();
}
}
-
+
public void noresult(String layout_file) {
try {
mBufferedOutputNoresultStream.write(layout_file.getBytes());
@@ -72,7 +75,7 @@
e.printStackTrace();
}
}
-
+
public void timedout(String url) {
try {
mBufferedOutputTimedoutStream.write(url.getBytes());
@@ -82,14 +85,14 @@
e.printStackTrace();
}
}
-
+
public MyTestRecorder(boolean resume) {
try {
File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
-
+
mBufferedOutputPassedStream =
new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
mBufferedOutputFailedStream =
@@ -102,7 +105,7 @@
e.printStackTrace();
}
}
-
+
public void close() {
try {
mBufferedOutputPassedStream.close();
@@ -120,7 +123,7 @@
private static final String LOGTAG = "LayoutTests";
static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-
+
static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
@@ -139,14 +142,35 @@
static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
+ static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+ static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+ static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+ static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+ static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
+
+ private ForwardServer fs8000, fs8080, fs8443;
+
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
private String mTestPathPrefix;
private boolean mFinished;
-
+
public LayoutTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
+
+ int addr = -1;
+ try {
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.e(LOGTAG, "failed to resolve server address.", ioe);
+ }
+ if(addr != -1) {
+ fs8000 = new ForwardServer(8000, addr, 8000);
+ fs8080 = new ForwardServer(8080, addr, 8080);
+ fs8443 = new ForwardServer(8443, addr, 8443);
+ }
}
// This function writes the result of the layout test to
@@ -157,7 +181,7 @@
bundle.putBoolean(file, result);
inst.sendStatus(0, bundle);
}
-
+
private void getTestList() {
// Read test list.
try {
@@ -174,7 +198,7 @@
Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
}
}
-
+
private void resumeTestList() {
// read out the test name it stoped last time.
try {
@@ -189,7 +213,7 @@
Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
}
}
-
+
private void clearTestStatus() {
// Delete TEST_STATUS_FILE
try {
@@ -208,13 +232,13 @@
// Write actual results to result directory.
return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
}
-
+
private String getExpectedResultFile(String test) {
int pos = test.lastIndexOf('.');
if(pos == -1)
return null;
String shortName = test.substring(0, pos);
- return shortName + "-expected.txt";
+ return shortName + "-expected.txt";
}
private String getAndroidExpectedResultFile(String expectedResultFile) {
@@ -224,7 +248,7 @@
// Wrap up
private void failedCase(String file) {
Log.w("Layout test: ", file + " failed");
- mResultRecorder.failed(file);
+ mResultRecorder.failed(file);
}
private void passedCase(String file) {
@@ -236,7 +260,7 @@
Log.v("Layout test:", file + " no expected result");
mResultRecorder.noresult(file);
}
-
+
private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
Log.v(LOGTAG, " Processing result: " + testFile);
@@ -257,13 +281,13 @@
break;
}
}
-
+
if (passing) {
passedCase(testFile);
} else {
failedCase(testFile);
}
-
+
fe.close();
fr.close();
} catch (FileNotFoundException ex) {
@@ -278,7 +302,7 @@
noresultCase(testFile);
}
}
-
+
private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
activity.setCallback(new TestShellCallback() {
public void finished() {
@@ -287,7 +311,7 @@
LayoutTestsAutoTest.this.notifyAll();
}
}
-
+
public void timedOut(String url) {
}
});
@@ -306,16 +330,16 @@
resultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
mFinished = false;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(activity, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
activity.startActivity(intent);
-
+
// Wait until done.
synchronized (this) {
while(!mFinished){
@@ -324,18 +348,18 @@
} catch (InterruptedException e) { }
}
}
-
+
if (!mRebaselineResults) {
String expectedResultFile = getExpectedResultFile(test);
File f = new File(expectedResultFile);
if (!f.exists()) {
expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
processResult(test, resultFile, expectedResultFile);
}
- }
-
+ }
+
// Invokes running of layout tests
// and waits till it has finished running.
public void executeLayoutTests(boolean resume) {
@@ -348,28 +372,28 @@
}
this.mTestList = new Vector<String>();
-
+
// Read settings
try {
this.mTestPathPrefix =
(new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
- } catch (IOException e) {
+ } catch (IOException e) {
Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
return;
}
-
+
this.mRebaselineResults = runner.mRebaseline;
-
+
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {
timeout = DEFAULT_TIMEOUT_IN_MILLIS;
}
-
+
this.mResultRecorder = new MyTestRecorder(resume);
-
+
if (!resume)
clearTestStatus();
-
+
getTestList();
if (resume)
resumeTestList();
@@ -377,6 +401,15 @@
TestShellActivity activity = (TestShellActivity) getActivity();
// Run tests.
+ int addr = -1;
+ try{
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while resolving test host name", ioe);
+ }
+ if(addr == -1) {
+ Log.w(LOGTAG, "failed to resolve test host. http tests will fail.");
+ }
for (int i = 0; i < mTestList.size(); i++) {
String s = mTestList.elementAt(i);
FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
@@ -385,10 +418,48 @@
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-
+ if(fs8000 != null)
+ fs8000.stop();
+ if(fs8080 != null)
+ fs8080.stop();
+ if(fs8443 != null)
+ fs8443.stop();
+
activity.finish();
}
+ private void startForwardServerIfNeeded() {
+ try {
+ if(fs8000 != null)
+ fs8000.start();
+ if(fs8080 != null)
+ fs8080.start();
+ if(fs8443 != null)
+ fs8443.start();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+ }
+ }
+
+ private String getTestUrl(String path) {
+ String url = null;
+ if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+ url = "file://" + path;
+ } else {
+ startForwardServerIfNeeded();
+ if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+ // still cut the URL after "http/tests/"
+ url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+ && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+ && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else {
+ url = "file://" + path;
+ }
+ }
+ return url;
+ }
private String getTestPath() {
LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
@@ -403,10 +474,10 @@
Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
}
Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-
+
return test_path;
}
-
+
public void generateTestList() {
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
@@ -431,7 +502,7 @@
} catch (Exception e) {
e.printStackTrace();
}
-
+
executeLayoutTests(false);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 48c1e5d..30e1d99 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -531,8 +531,14 @@
}
@Override
+ public boolean onJsTimeout() {
+ Log.v(LOGTAG, "JavaScript timeout");
+ return false;
+ }
+
+ @Override
public void onExceededDatabaseQuota(String url_str,
- String databaseIdentifier, long currentQuota,
+ String databaseIdentifier, long currentQuota, long totalUsedQuota,
WebStorage.QuotaUpdater callback) {
if (mDumpDatabaseCallbacks) {
if (mDatabaseCallbackStrings == null) {
@@ -614,6 +620,9 @@
}
WebSettings settings = webview.getSettings();
+ settings.setAppCacheEnabled(true);
+ settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
+ settings.setAppCacheMaxSize(Long.MAX_VALUE);
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setSupportMultipleWindows(true);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
new file mode 100644
index 0000000..9a3e9c2
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -0,0 +1,112 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class AdbUtils {
+
+ private static final String ADB_OK = "OKAY";
+ private static final int ADB_PORT = 5037;
+ private static final String ADB_HOST = "127.0.0.1";
+ private static final int ADB_RESPONSE_SIZE = 4;
+
+ private static final String LOGTAG = "AdbUtils";
+
+ /**
+ *
+ * Convert integer format IP into xxx.xxx.xxx.xxx format
+ *
+ * @param host IP address in integer format
+ * @return human readable format
+ */
+ public static String convert(int host) {
+ return ((host >> 24) & 0xFF) + "."
+ + ((host >> 16) & 0xFF) + "."
+ + ((host >> 8) & 0xFF) + "."
+ + (host & 0xFF);
+ }
+
+ /**
+ *
+ * Resolve DNS name into IP address
+ *
+ * @param host DNS name
+ * @return IP address in integer format
+ * @throws IOException
+ */
+ public static int resolve(String host) throws IOException {
+ Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
+ DataInputStream dis = new DataInputStream(localSocket.getInputStream());
+ OutputStream os = localSocket.getOutputStream();
+ int count_read = 0;
+ byte[] buf = new byte[128];
+
+ if (localSocket == null || dis == null || os == null)
+ return -1;
+ String cmd = "dns:" + host;
+
+ if(!sendAdbCmd(dis, os, cmd))
+ return -1;
+
+ count_read = dis.readInt();
+ localSocket.close();
+ return count_read;
+ }
+
+ /**
+ *
+ * Send an ADB command using existing socket connection
+ *
+ * the streams provided must be from a socket connected to adbd already
+ *
+ * @param is input stream of the socket connection
+ * @param os output stream of the socket
+ * @param cmd the adb command to send
+ * @return if adb gave a success response
+ * @throws IOException
+ */
+ public static boolean sendAdbCmd(InputStream is, OutputStream os,
+ String cmd) throws IOException {
+ byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+ cmd = String.format("%04X", cmd.length()) + cmd;
+ os.write(cmd.getBytes());
+ int read = is.read(buf);
+ if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+ Log.w(LOGTAG, "adb cmd faild.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Get a tcp socket connection to specified IP address and port proxied by adb
+ *
+ * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+ * read from as if it is directly connected to the target
+ *
+ * @param remoteAddress IP address of the host to connect to
+ * @param remotePort port of the host to connect to
+ * @return a valid Socket instance if successful, null otherwise
+ */
+ public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
+ try {
+ Socket socket = new Socket(ADB_HOST, ADB_PORT);
+ String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
+ if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error creating adb socket", ioe);
+ return null;
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
new file mode 100644
index 0000000..74e018e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -0,0 +1,117 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * A port forwarding server. Listens at specified local port and forward the tcp communications to
+ * external host/port via adb networking proxy.
+ *
+ */
+public class ForwardServer {
+
+ private static final String LOGTAG = "ForwardServer";
+
+ private int remotePort;
+ private int remoteAddress;
+ private int localPort;
+ private ServerSocket serverSocket;
+ private boolean started;
+
+ private Set<Forwarder> forwarders;
+
+ public ForwardServer(int localPort, int remoteAddress, int remotePort) {
+ this.localPort = localPort;
+ this.remoteAddress = remoteAddress;
+ this.remotePort = remotePort;
+ started = false;
+ forwarders = new HashSet<Forwarder>();
+ }
+
+ public synchronized void start() throws IOException {
+ if(!started) {
+ serverSocket = new ServerSocket(localPort);
+ Thread serverThread = new Thread(new ServerRunner(serverSocket));
+ serverThread.setName(LOGTAG);
+ serverThread.start();
+ started = true;
+ }
+ }
+
+ public synchronized void stop() {
+ if(started) {
+ synchronized (forwarders) {
+ for(Forwarder forwarder : forwarders)
+ forwarder.stop();
+ forwarders.clear();
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException ioe) {
+ Log.v(LOGTAG, "exception while closing", ioe);
+ } finally {
+ started = false;
+ }
+ }
+ }
+
+ public synchronized boolean isRunning() {
+ return started;
+ }
+
+ private class ServerRunner implements Runnable {
+
+ private ServerSocket socket;
+
+ public ServerRunner(ServerSocket socket) {
+ this.socket = socket;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ Socket localSocket = socket.accept();
+ Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
+ if(remoteSocket == null) {
+ try {
+ localSocket.close();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while closing socket", ioe);
+ } finally {
+ Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
+ }
+ } else {
+ Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
+ ForwardServer.this);
+ forwarder.start();
+ }
+ }
+ } catch (IOException ioe) {
+ return;
+ }
+ }
+ }
+
+ public void register(Forwarder forwarder) {
+ synchronized (forwarders) {
+ if(!forwarders.contains(forwarder)) {
+ forwarders.add(forwarder);
+ }
+ }
+ }
+
+ public void unregister(Forwarder recyclable) {
+ synchronized (forwarders) {
+ if(forwarders.contains(recyclable)) {
+ recyclable.stop();
+ forwarders.remove(recyclable);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
new file mode 100644
index 0000000..e1e04a7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -0,0 +1,92 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ *
+ * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ *
+ */
+public class Forwarder {
+
+ private ForwardServer server;
+ private Socket from, to;
+
+ private static final String LOGTAG = "Forwarder";
+
+ public Forwarder (Socket from, Socket to, ForwardServer server) {
+ this.server = server;
+ this.from = from;
+ this.to = to;
+ server.register(this);
+ }
+
+ public void start() {
+ Thread outgoing = new Thread(new SocketPipe(from, to));
+ Thread incoming = new Thread(new SocketPipe(to, from));
+ outgoing.setName(LOGTAG);
+ incoming.setName(LOGTAG);
+ outgoing.start();
+ incoming.start();
+ }
+
+ public void stop() {
+ shutdown(from);
+ shutdown(to);
+ }
+
+ private void shutdown(Socket socket) {
+ try {
+ socket.shutdownInput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownInput", e);
+ }
+ try {
+ socket.shutdownOutput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownOutput", e);
+ }
+ try {
+ socket.close();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#close", e);
+ }
+ }
+
+ private class SocketPipe implements Runnable {
+
+ private Socket in, out;
+
+ public SocketPipe(Socket in, Socket out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ int length;
+ InputStream is = in.getInputStream();
+ OutputStream os = out.getOutputStream();
+ byte[] buffer = new byte[4096];
+ while ((length = is.read(buffer)) > 0) {
+ os.write(buffer, 0, length);
+ }
+ } catch (IOException ioe) {
+ } finally {
+ server.unregister(Forwarder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SocketPipe{" + in + "=>" + out + "}";
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 12abce5..083cda3 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1467,6 +1467,7 @@
public synchronized boolean restart() {
if (mRunState == RUN_STATE_STOPPED) {
mRunState = RUN_STATE_STARTING;
+ resetInterface(true);
return WifiNative.startDriverCommand();
} else if (mRunState == RUN_STATE_STOPPING) {
mRunState = RUN_STATE_STARTING;