diff options
133 files changed, 4006 insertions, 1303 deletions
diff --git a/api/4.xml b/api/4.xml index c8a2e83fd136..cac3ae82fc80 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 c81997273f4a..b1e9c83eee00 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 e2d01de95a0a..f101007419fd 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -202,7 +202,6 @@ bool BootAnimation::android() { // 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 @@ bool BootAnimation::android() { 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 346f156f97e9..3c82fe52dba9 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 @@ int main(int argc, char** argv) 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) { + + sp<ProcessState> proc(ProcessState::self()); + ProcessState::self()->startThreadPool(); + + // create the boot animation object + sp<BootAnimation> boot = new BootAnimation(); - // create the boot animation object - sp<BootAnimation> boot = new BootAnimation(); + IPCThreadState::self()->joinThreadPool(); - IPCThreadState::self()->joinThreadPool(); + } return 0; } diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index 12bdead5c37c..d8db8b3ed4a1 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -119,7 +119,8 @@ int main(int argc, char **argv) { 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 961942ad7ca2..7e2357458248 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -102,6 +102,7 @@ static int64_t getNowUs() { 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 @@ int main(int argc, char **argv) { } return 0; + } else if (argc > 1 && !strcmp(argv[1], "--audio")) { + audioOnly = true; + ++argv; + --argc; } #if 0 @@ -149,7 +154,11 @@ int main(int argc, char **argv) { 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 a3456c756404..79bd6e7f55b1 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -163,6 +163,10 @@ public abstract class AccessibilityService extends Service { } } + /** + * 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 ba6cc32808d4..3aeac538f044 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1085,6 +1085,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ class ActivityManagerProxy implements IActivityManager 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 e21b1d9689b8..32a289122cf2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3634,7 +3634,7 @@ public final class ActivityThread { 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 95b376cce673..b1b52824bfae 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -266,6 +266,8 @@ public interface IActivityManager extends IInterface { 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 @@ public interface IActivityManager extends IInterface { 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 f9c38f998c35..f7479bcdb8bf 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -273,11 +273,6 @@ public final class PendingIntent implements Parcelable { 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 final class PendingIntent implements Parcelable { * */ 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 dd70130eb9d0..e991bc6f8e31 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -51,6 +51,7 @@ import android.util.Log; 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 d6044145c2d2..57826444665a 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 @@ public class BluetoothPbap { /** 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 @@ public class BluetoothPbap { /** 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 @@ public class BluetoothPbap { } /** - * Create a BluetoothHeadset proxy object. + * Create a BluetoothPbap proxy object. */ public BluetoothPbap(Context context, ServiceListener l) { mContext = context; @@ -133,7 +129,7 @@ public class BluetoothPbap { /** * 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 @@ public class BluetoothPbap { } /** - * 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 @@ public class BluetoothPbap { 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 @@ public class BluetoothPbap { } /** - * 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 @@ public class BluetoothPbap { } /** - * 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 8b0b6ab0a979..c0db01a7db56 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -26,10 +26,14 @@ import java.util.Map; 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 @@ public class ContentProviderOperation implements Parcelable { 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 @@ public class ContentProviderOperation implements Parcelable { 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 @@ public class ContentProviderOperation implements Parcelable { } 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 c6c9835231bd..84449ef8f3c7 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1293,7 +1293,8 @@ public abstract class Context { * 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 45a082a9520e..15612cefcc27 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -135,6 +135,7 @@ public class ContextWrapper extends Context { 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 66b507dbea59..64ee60e265c1 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2412,7 +2412,7 @@ public class Intent implements Parcelable { /** * 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 4da49d974fd5..0e4d98498e8f 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -52,6 +52,9 @@ import android.util.AndroidException; * 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 @@ public class IntentSender implements Parcelable { 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 9ca11cd5c605..0a42a6faf9f4 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -131,8 +131,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { 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 a29c2c83cfbf..ec2e78c9df2f 100644 --- a/core/java/android/gesture/GestureLibrary.java +++ b/core/java/android/gesture/GestureLibrary.java @@ -35,6 +35,7 @@ public abstract class GestureLibrary { 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 5486920249cf..188e7ff09e50 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -26,6 +26,7 @@ interface IPowerManager 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 bfcf2fc2fbcd..d5934102c856 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -114,12 +114,14 @@ public class PowerManager 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 class PowerManager 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 @@ public class PowerManager 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 @@ public class PowerManager } 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 abdcd931db2d..db25cfa6a31a 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -28,6 +28,7 @@ import android.preference.PreferenceManager; 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 @@ import android.widget.SeekBar.OnSeekBarChangeListener; * @hide */ public class VolumePreference extends SeekBarPreference implements - PreferenceManager.OnActivityStopListener { + PreferenceManager.OnActivityStopListener, View.OnKeyListener { private static final String TAG = "VolumePreference"; @@ -66,6 +67,30 @@ public class VolumePreference extends SeekBarPreference implements 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 @@ public class VolumePreference extends SeekBarPreference implements } mRingtone = RingtoneManager.getRingtone(mContext, defaultUri); - mRingtone.setStreamType(mStreamType); + if (mRingtone != null) { + mRingtone.setStreamType(mStreamType); + } } public void stop() { @@ -215,5 +242,12 @@ public class VolumePreference extends SeekBarPreference implements 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 1fb5e1037f70..01189fe8cf43 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -113,7 +113,7 @@ public final class ContactsContract { 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 @@ public final class ContactsContract { /** * 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 @@ public final class ContactsContract { /** - * 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 @@ public final class ContactsContract { /** * 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 @@ public final class ContactsContract { /** * 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 @@ public final class ContactsContract { * 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 @@ public final class ContactsContract { /** * 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 @@ public final class ContactsContract { } } + @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 @@ public final class ContactsContract { 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 @@ -341,10 +346,9 @@ public final class ContactsContract { * 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 raw contact, it is marked for deletion and removed from its - * aggregate. The sync adaptor deletes the raw contact on the server and + * 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.RawContacts#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 @@ public final class ContactsContract { * 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 @@ -383,13 +386,13 @@ public final class ContactsContract { * 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 @@ -434,13 +437,6 @@ public final class ContactsContract { } } - /** - * 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,23 +451,21 @@ public final class ContactsContract { public static final String MIMETYPE = "mimetype"; /** - * A reference to the {@link android.provider.ContactsContract.RawContacts#_ID} + * A reference to the {@link RawContacts#_ID} * that this data belongs to. */ public static final String RAW_CONTACT_ID = "raw_contact_id"; - @Deprecated - public static final String 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"; @@ -545,7 +539,7 @@ public final class ContactsContract { * 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 */ @@ -565,7 +559,7 @@ public final class ContactsContract { /** * 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 { @@ -576,15 +570,11 @@ public final class ContactsContract { public static final String _ID = "presence_id"; /** - * Reference to the {@link android.provider.ContactsContract.RawContacts#_ID} this presence - * references. + * Reference to the {@link RawContacts#_ID} this presence references. * <P>Type: INTEGER</P> */ public static final String RAW_CONTACT_ID = "raw_contact_id"; - @Deprecated - public static final String CONTACT_ID = RAW_CONTACT_ID; - /** * Reference to the {@link Data#_ID} entry that owns this presence. * <P>Type: INTEGER</P> @@ -844,7 +834,7 @@ public final class ContactsContract { /** * The content:// style URI for all data records of the * {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the - * associated raw contact and aggregate data. + * associated raw contact and aggregate contact data. */ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI, "phones"); @@ -852,7 +842,7 @@ public final class ContactsContract { /** * The content:// style URI for filtering data records of the * {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the - * associated raw 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, @@ -1202,7 +1192,7 @@ public final class ContactsContract { 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> @@ -1211,7 +1201,7 @@ public final class ContactsContract { 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}. @@ -1299,34 +1289,33 @@ public final class ContactsContract { 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 raw 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 raw 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. + * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the + * aggregate contact that the rule applies to. */ - public static final String AGGREGATE_ID = "aggregate_id"; + public static final String CONTACT_ID = "contact_id"; /** - * A reference to the {@link android.provider.ContactsContract.RawContacts#_ID} of the - * raw contact that the rule applies to. + * 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"; - - @Deprecated - public static final String CONTACT_ID = RAW_CONTACT_ID; } /** diff --git a/core/java/android/provider/SocialContract.java b/core/java/android/provider/SocialContract.java index a3b1d6ecd560..d54277448179 100644 --- a/core/java/android/provider/SocialContract.java +++ b/core/java/android/provider/SocialContract.java @@ -19,7 +19,7 @@ package android.provider; 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 @@ public class SocialContract { /** * 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/view/Surface.java b/core/java/android/view/Surface.java index 9178131346f9..c4bf642f5686 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -107,8 +107,14 @@ public class Surface implements Parcelable { 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 46aea022912b..4baf61211fee 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 class ViewDebug { 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 a5739835321b..e21824e0647d 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -23,7 +23,9 @@ import android.content.res.Resources; 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 @@ import android.widget.Toast; 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 @@ public class VolumePanel extends Handler protected Context mContext; private AudioManager mAudioManager; protected AudioService mAudioService; + private boolean mRingIsSilent; private final Toast mToast; private final View mView; @@ -138,7 +141,7 @@ public class VolumePanel extends Handler 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 @@ public class VolumePanel extends Handler 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 @@ public class VolumePanel extends Handler 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 @@ public class VolumePanel extends Handler 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 @@ public class VolumePanel extends Handler mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) { sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY); } - } protected void onPlaySound(int streamType, int flags) { @@ -337,17 +354,15 @@ public class VolumePanel extends Handler /** * 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 3b67fb6fc0ad..ed77ce883e30 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -72,38 +72,41 @@ class CallbackProxy extends Handler { 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 @@ class CallbackProxy extends Handler { 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 @@ class CallbackProxy extends Handler { * @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 @@ class CallbackProxy extends Handler { 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 000000000000..d06d7e2e9f0f --- /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 dd43b8b9f06c..d52406de7920 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -198,17 +198,48 @@ public class WebChromeClient { * @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 @@ public class WebChromeClient { * @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 1a60dbaec669..c3b359eb64e2 100644 --- a/core/java/android/webkit/WebStorage.java +++ b/core/java/android/webkit/WebStorage.java @@ -55,7 +55,8 @@ public final class WebStorage { // 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 @@ public final class WebStorage { 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 @@ public final class WebStorage { } 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 @@ public final class WebStorage { } 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 @@ public final class WebStorage { 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 19df87feb7a9..358fc9ec2bdf 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -351,6 +351,9 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout */ // 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout "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 @@ public class WebView extends AbsoluteLayout // 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout // 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout // 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout } } // 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout .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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout mInvInitialZoomScale = 1.0f / oldScale; mInvFinalZoomScale = 1.0f / mActualScale; mZoomScale = mActualScale; + if (!mInZoomOverview) { + mLastScale = scale; + } invalidate(); return true; } else { @@ -4470,6 +4535,9 @@ public class WebView extends AbsoluteLayout 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 class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout } } + 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout } 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout // 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 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout } } break; - case DID_FIRST_LAYOUT_MSG_ID: + case DID_FIRST_LAYOUT_MSG_ID: { if (mNativeClass == 0) { break; } @@ -4943,15 +5083,17 @@ public class WebView extends AbsoluteLayout 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 @@ public class WebView extends AbsoluteLayout // 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 @@ public class WebView extends AbsoluteLayout // the WebTextView was visible. clearTextEntry(); break; + } case MOVE_OUT_OF_PLUGIN: if (nativePluginEatsNavKey()) { navHandledKey(msg.arg1, 1, false, 0, true); @@ -5542,4 +5695,7 @@ public class WebView extends AbsoluteLayout 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 4993fcf05741..4afc4cd63d45 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -36,6 +36,7 @@ import android.view.SurfaceHolder; import android.view.SurfaceView; import java.util.ArrayList; +import java.util.Set; import junit.framework.Assert; @@ -96,7 +97,8 @@ final class WebViewCore { 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 @@ final class WebViewCore { 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 @@ final class WebViewCore { } /** - * 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 @@ final class WebViewCore { // 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 @@ final class WebViewCore { /* * 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 @@ final class WebViewCore { 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 @@ final class WebViewCore { 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 @@ final class WebViewCore { 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 @@ final class WebViewCore { 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 @@ final class WebViewCore { */ 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 @@ final class WebViewCore { } } + // 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 @@ final class WebViewCore { public Region mInvalRegion; public Point mViewPoint; public Point mWidthHeight; + public int mMinPrefWidth; } private void webkitDraw() { @@ -1424,6 +1514,9 @@ final class WebViewCore { // 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 @@ final class WebViewCore { 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 @@ final class WebViewCore { } } - // reset restored offset - mRestoredX = mRestoredY = 0; + // reset restored offset, scale + mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0; } } @@ -1777,6 +1871,17 @@ final class WebViewCore { } // 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 e613ec432710..ea88b5bf8b69 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -104,6 +104,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } /** + * @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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 24c0e2a4a2d9..e19a93dc64ea 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -432,7 +432,7 @@ public class RelativeLayout extends ViewGroup { 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 @@ public class RelativeLayout extends ViewGroup { 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 e27b36f0f4a1..fbe0d22930cb 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 @@ public class QueryParamsImpl extends QueryParams { sb.append('?'); } for (String param : params) { + String value = mParams.get(param); + if (value == null) continue; if (first) { first = false; } else { @@ -67,7 +69,7 @@ public class QueryParamsImpl extends QueryParams { } 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 64491471b14c..65c04357adfd 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -53,10 +53,11 @@ struct fields_t { 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 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th 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 @@ static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobjec 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 @@ static JNINativeMethod gMethods[] = { #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 @@ int register_android_media_AudioTrack(JNIEnv *env) 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 17704ae80c55..6ad244187d83 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 Binary files differindex 778255ae27c8..465cabd7e929 100644 --- a/core/res/res/drawable/expander_ic_maximized.9.png +++ b/core/res/res/drawable/expander_ic_maximized.9.png diff --git a/core/res/res/drawable/expander_ic_minimized.9.png b/core/res/res/drawable/expander_ic_minimized.9.png Binary files differindex 5235c18f31af..9967ecbd6c1e 100644 --- a/core/res/res/drawable/expander_ic_minimized.9.png +++ b/core/res/res/drawable/expander_ic_minimized.9.png diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 0e848398067c..549b66835430 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 f829b0855120..2b9e448706e1 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -96,6 +96,7 @@ public class RenderScript { 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 class RenderScript { } 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 573610ca55ef..6f781a08b480 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -291,6 +291,29 @@ nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jint dstFmt, jboolean g 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 @@ static JNINativeMethod methods[] = { {"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 085945710d8f..e76fd4ceadd1 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 @@ class OMXDecoder : public MediaSource, 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 @@ private: }; 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 @@ private: IOMX::node_id mNode; char *mComponentName; bool mIsMP3; + bool mIsAVC; + uint32_t mQuirks; MediaSource *mSource; sp<MetaData> mOutputFormat; @@ -116,7 +131,8 @@ private: 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 @@ private: 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 @@ private: 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 000000000000..f7fa81b86a59 --- /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 1ae8dab4281f..b36b34a2c551 100644 --- a/keystore/jni/certtool.c +++ b/keystore/jni/certtool.c @@ -30,13 +30,17 @@ jstring 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 c10e02b7c370..f5c03bb16795 100644 --- a/libs/audioflinger/Android.mk +++ b/libs/audioflinger/Android.mk @@ -107,6 +107,7 @@ LOCAL_MODULE:= libaudioflinger 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 133613123c4e..232ffb05bda4 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -3443,8 +3443,8 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, void *output) 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 855ea63463b7..1d14f70e87ec 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -146,26 +146,26 @@ enum RsDepthFunc { }; 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 07893014ac70..7a5556eee562 100644 --- a/libs/rs/RenderScriptEnv.h +++ b/libs/rs/RenderScriptEnv.h @@ -30,11 +30,3 @@ typedef struct { #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 6885251d9250..495fe557b742 100644 --- a/libs/rs/java/Film/res/raw/filmstrip.c +++ b/libs/rs/java/Film/res/raw/filmstrip.c @@ -11,29 +11,29 @@ typedef struct FilmScriptUserEnvRec { 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 @@ int main(int index) 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; - - /* - disable(GL_LIGHTING); - + float focusPos = loadF(1, POS_FOCUS); + int focusID = 0; + int lastFocusID = loadI32(2, STATE_LAST_FOCUS); + int imgCount = 13; - if (trans > (-.3)) { - focusID = -1.0 - focusPos; + if (trans > (-.3f)) { + focusID = -1.0f - focusPos; if (focusID >= imgCount) { focusID = -1; } @@ -71,6 +65,7 @@ int main(int index) focusID = -1; } + /* if (focusID != lastFocusID) { if (lastFocusID >= 0) { uploadToTexture(con, env->tex[lastFocusID], 1); @@ -79,36 +74,38 @@ int main(int index) 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; - } - - int start = offset -2; - int end = offset + 2; - - if (start < 0) { - start = 0; - } - if (end > env->triangleOffsetsCount) { - end = env->triangleOffsetsCount; + 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]); + */ } - - 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 fca0818983d1..395bd3542b78 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.renderscript.Matrix; 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.KeyEvent; 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 @@ public class FilmRS { 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 @@ public class FilmRS { 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 @@ public class FilmRS { 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 @@ public class FilmRS { } - 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 @@ public class FilmRS { 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 @@ public class FilmRS { 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 Binary files differnew file mode 100644 index 000000000000..030ae73d572c --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/calendar.png diff --git a/libs/rs/java/Rollo/res/raw/g1155.png b/libs/rs/java/Rollo/res/raw/g1155.png Binary files differnew file mode 100644 index 000000000000..68e1843a63e0 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/g1155.png diff --git a/libs/rs/java/Rollo/res/raw/g2140.png b/libs/rs/java/Rollo/res/raw/g2140.png Binary files differnew file mode 100644 index 000000000000..8c4e85333dec --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/g2140.png diff --git a/libs/rs/java/Rollo/res/raw/path1920.png b/libs/rs/java/Rollo/res/raw/path1920.png Binary files differnew file mode 100644 index 000000000000..3510665cb683 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path1920.png diff --git a/libs/rs/java/Rollo/res/raw/path1927.png b/libs/rs/java/Rollo/res/raw/path1927.png Binary files differnew file mode 100644 index 000000000000..fccc84613104 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path1927.png diff --git a/libs/rs/java/Rollo/res/raw/path3099.png b/libs/rs/java/Rollo/res/raw/path3099.png Binary files differnew file mode 100644 index 000000000000..527ebf6f681f --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path3099.png diff --git a/libs/rs/java/Rollo/res/raw/path3950.png b/libs/rs/java/Rollo/res/raw/path3950.png Binary files differnew file mode 100644 index 000000000000..59a646ae6be2 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path3950.png diff --git a/libs/rs/java/Rollo/res/raw/path431.png b/libs/rs/java/Rollo/res/raw/path431.png Binary files differnew file mode 100644 index 000000000000..5d2ed75bb635 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path431.png diff --git a/libs/rs/java/Rollo/res/raw/path4481.png b/libs/rs/java/Rollo/res/raw/path4481.png Binary files differnew file mode 100644 index 000000000000..78be0fcb7969 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path4481.png diff --git a/libs/rs/java/Rollo/res/raw/path5168.png b/libs/rs/java/Rollo/res/raw/path5168.png Binary files differnew file mode 100644 index 000000000000..a7c3a19eb999 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path5168.png diff --git a/libs/rs/java/Rollo/res/raw/path676.png b/libs/rs/java/Rollo/res/raw/path676.png Binary files differnew file mode 100644 index 000000000000..209969077307 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path676.png diff --git a/libs/rs/java/Rollo/res/raw/path754.png b/libs/rs/java/Rollo/res/raw/path754.png Binary files differnew file mode 100644 index 000000000000..88aed5b86e44 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path754.png diff --git a/libs/rs/java/Rollo/res/raw/path815.png b/libs/rs/java/Rollo/res/raw/path815.png Binary files differnew file mode 100644 index 000000000000..407570f80adf --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/path815.png diff --git a/libs/rs/java/Rollo/res/raw/polygon2408.png b/libs/rs/java/Rollo/res/raw/polygon2408.png Binary files differnew file mode 100644 index 000000000000..4413954f7e19 --- /dev/null +++ b/libs/rs/java/Rollo/res/raw/polygon2408.png diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c index d338d0df1b0c..9e03a448d00d 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 @@ int main(void* con, int ft, int launchID) float touchCut = 1.f; if (loadI32(0, STATE_TOUCH)) { - touchCut = 5.f; + touchCut = 4.f; } @@ -60,20 +61,24 @@ int main(void* con, int ft, int launchID) 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 main(void* con, int ft, int launchID) 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; + } + + 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 0; + return 1; } diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c index b04ea73e53f6..256fa3cf40b7 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 imageID; + int done = loadI32(0, STATE_DONE); + int selectedID = loadI32(0, STATE_SELECTION); + int iconCount = loadI32(0, STATE_COUNT); + + float f = loadF(2, 0); + + float iconSize = 1.f; + float iconSpacing = 0.2f; + float z = 4.f; + + pfClearColor(0.0f, 0.0f, 0.0f, f); + if (done) { + } else { + if (f < 0.8f) { + f = f + 0.02f; + storeF(2, 0, f); + } + } + + 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; - int imageID; - int tx1; - int ty1; - int tz1; - int tx2; - int ty2; - int tz2; - int tmpSin; - int tmpCos; - int iconCount; - int pressure; + 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; - int ringCount; + 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; - rotStep = 16 * 0x10000; - pressure = loadI32(0, 2); - rowCount = 4; + float tz1 = z + tmpSin * iconSize; + float tz2 = z; - iconCount = loadI32(0, 1); - rot = (-20 + loadI32(0, 0)) * 0x10000; + float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing)); + float tx2 = tx1 + iconSize; - for (ringCount = 0; ringCount < 5; ringCount++) { - drawLoop(0, 0, 0x90000 + (ringCount * 0x80000)); + bindTexture(NAMED_PF, 0, loadI32(1, index)); + drawQuad(tx1, ty1, tz1, + tx2, ty1, tz1, + tx2, ty2, tz2, + tx1, ty2, tz2); + index++; + } } - return 0; + // 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 8f4833519a62..520e3e4f55d5 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 @@ package com.android.rollo; import java.io.Writer; +import android.renderscript.RSSurfaceView; import android.renderscript.RenderScript; import android.renderscript.ProgramVertexAlloc; @@ -25,8 +26,11 @@ import android.content.Context; 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 class RolloRS { 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 class RolloRS { } 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 @@ public class RolloRS { 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 @@ public class RolloRS { 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 @@ public class RolloRS { 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 @@ public class RolloRS { { - 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 @@ public class RolloRS { } + 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 @@ public class RolloRS { //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 @@ public class RolloRS { } - 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 b5e02af9867a..71d6c7e10ce4 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 @@ public class RolloView extends RSSurfaceView { float mOldColumn; float mZoom = 1; - int mIconCount = 38; + int mIconCount = 29; int mRows = 4; int mColumns = (mIconCount + mRows - 1) / mRows; @@ -90,8 +90,8 @@ public class RolloView extends RSSurfaceView { 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 @@ public class RolloView extends RSSurfaceView { 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 @@ public class RolloView extends RSSurfaceView { 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 @@ public class RolloView extends RSSurfaceView { 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 2f99808b8682..45e6d1be8cb0 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -99,6 +99,16 @@ AllocationCreateFromBitmap { 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 c143307bd549..c6a9149bc5c2 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -204,12 +204,12 @@ static void mip565(const Adapter2D &out, const Adapter2D &in) 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 @@ static void mip8888(const Adapter2D &out, const Adapter2D &in) 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 @@ static ElementConverter_t pickConverter(RsElementPredefined dstFmt, RsElementPre 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 @@ RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h 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 @@ RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool g 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 78b8bf89e9e8..e52b0e00b203 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -79,8 +79,7 @@ bool Context::runScript(Script *s, uint32_t launchID) 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 497dbcf7620f..a00b8e8690f0 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -83,6 +83,7 @@ public: 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 417ba6aed13e..792135d4cfc6 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -55,8 +55,6 @@ void ProgramVertex::setupGL() glLoadIdentity(); } - - LOGE("lights %i ", mLightCount); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (mLightCount) { @@ -103,6 +101,25 @@ void ProgramVertex::addLight(const Light *l) } } +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 ac15b70a7cb6..da5ed815514a 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -41,6 +41,10 @@ public: 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 129b19fc5a54..412190647ad5 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -135,7 +135,6 @@ static float SC_randf(float max) - ////////////////////////////////////////////////////////////////////////////// // Matrix routines ////////////////////////////////////////////////////////////////////////////// @@ -257,6 +256,24 @@ static void SC_bindProgramVertex(RsProgramVertex pv) } ////////////////////////////////////////////////////////////////////////////// +// 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 @@ static void SC_drawQuad(float x1, float y1, float z1, glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } -////////////////////////////////////////////////////////////////////////////// -// -////////////////////////////////////////////////////////////////////////////// - -extern "C" const void * loadVp(uint32_t bank, uint32_t offset) +static void SC_drawRect(float x1, float y1, + float x2, float y2, float z) { - GET_TLS(); - return &static_cast<const uint8_t *>(sc->mSlots[bank]->getPtr())[offset]; + SC_drawQuad(x1, y2, z, + x2, y2, z, + x2, y1, z, + x1, y1, z); } - +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// 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 @@ extern "C" void materialSpecular(float r, float g, float b, float a) 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 @@ static void SC_ClearColor(float r, float g, float b, float a) 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 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = { "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 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = { { "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 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = { // 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 9fffbbfbb9ff..ff49c87db311 100644 --- a/libs/surfaceflinger/LayerBitmap.cpp +++ b/libs/surfaceflinger/LayerBitmap.cpp @@ -177,22 +177,17 @@ status_t LayerBitmap::setSize(uint32_t w, uint32_t h) 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 7a7574f57771..102899c562b2 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -650,6 +650,7 @@ void SurfaceFlinger::handleTransactionLocked( if (currentLayers.indexOf( layer ) < 0) { // this layer is not visible anymore ditchedLayers.add(layer); + mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); } } } @@ -685,17 +686,15 @@ void SurfaceFlinger::computeVisibleRegions( 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 @@ void SurfaceFlinger::computeVisibleRegions( 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 e8687a7a51f2..2569a0f1cd46 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -334,6 +334,7 @@ private: // 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 be04777528ea..c51d989b4c50 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -196,6 +196,7 @@ BackupDataReader::Status() } 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 @@ BackupDataReader::Status() 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 @@ BackupDataReader::ReadNextHeader(bool* done, int* type) 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 9e1a72c1a8af..aaac192ad3ad 100755 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -197,6 +197,10 @@ public class GpsLocationProvider extends ILocationProvider.Stub { // 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 @@ public class GpsLocationProvider extends ILocationProvider.Stub { 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 @@ public class GpsLocationProvider extends ILocationProvider.Stub { 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 040d4bc65758..60fc0e048b0d 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -649,10 +649,11 @@ public class AudioManager { * <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 @@ public class AudioManager { * @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 @@ public class AudioManager { * <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 @@ public class AudioManager { * 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 30640c308d7b..1f9e3afd9038 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -47,7 +47,10 @@ import com.android.internal.telephony.ITelephony; 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 @@ public class AudioService extends IAudioService.Stub { 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 @@ public class AudioService extends IAudioService.Stub { 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 @@ public class AudioService extends IAudioService.Stub { 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 @@ public class AudioService extends IAudioService.Stub { 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 @@ public class AudioService extends IAudioService.Stub { } setStreamVolumeIndex(streamType, index); } - setRingerMode(mRingerMode); + + // Restore ringer mode + setRingerModeInt(getRingerMode(), false); + mMediaServerOk = true; break; @@ -1276,10 +1347,12 @@ public class AudioService extends IAudioService.Stub { 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 @@ public class AudioService extends IAudioService.Stub { 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 @@ public class AudioService extends IAudioService.Stub { 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 bb4252b3a2e9..d3d2d29ece8d 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -60,4 +60,12 @@ interface IAudioService { 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 44026e428d67..8481410cc8f3 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -605,21 +605,6 @@ public class RingtoneManager { 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 class RingtoneManager { 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 class RingtoneManager { 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 1d960c5cea0c..95d61cdf64ec 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 5944d9c2bf04..5be9224d6259 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -26,6 +26,7 @@ LOCAL_SRC_FILES:= \ 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 17c72b926e3e..d5475568ce5c 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -87,7 +87,10 @@ void AudioPlayer::start() { } 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 @@ void AudioPlayer::fillBuffer(void *data, size_t size) { 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 6b47a3808a0b..01cb2d914b24 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -73,8 +73,6 @@ static bool get_mp3_frame_size( 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 caaec06af32d..4c883c626e1c 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -73,6 +73,8 @@ private: bool mNeedsNALFraming; + uint8_t *mSrcBuffer; + MPEG4Source(const MPEG4Source &); MPEG4Source &operator=(const MPEG4Source &); }; @@ -743,7 +745,8 @@ MPEG4Source::MPEG4Source( 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 MPEG4Source::start(MetaData *params) { 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 @@ status_t MPEG4Source::stop() { mBuffer = NULL; } + delete[] mSrcBuffer; + mSrcBuffer = NULL; + delete mGroup; mGroup = NULL; @@ -832,33 +843,31 @@ status_t MPEG4Source::read( // 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; - } - - err = mGroup->acquire_buffer(&mBuffer); - if (err != OK) { - assert(mBuffer == NULL); - return err; - } + if (err != OK) { + return err; + } - assert(mBuffer->size() + 2 >= size); + err = mGroup->acquire_buffer(&mBuffer); + if (err != OK) { + assert(mBuffer == NULL); + return err; + } + 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 @@ status_t MPEG4Source::read( 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; + if (num_bytes_read < (ssize_t)size) { + mBuffer->release(); + mBuffer = NULL; - mBuffer->set_range(mBufferOffset - 2, nal_length + 4); - } else { - mBuffer->set_range(mBufferOffset + 2, nal_length); + return err; } - mBufferOffset += nal_length + 2; - mBufferSizeRemaining -= nal_length + 2; + 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; + } - if (mBufferSizeRemaining > 0) { - *out = mBuffer->clone(); - } else { - *out = mBuffer; - mBuffer = NULL; + 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 78fcdee16a8f..04c9a11d96e8 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 @@ void MediaPlayerImpl::videoEntry() { { 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 @@ void MediaPlayerImpl::displayOrDiscardFrame( 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::init() { } void MediaPlayerImpl::setAudioSource(MediaSource *source) { + LOGI("setAudioSource"); mAudioSource = source; sp<MetaData> meta = source->getFormat(); @@ -646,17 +652,28 @@ void MediaPlayerImpl::populateISurface() { 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 c059a9df624a..5e449995a4e8 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 @@ struct CodecInfo { }; 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 const char *GetCodec(const CodecInfo *info, size_t numInfos, } // 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 @@ OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) { 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 *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) { } } - 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 @@ OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) { 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 @@ status_t OMXDecoder::start(MetaData *) { // 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 @@ status_t OMXDecoder::stop() { } int attempt = 1; - while (mState != OMX_StateLoaded && attempt < 10) { + while (mState != OMX_StateLoaded && attempt < 20) { usleep(100000); ++attempt; @@ -366,7 +377,11 @@ status_t OMXDecoder::read( 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 @@ void OMXDecoder::setAACFormat() { 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 @@ void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) { 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 @@ void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) { 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 @@ void OMXDecoder::setup() { success = success && meta->findInt32(kKeyHeight, &height); assert(success); - setVideoOutputFormat(width, height); + setVideoOutputFormat(mime, width, height); } // dumpPortDefinition(0); @@ -644,10 +939,7 @@ void OMXDecoder::setup() { } 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 @@ void OMXDecoder::onStart() { 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 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) { 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 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) { 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 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { 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()); - - if (port_index == kPortIndexInput) { - postEmptyBufferDone(buffer); - } else { - postInitialFillBuffer(buffer); + PortStatus status = getPortStatus(port_index); + + 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::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) { 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 @@ void OMXDecoder::onStateChanged(OMX_STATETYPE to) { 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 @@ void OMXDecoder::initiateShutdown() { 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 @@ void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) { 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::onEmptyBufferDone(IOMX::buffer_id buffer) { 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 @@ void OMXDecoder::onFillBufferDone(const omx_message &msg) { 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 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { 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 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) { 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 @@ void OMXDecoder::onRealFillBufferDone(const omx_message &msg) { 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 @@ void OMXDecoder::signalBufferReturned(MediaBuffer *_buffer) { 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 @@ void OMXDecoder::postInitialFillBuffer(IOMX::buffer_id buffer) { 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 000000000000..ba42ef4ea2d9 --- /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 7f3f1141d9a4..445e681e549f 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -149,7 +149,7 @@ void* Loader::open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks) 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 a7c01b39e143..000000000000 --- 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 dc75a92d6cf4..2b089d92e127 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 f85d3f0ce8b7..000000000000 --- 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 50c8a142357a..a293522a2e0b 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 a64805aaa0ce..000000000000 --- 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 d30d1953f47e..de3958b37485 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 56334cc3fc40..000000000000 --- 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 686ec8b8f36d..7a1386a861c3 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 19c0896553e6..000000000000 --- 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 29e462fa4bbf..f88a6540c1f2 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 625235ac7e2c..000000000000 --- 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 b37b5357f82d..7a0e41673716 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 b60832ebbf3f..000000000000 --- 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 4ab1e915de99..ccff82e372a1 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 fdbba8827e84..000000000000 --- 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 b24144a255a8..0700a762ada8 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 af0274143756..c33bdd732733 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 145168216966..9877342a490a 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.ContentUris; 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 @@ public class SettingsProvider extends ContentProvider { // 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 @@ public class SettingsProvider extends ContentProvider { 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 3858883eb3e9..6eb3cf2f0923 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -845,16 +845,18 @@ java.util.GregorianCalendar 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.ResourceBundle 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.https.Handler 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.xml.sax.helpers.NewInstance org.xmlpull.v1.XmlPullParserFactory org.xmlpull.v1.sax2.Driver sun.misc.Unsafe - diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index a682fcb444ba..45c1e5ca4a8c 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -44,6 +44,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import com.android.internal.app.ShutdownThread; /** @@ -182,6 +183,11 @@ class BatteryService extends Binder { 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 d6cd4ef1001a..134fb6fb47e0 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -60,7 +60,6 @@ import android.net.Uri; 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { } 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { dataDir.delete(); } synchronized (mPackages) { - outInfo.removedUid = mSettings.removePackageLP(packageName); + if (outInfo != null) { + outInfo.removedUid = mSettings.removePackageLP(packageName); + } } } synchronized (mPackages) { @@ -4256,7 +4279,7 @@ class PackageManagerService extends IPackageManager.Stub { } return true; } - + private void deletePackageResourcesLI(String packageName, String sourceDir, String publicSourceDir) { File sourceFile = new File(sourceDir); @@ -4286,7 +4309,9 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { String resourcePathString; private long timeStamp; private String timeStampString = "0"; - final int versionCode; + int versionCode; PackageSignatures signatures = new PackageSignatures(); @@ -5701,10 +5726,6 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { } 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 79d78ad13a94..a3c34365875b 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -29,6 +29,10 @@ import android.content.Intent; 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.HashMap; 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } } 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage 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 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage 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 78ca8316b653..edba5b6dd653 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -8231,7 +8231,9 @@ public class WindowManagerService extends IWindowManager.Stub // 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 8a4b8f97fa47..7bd2532e6cbf 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -4742,7 +4742,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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 775b0343b751..fc491d76b962 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -278,8 +278,8 @@ public class SmsMessage { 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 class SmsMessage { 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 @@ public class SmsMessage { 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 aec7aee6aa03..dda01879367d 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 @@ public class CDMAPhone extends PhoneBase { 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 91bd9930af35..7788c75b8203 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 @@ public final class CdmaCallTracker extends CallTracker { // 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 { 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 13cea990bdf0..c71003bec5dc 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 @@ public final class BearerData { 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"); - } - 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); + 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); + } + 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 @@ public final class BearerData { } 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 @@ public final class BearerData { } } - 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"); - } - 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); + 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); + } + 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.numberOfMessages = inStream.read(8); + 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 @@ public final class BearerData { } } - 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 @@ public final class BearerData { } 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "MESSAGE_STATUS decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.errorClass = inStream.read(2); - bData.messageStatus = inStream.read(6); - bData.messageStatusSet = true; + 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)); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.deferredDeliveryTimeRelative = inStream.read(8); - bData.deferredDeliveryTimeRelativeSet = true; + 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.validityPeriodRelative = inStream.read(8); - bData.validityPeriodRelativeSet = true; + 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "LANGUAGE_INDICATOR decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.language = inStream.read(8); - bData.languageIndicatorSet = true; + 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "PRIORITY_INDICATOR decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.priority = inStream.read(2); - inStream.skip(6); - bData.priorityIndicatorSet = true; + 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); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "USER_REPONSE_CODE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.userResponseCode = inStream.read(8); - bData.userResponseCodeSet = true; + inStream.skip(paramBits); + bData.userResponseCodeSet = decodeSuccess; + return decodeSuccess; } /** @@ -1310,72 +1488,73 @@ public final class BearerData { 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 ac17ebf47923..a923d2ab6593 100644 --- a/test-runner/android/test/ProviderTestCase2.java +++ b/test-runner/android/test/ProviderTestCase2.java @@ -3,6 +3,7 @@ package android.test; 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 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro 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 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro 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 b83a44d6ac00..9fb1e612f914 100644 --- a/test-runner/android/test/mock/MockContext.java +++ b/test-runner/android/test/mock/MockContext.java @@ -110,6 +110,7 @@ public class MockContext extends Context { 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 90a29179c9e2..528545ca8841 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 @@ public class CdmaSmsTest extends AndroidTestCase { 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 a03490d8f041..2eecef8304f2 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 @@ class MyTestRecorder { 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 @@ class MyTestRecorder { e.printStackTrace(); } } - + public void failed(String layout_file) { try { mBufferedOutputFailedStream.write(layout_file.getBytes()); @@ -62,7 +65,7 @@ class MyTestRecorder { e.printStackTrace(); } } - + public void noresult(String layout_file) { try { mBufferedOutputNoresultStream.write(layout_file.getBytes()); @@ -72,7 +75,7 @@ class MyTestRecorder { e.printStackTrace(); } } - + public void timedout(String url) { try { mBufferedOutputTimedoutStream.write(url.getBytes()); @@ -82,14 +85,14 @@ class MyTestRecorder { 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 @@ class MyTestRecorder { e.printStackTrace(); } } - + public void close() { try { mBufferedOutputPassedStream.close(); @@ -120,7 +123,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh bundle.putBoolean(file, result); inst.sendStatus(0, bundle); } - + private void getTestList() { // Read test list. try { @@ -174,7 +198,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE); } } - + private void clearTestStatus() { // Delete TEST_STATUS_FILE try { @@ -208,13 +232,13 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh // 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh // 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh break; } } - + if (passing) { passedCase(testFile); } else { failedCase(testFile); } - + fe.close(); fr.close(); } catch (FileNotFoundException ex) { @@ -278,7 +302,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh noresultCase(testFile); } } - + private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) { activity.setCallback(new TestShellCallback() { public void finished() { @@ -287,7 +311,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh LayoutTestsAutoTest.this.notifyAll(); } } - + public void timedOut(String url) { } }); @@ -306,16 +330,16 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh 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 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } 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 48c1e5dba4f4..30e1d99bdac2 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -531,8 +531,14 @@ public class TestShellActivity extends Activity implements LayoutTestController } @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 @@ public class TestShellActivity extends Activity implements LayoutTestController } 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 000000000000..9a3e9c202c2f --- /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 000000000000..74e018eada1f --- /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 000000000000..e1e04a7e538c --- /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 12abce57eafc..083cda34f44a 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -1467,6 +1467,7 @@ public class WifiStateTracker extends NetworkStateTracker { 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; |