summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml149
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java12
-rw-r--r--core/java/android/animation/KeyframeSet.java49
-rw-r--r--core/java/android/animation/ObjectAnimator.java11
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java2
-rw-r--r--core/java/android/app/ActionBar.java2
-rw-r--r--core/java/android/app/Application.java18
-rw-r--r--core/java/android/app/DownloadManager.java8
-rw-r--r--core/java/android/app/Fragment.java10
-rw-r--r--core/java/android/app/FragmentBreadCrumbs.java2
-rw-r--r--core/java/android/app/FragmentManager.java18
-rw-r--r--core/java/android/bluetooth/BluetoothDeviceProfileState.java1
-rw-r--r--core/java/android/content/Intent.java65
-rw-r--r--core/java/android/preference/PreferenceActivity.java106
-rw-r--r--core/java/android/server/BluetoothService.java12
-rw-r--r--core/java/android/view/View.java17
-rw-r--r--core/java/android/view/ViewGroup.java176
-rw-r--r--core/java/android/view/ViewRoot.java5
-rw-r--r--core/java/android/view/WindowManager.java48
-rw-r--r--core/java/android/view/WindowManagerPolicy.java11
-rw-r--r--core/java/android/webkit/WebTextView.java1
-rw-r--r--core/java/android/webkit/WebView.java4
-rw-r--r--core/java/android/webkit/WebViewCore.java41
-rw-r--r--core/java/android/widget/MediaController.java45
-rw-r--r--core/java/android/widget/RemoteViews.java50
-rw-r--r--core/java/android/widget/TabWidget.java1
-rw-r--r--core/java/android/widget/TextView.java9
-rw-r--r--core/java/android/widget/VideoView.java15
-rw-r--r--core/res/res/anim/fragment_close_enter.xml2
-rw-r--r--core/res/res/anim/fragment_close_exit.xml2
-rw-r--r--core/res/res/anim/fragment_open_enter.xml2
-rw-r--r--core/res/res/anim/fragment_open_exit.xml2
-rw-r--r--core/res/res/layout/tab_content.xml5
-rw-r--r--core/res/res/values/themes.xml2
-rw-r--r--core/tests/coretests/res/raw/obb_enc_file100_orig1.obbbin0 -> 275008 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_enc_file100_orig3.obbbin0 -> 298560 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_file1.obbbin0 -> 275008 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_file2.obbbin0 -> 266816 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_file2_nosign.obbbin0 -> 266752 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_file3.obbbin0 -> 298560 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_file3_bad_packagename.obbbin0 -> 298576 bytes
-rw-r--r--core/tests/coretests/src/android/app/DownloadManagerBaseTest.java7
-rw-r--r--core/tests/coretests/src/android/app/DownloadManagerStressTest.java10
-rw-r--r--core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java644
-rw-r--r--core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java244
-rw-r--r--docs/html/guide/developing/tools/MonkeyDevice.jd1353
-rw-r--r--docs/html/guide/developing/tools/MonkeyImage.jd435
-rw-r--r--docs/html/guide/developing/tools/MonkeyRunner.jd445
-rw-r--r--docs/html/guide/developing/tools/index.jd70
-rw-r--r--docs/html/guide/developing/tools/monkeyrunner_concepts.jd308
-rw-r--r--docs/html/guide/guide_toc.cs62
-rw-r--r--docs/html/guide/topics/resources/providing-resources.jd5
-rw-r--r--docs/html/guide/topics/testing/index.jd14
-rwxr-xr-xdocs/html/guide/topics/testing/testing_android.jd44
-rw-r--r--docs/html/resources/dashboard/platform-versions.jd37
-rw-r--r--docs/html/resources/faq/framework.jd43
-rw-r--r--graphics/java/android/graphics/drawable/ColorDrawable.java23
-rw-r--r--graphics/java/android/renderscript/Allocation.java1
-rw-r--r--include/media/AudioSystem.h8
-rw-r--r--include/media/stagefright/HardwareAPI.h18
-rw-r--r--libs/rs/rsScriptC.cpp17
-rw-r--r--libs/rs/rsScriptC.h1
-rw-r--r--libs/rs/rsScriptC_Lib.cpp168
-rw-r--r--libs/rs/rsScriptC_LibCL.cpp195
-rw-r--r--libs/rs/rsScriptC_LibGL.cpp68
-rw-r--r--libs/ui/InputDispatcher.cpp16
-rw-r--r--media/java/android/media/AudioService.java35
-rw-r--r--media/java/android/media/AudioSystem.java4
-rw-r--r--media/java/android/media/MediaFile.java12
-rw-r--r--media/java/android/media/MediaScanner.java28
-rw-r--r--media/java/android/media/MtpDatabase.java20
-rw-r--r--media/libstagefright/OMXCodec.cpp18
-rw-r--r--media/libstagefright/StagefrightMediaScanner.cpp2
-rw-r--r--policy/src/com/android/internal/policy/impl/KeyguardViewBase.java29
-rw-r--r--policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java1
-rw-r--r--policy/src/com/android/internal/policy/impl/LockScreen.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java12
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java497
-rw-r--r--services/audioflinger/AudioPolicyManagerBase.cpp22
-rw-r--r--services/java/com/android/server/DockObserver.java9
-rw-r--r--services/java/com/android/server/HeadsetObserver.java183
-rw-r--r--services/java/com/android/server/InputManager.java11
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java9
-rw-r--r--services/java/com/android/server/SystemServer.java18
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java28
-rw-r--r--services/java/com/android/server/WindowManagerService.java12
-rw-r--r--services/java/com/android/server/WiredAccessoryObserver.java258
-rw-r--r--services/jni/com_android_server_InputManager.cpp8
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java31
-rw-r--r--telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java8
-rw-r--r--telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl1
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl1
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java4
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneNotifier.java1
-rw-r--r--telephony/java/com/android/internal/telephony/ServiceStateTracker.java8
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CDMAPhone.java19
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java18
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java50
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java12
-rw-r--r--telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java3
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java24
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java1247
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java559
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java1211
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java750
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java27
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java4
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java10
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java6
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java11
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java2
113 files changed, 6793 insertions, 3589 deletions
diff --git a/api/current.xml b/api/current.xml
index 35fb3ef..54aae7f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26658,6 +26658,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;extra_click_download_ids&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="PAUSED_QUEUED_FOR_WIFI"
type="int"
transient="false"
@@ -27617,6 +27628,17 @@
visibility="public"
>
</method>
+<method name="onDestroyOptionsMenu"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onDestroyView"
return="void"
abstract="false"
@@ -50109,6 +50131,17 @@
visibility="public"
>
</field>
+<field name="CATEGORY_HE_DESK_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.category.HE_DESK_DOCK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CATEGORY_HOME"
type="java.lang.String"
transient="false"
@@ -50142,6 +50175,17 @@
visibility="public"
>
</field>
+<field name="CATEGORY_LE_DESK_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.category.LE_DESK_DOCK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CATEGORY_MONKEY"
type="java.lang.String"
transient="false"
@@ -50361,6 +50405,28 @@
visibility="public"
>
</field>
+<field name="EXTRA_DOCK_STATE_HE_DESK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_LE_DESK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_DOCK_STATE_UNDOCKED"
type="int"
transient="false"
@@ -83600,6 +83666,17 @@
visibility="public"
>
</method>
+<method name="getColor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getOpacity"
return="int"
abstract="false"
@@ -83624,6 +83701,19 @@
<parameter name="alpha" type="int">
</parameter>
</method>
+<method name="setColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="color" type="int">
+</parameter>
+</method>
<method name="setColorFilter"
return="void"
abstract="false"
@@ -145048,6 +145138,23 @@
<parameter name="key" type="java.lang.CharSequence">
</parameter>
</method>
+<method name="finishPreferencePanel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="caller" type="android.app.Fragment">
+</parameter>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="resultData" type="android.content.Intent">
+</parameter>
+</method>
<method name="getPreferenceManager"
return="android.preference.PreferenceManager"
abstract="false"
@@ -145276,7 +145383,7 @@
<parameter name="push" type="boolean">
</parameter>
</method>
-<method name="startPreferenceFragment"
+<method name="startPreferencePanel"
return="void"
abstract="false"
native="false"
@@ -145286,9 +145393,17 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="fragment" type="android.app.Fragment">
+<parameter name="fragmentClass" type="java.lang.String">
</parameter>
-<parameter name="ft" type="android.app.FragmentTransaction">
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="titleRes" type="int">
+</parameter>
+<parameter name="titleText" type="java.lang.CharSequence">
+</parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
</parameter>
</method>
<method name="startWithFragment"
@@ -145305,6 +145420,10 @@
</parameter>
<parameter name="args" type="android.os.Bundle">
</parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
+</parameter>
</method>
<method name="switchToHeader"
return="void"
@@ -245494,7 +245613,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
@@ -347567,7 +347686,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="toCopyIn" type="E[]">
+<parameter name="array" type="E[]">
</parameter>
</constructor>
<method name="add"
@@ -347595,7 +347714,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="element" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="addAll"
@@ -347723,7 +347842,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="indexOf"
@@ -347736,9 +347857,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="isEmpty"
@@ -347773,7 +347892,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="lastIndexOf"
@@ -347786,9 +347907,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="listIterator"
@@ -347879,7 +347998,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="element" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="size"
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 37c8ad0..b5fddfa 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -389,11 +389,13 @@ public final class Bmgr {
if (err == 0) {
observer.waitForCompletion();
sets = observer.sets;
- for (RestoreSet s : sets) {
- if (s.token == token) {
- System.out.println("Scheduling restore: " + s.name);
- didRestore = (mRestore.restoreAll(token, observer) == 0);
- break;
+ if (sets != null) {
+ for (RestoreSet s : sets) {
+ if (s.token == token) {
+ System.out.println("Scheduling restore: " + s.name);
+ didRestore = (mRestore.restoreAll(token, observer) == 0);
+ break;
+ }
}
}
}
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 1741e60..2242462 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -28,12 +28,18 @@ class KeyframeSet {
private int mNumKeyframes;
- ArrayList<Keyframe> mKeyframes;
+ Keyframe mFirstKeyframe;
+ Keyframe mLastKeyframe;
+ TimeInterpolator mInterpolator; // only used in the 2-keyframe case
+ ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
public KeyframeSet(Keyframe... keyframes) {
+ mNumKeyframes = keyframes.length;
mKeyframes = new ArrayList<Keyframe>();
mKeyframes.addAll(Arrays.asList(keyframes));
- mNumKeyframes = mKeyframes.size();
+ mFirstKeyframe = mKeyframes.get(0);
+ mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
+ mInterpolator = mLastKeyframe.getInterpolator();
}
public static KeyframeSet ofInt(int... values) {
@@ -125,32 +131,40 @@ class KeyframeSet {
* @return The animated value.
*/
public Object getValue(float fraction, TypeEvaluator evaluator) {
- // TODO: special-case 2-keyframe common case
+
+ // Special-case optimization for the common case of only two keyframes
+ if (mNumKeyframes == 2) {
+ if (mInterpolator != null) {
+ fraction = mInterpolator.getInterpolation(fraction);
+ }
+ return evaluator.evaluate(fraction, mFirstKeyframe.getValue(),
+ mLastKeyframe.getValue());
+ }
if (fraction <= 0f) {
- final Keyframe prevKeyframe = mKeyframes.get(0);
final Keyframe nextKeyframe = mKeyframes.get(1);
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
- float intervalFraction = (fraction - prevKeyframe.getFraction()) /
- (nextKeyframe.getFraction() - prevKeyframe.getFraction());
- return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
+ final float prevFraction = mFirstKeyframe.getFraction();
+ float intervalFraction = (fraction - prevFraction) /
+ (nextKeyframe.getFraction() - prevFraction);
+ return evaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
nextKeyframe.getValue());
} else if (fraction >= 1f) {
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
- final Keyframe nextKeyframe = mKeyframes.get(mNumKeyframes - 1);
- final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
+ final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
- float intervalFraction = (fraction - prevKeyframe.getFraction()) /
- (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+ final float prevFraction = prevKeyframe.getFraction();
+ float intervalFraction = (fraction - prevFraction) /
+ (mLastKeyframe.getFraction() - prevFraction);
return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
- nextKeyframe.getValue());
+ mLastKeyframe.getValue());
}
- Keyframe prevKeyframe = mKeyframes.get(0);
+ Keyframe prevKeyframe = mFirstKeyframe;
for (int i = 1; i < mNumKeyframes; ++i) {
Keyframe nextKeyframe = mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
@@ -158,14 +172,15 @@ class KeyframeSet {
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
- float intervalFraction = (fraction - prevKeyframe.getFraction()) /
- (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+ final float prevFraction = prevKeyframe.getFraction();
+ float intervalFraction = (fraction - prevFraction) /
+ (nextKeyframe.getFraction() - prevFraction);
return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
nextKeyframe.getValue());
}
prevKeyframe = nextKeyframe;
}
- // shouldn't get here
- return mKeyframes.get(mNumKeyframes - 1).getValue();
+ // shouldn't reach here
+ return mLastKeyframe.getValue();
}
}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 7427651..5b8c91d 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -376,9 +376,14 @@ public final class ObjectAnimator extends ValueAnimator {
*/
@Override
public void setTarget(Object target) {
- mTarget = target;
- // New property/values/target should cause re-initialization prior to starting
- mInitialized = false;
+ if (mTarget != target) {
+ mTarget = target;
+ if (mTarget != null && target != null && mTarget.getClass() == target.getClass()) {
+ return;
+ }
+ // New target type should cause re-initialization prior to starting
+ mInitialized = false;
+ }
}
@Override
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ad8c971..a0b70b5 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1142,7 +1142,7 @@ public class ValueAnimator extends Animator {
switch (mPlayingState) {
case RUNNING:
case SEEKED:
- float fraction = (float)(currentTime - mStartTime) / mDuration;
+ float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
if (fraction >= 1f) {
if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
// Time to repeat
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 66038d8..b359ce6 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -299,7 +299,7 @@ public abstract class ActionBar {
*
* <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the
* {@link #DISPLAY_SHOW_HOME} option.
- * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_HIDE_HOME | DISPLAY_USE_LOGO)
+ * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)
* will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.
*
* @param options A combination of the bits defined by the DISPLAY_ constants
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 45ce860..b9ac848 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -27,6 +27,14 @@ import android.content.res.Configuration;
* AndroidManifest.xml's &lt;application&gt; tag, which will cause that class
* to be instantiated for you when the process for your application/package is
* created.
+ *
+ * <p class="note">There is normally no need to subclass Application. In
+ * most situation, static singletons can provide the same functionality in a
+ * more modular way. If your singleton needs a global context (for example
+ * to register broadcast receivers), the function to retrieve it can be
+ * given a {@link android.content.Context} which internally uses
+ * {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
+ * when first constructing the singleton.</p>
*/
public class Application extends ContextWrapper implements ComponentCallbacks {
@@ -46,12 +54,10 @@ public class Application extends ContextWrapper implements ComponentCallbacks {
}
/**
- * Called when the application is stopping. There are no more application
- * objects running and the process will exit. <em>Note: never depend on
- * this method being called; in many cases an unneeded application process
- * will simply be killed by the kernel without executing any application
- * code.</em>
- * If you override this method, be sure to call super.onTerminate().
+ * This method is for use in emulated process environments. It will
+ * never be called on a production Android device, where processes are
+ * removed by simply killing them; no user code (including this callback)
+ * is executed when doing so.
*/
public void onTerminate() {
}
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 570e494..592a63b 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -272,6 +272,14 @@ public class DownloadManager {
*/
public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
+ /**
+ * When clicks on multiple notifications are received, the following
+ * provides an array of download ids corresponding to the download notification that was
+ * clicked. It can be retrieved by the receiver of this
+ * Intent using {@link android.content.Intent#getLongArrayExtra(String)}.
+ */
+ public static final String EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extra_click_download_ids";
+
// this array must contain all public columns
private static final String[] COLUMNS = new String[] {
COLUMN_ID,
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f27a15e..eaf1aee 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1027,6 +1027,16 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
}
/**
+ * Called when this fragment's option menu items are no longer being
+ * included in the overall options menu. Receiving this call means that
+ * the menu needed to be rebuilt, but this fragment's items were not
+ * included in the newly built menu (its {@link #onCreateOptionsMenu(Menu, MenuInflater)}
+ * was not called).
+ */
+ public void onDestroyOptionsMenu() {
+ }
+
+ /**
* This hook is called whenever an item in your options menu is selected.
* The default implementation simply returns false to have the normal
* processing happen (calling the item's Runnable or sending a message to
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index 22e0747..e924c1c 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -16,6 +16,7 @@
package android.app;
+import android.animation.LayoutTransition;
import android.app.FragmentManager.BackStackEntry;
import android.content.Context;
import android.util.AttributeSet;
@@ -69,6 +70,7 @@ public class FragmentBreadCrumbs extends ViewGroup
addView(mContainer);
a.getFragmentManager().addOnBackStackChangedListener(this);
updateCrumbs();
+ setLayoutTransition(new LayoutTransition());
}
/**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 45f9325..512ca16 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -268,6 +268,7 @@ final class FragmentManagerImpl implements FragmentManager {
ArrayList<Fragment> mAdded;
ArrayList<Integer> mAvailIndices;
ArrayList<BackStackRecord> mBackStack;
+ ArrayList<Fragment> mCreatedMenus;
// Must be accessed while locked.
ArrayList<BackStackRecord> mBackStackIndices;
@@ -1325,15 +1326,32 @@ final class FragmentManagerImpl implements FragmentManager {
public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
boolean show = false;
+ ArrayList<Fragment> newMenus = null;
if (mActive != null) {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
if (f != null && !f.mHidden && f.mHasMenu) {
show = true;
f.onCreateOptionsMenu(menu, inflater);
+ if (newMenus == null) {
+ newMenus = new ArrayList<Fragment>();
+ }
+ newMenus.add(f);
}
}
}
+
+ if (mCreatedMenus != null) {
+ for (int i=0; i<mCreatedMenus.size(); i++) {
+ Fragment f = mCreatedMenus.get(i);
+ if (newMenus == null || !newMenus.contains(f)) {
+ f.onDestroyOptionsMenu();
+ }
+ }
+ }
+
+ mCreatedMenus = newMenus;
+
return show;
}
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 0c8e4d9..138e7f2 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -773,6 +773,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
case CONNECT_HFP_INCOMING:
transitionTo(mIncomingHandsfree);
+ break;
case CONNECT_A2DP_INCOMING:
transitionTo(mIncomingA2dp);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8c36aa6..e14282c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -533,6 +533,8 @@ import java.util.Set;
* <li> {@link #CATEGORY_TEST}
* <li> {@link #CATEGORY_CAR_DOCK}
* <li> {@link #CATEGORY_DESK_DOCK}
+ * <li> {@link #CATEGORY_LE_DESK_DOCK}
+ * <li> {@link #CATEGORY_HE_DESK_DOCK}
* <li> {@link #CATEGORY_CAR_MODE}
* <li> {@link #CATEGORY_APP_MARKET}
* </ul>
@@ -549,6 +551,8 @@ import java.util.Set;
* <li> {@link #EXTRA_CHANGED_COMPONENT_NAME}
* <li> {@link #EXTRA_DATA_REMOVED}
* <li> {@link #EXTRA_DOCK_STATE}
+ * <li> {@link #EXTRA_DOCK_STATE_HE_DESK}
+ * <li> {@link #EXTRA_DOCK_STATE_LE_DESK}
* <li> {@link #EXTRA_DOCK_STATE_CAR}
* <li> {@link #EXTRA_DOCK_STATE_DESK}
* <li> {@link #EXTRA_DOCK_STATE_UNDOCKED}
@@ -1822,6 +1826,36 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.HEADSET_PLUG";
/**
+ * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>name</em> - Headset type, human readable string </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_ANLG_HEADSET_PLUG =
+ "android.intent.action.DOCK_HEADSET_PLUG";
+
+ /**
+ * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>name</em> - Headset type, human readable string </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_DGTL_HEADSET_PLUG =
+ "android.intent.action.DOCK_HEADSET_PLUG";
+
+ /**
* Broadcast Action: An outgoing call is about to be placed.
*
* <p>The Intent will have the following extra value:
@@ -2060,6 +2094,21 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
+ /**
+ * An activity to run when device is inserted into a analog (low end) dock.
+ * Used with {@link #ACTION_MAIN} to launch an activity. For more
+ * information, see {@link android.app.UiModeManager}.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
+
+ /**
+ * An activity to run when device is inserted into a digital (high end) dock.
+ * Used with {@link #ACTION_MAIN} to launch an activity. For more
+ * information, see {@link android.app.UiModeManager}.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_HE_DESK_DOCK = "android.intent.category.HE_DESK_DOCK";
/**
* Used to indicate that the activity can be used in a car environment.
@@ -2208,7 +2257,9 @@ public class Intent implements Parcelable, Cloneable {
* intents to request the dock state. Possible values are
* {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
* {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
- * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}, or
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_LE_DESK}, or
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_HE_DESK}.
*/
public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
@@ -2231,6 +2282,18 @@ public class Intent implements Parcelable, Cloneable {
public static final int EXTRA_DOCK_STATE_CAR = 2;
/**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is in a analog (low end) dock.
+ */
+ public static final int EXTRA_DOCK_STATE_LE_DESK = 3;
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is in a digital (high end) dock.
+ */
+ public static final int EXTRA_DOCK_STATE_HE_DESK = 4;
+
+ /**
* Boolean that can be supplied as meta-data with a dock activity, to
* indicate that the dock should take over the home key when it is active.
*/
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 0c6a237..97c957d 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -825,7 +825,7 @@ public abstract class PreferenceActivity extends ListActivity implements
/**
* Called when the user selects an item in the header list. The default
- * implementation will call either {@link #startWithFragment(String, Bundle)}
+ * implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int)}
* or {@link #switchToHeader(Header)} as appropriate.
*
* @param header The header that was selected.
@@ -834,7 +834,7 @@ public abstract class PreferenceActivity extends ListActivity implements
public void onHeaderClick(Header header, int position) {
if (header.fragment != null) {
if (mSinglePane) {
- startWithFragment(header.fragment, header.fragmentArguments);
+ startWithFragment(header.fragment, header.fragmentArguments, null, 0);
} else {
switchToHeader(header);
}
@@ -852,13 +852,18 @@ public abstract class PreferenceActivity extends ListActivity implements
* @param fragmentName The name of the fragment to display.
* @param args Optional arguments to supply to the fragment.
*/
- public void startWithFragment(String fragmentName, Bundle args) {
+ public void startWithFragment(String fragmentName, Bundle args,
+ Fragment resultTo, int resultRequestCode) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClass(this, getClass());
intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
intent.putExtra(EXTRA_NO_HEADERS, true);
- startActivity(intent);
+ if (resultTo == null) {
+ startActivity(intent);
+ } else {
+ resultTo.startActivityForResult(intent, resultRequestCode);
+ }
}
/**
@@ -923,9 +928,15 @@ public abstract class PreferenceActivity extends ListActivity implements
* @param header The new header to display.
*/
public void switchToHeader(Header header) {
- int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
- switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
- setSelectedHeader(header);
+ if (mCurHeader == header) {
+ // This is the header we are currently displaying. Just make sure
+ // to pop the stack up to its root state.
+ getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
+ } else {
+ int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
+ switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
+ setSelectedHeader(header);
+ }
}
Header findBestMatchingHeader(Header cur, ArrayList<Header> from) {
@@ -982,7 +993,7 @@ public abstract class PreferenceActivity extends ListActivity implements
*/
public void startPreferenceFragment(Fragment fragment, boolean push) {
FragmentTransaction transaction = getFragmentManager().openTransaction();
- startPreferenceFragment(fragment, transaction);
+ transaction.replace(com.android.internal.R.id.prefs, fragment);
if (push) {
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.addToBackStack(BACK_STACK_PREFS);
@@ -993,25 +1004,74 @@ public abstract class PreferenceActivity extends ListActivity implements
}
/**
- * Start a new fragment.
- *
- * @param fragment The fragment to start
- * @param ft The FragmentTransaction in which to perform this operation.
- * Will not be added to the back stack or committed for you; you use do that.
+ * Start a new fragment containing a preference panel. If the prefences
+ * are being displayed in multi-pane mode, the given fragment class will
+ * be instantiated and placed in the appropriate pane. If running in
+ * single-pane mode, a new activity will be launched in which to show the
+ * fragment.
+ *
+ * @param fragmentClass Full name of the class implementing the fragment.
+ * @param args Any desired arguments to supply to the fragment.
+ * @param titleRes Optional resource identifier of the title of this
+ * fragment.
+ * @param titleText Optional text of the title of this fragment.
+ * @param resultTo Optional fragment that result data should be sent to.
+ * If non-null, resultTo.onActivityResult() will be called when this
+ * preference panel is done. The launched panel must use
+ * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
+ * @param resultRequestCode If resultTo is non-null, this is the caller's
+ * request code to be received with the resut.
*/
- public void startPreferenceFragment(Fragment fragment, FragmentTransaction ft) {
- ft.replace(com.android.internal.R.id.prefs, fragment);
+ public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
+ CharSequence titleText, Fragment resultTo, int resultRequestCode) {
+ if (mSinglePane) {
+ startWithFragment(fragmentClass, args, resultTo, resultRequestCode);
+ } else {
+ Fragment f = Fragment.instantiate(this, fragmentClass, args);
+ if (resultTo != null) {
+ f.setTargetFragment(resultTo, resultRequestCode);
+ }
+ FragmentTransaction transaction = getFragmentManager().openTransaction();
+ transaction.replace(com.android.internal.R.id.prefs, f);
+ if (titleRes != 0) {
+ transaction.setBreadCrumbTitle(titleRes);
+ } else if (titleText != null) {
+ transaction.setBreadCrumbTitle(titleText);
+ }
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+ transaction.addToBackStack(BACK_STACK_PREFS);
+ transaction.commit();
+ }
}
-
+
+ /**
+ * Called by a preference panel fragment to finish itself.
+ *
+ * @param caller The fragment that is asking to be finished.
+ * @param resultCode Optional result code to send back to the original
+ * launching fragment.
+ * @param resultData Optional result data to send back to the original
+ * launching fragment.
+ */
+ public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
+ if (mSinglePane) {
+ setResult(resultCode, resultData);
+ finish();
+ } else {
+ if (caller != null) {
+ if (caller.getTargetFragment() != null) {
+ caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
+ resultCode, resultData);
+ }
+ }
+ // XXX be smarter about popping the stack.
+ onBackPressed();
+ }
+ }
+
@Override
public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
- Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
- FragmentTransaction transaction = getFragmentManager().openTransaction();
- startPreferenceFragment(f, transaction);
- transaction.setBreadCrumbTitle(pref.getTitle());
- transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
- transaction.addToBackStack(BACK_STACK_PREFS);
- transaction.commit();
+ startPreferencePanel(pref.getFragment(), pref.getExtras(), 0, pref.getTitle(), null, 0);
return true;
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 7289012..ec8f031 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -385,11 +385,23 @@ public class BluetoothService extends IBluetooth.Stub {
// Allow 3 seconds for profiles to gracefully disconnect
// TODO: Introduce a callback mechanism so that each profile can notify
// BluetoothService when it is done shutting down
+ disconnectDevices();
+
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
return true;
}
+ private synchronized void disconnectDevices() {
+ // Disconnect devices handled by BluetoothService.
+ for (BluetoothDevice device: getConnectedInputDevices()) {
+ disconnectInputDevice(device);
+ }
+
+ for (BluetoothDevice device: getConnectedPanDevices()) {
+ disconnectPanDevice(device);
+ }
+ }
private synchronized void finishDisable(boolean saveSetting) {
if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 87e03cf..a9f0780 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6296,8 +6296,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (invalidateCache) {
mPrivateFlags &= ~DRAWING_CACHE_VALID;
}
- final ViewParent p = mParent;
final AttachInfo ai = mAttachInfo;
+ final ViewParent p = mParent;
+ if (p != null && ai != null && ai.mHardwareAccelerated) {
+ // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+ // with a null dirty rect, which tells the ViewRoot to redraw everything
+ p.invalidateChild(this, null);
+ return;
+ }
if (p != null && ai != null) {
final Rect r = ai.mTmpInvalRect;
r.set(0, 0, mRight - mLeft, mBottom - mTop);
@@ -6321,7 +6327,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
@ViewDebug.ExportedProperty(category = "drawing")
public boolean isOpaque() {
- return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK;
+ return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK &&
+ (mAlpha >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
}
private void computeOpaqueFlags() {
@@ -8618,7 +8625,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
@RemotableViewMethod
public void setBackgroundColor(int color) {
- setBackgroundDrawable(new ColorDrawable(color));
+ if (mBGDrawable instanceof ColorDrawable) {
+ ((ColorDrawable) mBGDrawable).setColor(color);
+ } else {
+ setBackgroundDrawable(new ColorDrawable(color));
+ }
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b881bdd..aef13ad 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2101,6 +2101,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int cr = child.mRight;
final int cb = child.mBottom;
+ final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
+
final int flags = mGroupFlags;
if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
@@ -2182,7 +2184,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
- concatMatrix |= !child.hasIdentityMatrix();
+ concatMatrix |= !childHasIdentityMatrix;
// Sets the flag as early as possible to allow draw() implementations
// to call invalidate() successfully when doing animations
@@ -2231,40 +2233,41 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
- int transX = 0;
- int transY = 0;
-
- if (hasNoCache) {
- transX = -sx;
- transY = -sy;
- }
+ if (transformToApply != null || !childHasIdentityMatrix) {
+ int transX = 0;
+ int transY = 0;
- if (transformToApply != null) {
- if (concatMatrix) {
- // Undo the scroll translation, apply the transformation matrix,
- // then redo the scroll translate to get the correct result.
- canvas.translate(-transX, -transY);
- canvas.concat(transformToApply.getMatrix());
- canvas.translate(transX, transY);
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+ if (hasNoCache) {
+ transX = -sx;
+ transY = -sy;
}
- float transformAlpha = transformToApply.getAlpha();
- if (transformAlpha < 1.0f) {
- alpha *= transformToApply.getAlpha();
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+ if (transformToApply != null) {
+ if (concatMatrix) {
+ // Undo the scroll translation, apply the transformation matrix,
+ // then redo the scroll translate to get the correct result.
+ canvas.translate(-transX, -transY);
+ canvas.concat(transformToApply.getMatrix());
+ canvas.translate(transX, transY);
+ mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+ }
+
+ float transformAlpha = transformToApply.getAlpha();
+ if (transformAlpha < 1.0f) {
+ alpha *= transformToApply.getAlpha();
+ mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+ }
}
- }
- if (!child.hasIdentityMatrix()) {
- canvas.translate(-transX, -transY);
- canvas.concat(child.getMatrix());
- canvas.translate(transX, transY);
+ if (!childHasIdentityMatrix) {
+ canvas.translate(-transX, -transY);
+ canvas.concat(child.getMatrix());
+ canvas.translate(transX, transY);
+ }
}
if (alpha < 1.0f) {
mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-
if (hasNoCache) {
final int multipliedAlpha = (int) (255 * alpha);
if (!child.onSetAlpha(multipliedAlpha)) {
@@ -3209,19 +3212,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- final int[] location = attachInfo.mInvalidateChildLocation;
- location[CHILD_LEFT_INDEX] = child.mLeft;
- location[CHILD_TOP_INDEX] = child.mTop;
- Matrix childMatrix = child.getMatrix();
- if (!childMatrix.isIdentity()) {
- RectF boundingRect = attachInfo.mTmpTransformRect;
- boundingRect.set(dirty);
- childMatrix.mapRect(boundingRect);
- dirty.set((int) boundingRect.left, (int) boundingRect.top,
- (int) (boundingRect.right + 0.5f),
- (int) (boundingRect.bottom + 0.5f));
- }
-
// If the child is drawing an animation, we want to copy this flag onto
// ourselves and the parent to make sure the invalidate request goes
// through
@@ -3229,45 +3219,95 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Check whether the child that requests the invalidate is fully opaque
final boolean isOpaque = child.isOpaque() && !drawAnimation &&
- child.getAnimation() != null;
+ child.getAnimation() == null;
// Mark the child as dirty, using the appropriate flag
// Make sure we do not set both flags at the same time
final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
- do {
- View view = null;
- if (parent instanceof View) {
- view = (View) parent;
- }
+ if (dirty == null) {
+ do {
+ View view = null;
+ if (parent instanceof View) {
+ view = (View) parent;
+ if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
+ // already marked dirty - we're done
+ break;
+ }
+ }
- if (drawAnimation) {
- if (view != null) {
- view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).mIsAnimating = true;
+ if (drawAnimation) {
+ if (view != null) {
+ view.mPrivateFlags |= DRAW_ANIMATION;
+ } else if (parent instanceof ViewRoot) {
+ ((ViewRoot) parent).mIsAnimating = true;
+ }
}
- }
- // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
- // flag coming from the child that initiated the invalidate
- if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
- view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+ if (parent instanceof ViewRoot) {
+ ((ViewRoot) parent).invalidate();
+ parent = null;
+ } else if (view != null) {
+ if ((mPrivateFlags & DRAWN) == DRAWN) {
+ view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+ view.mPrivateFlags =
+ (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+ }
+ parent = view.mParent;
+ } else {
+ parent = null;
+ }
+ }
+ } while (parent != null);
+ } else {
+ final int[] location = attachInfo.mInvalidateChildLocation;
+ location[CHILD_LEFT_INDEX] = child.mLeft;
+ location[CHILD_TOP_INDEX] = child.mTop;
+ Matrix childMatrix = child.getMatrix();
+ if (!childMatrix.isIdentity()) {
+ RectF boundingRect = attachInfo.mTmpTransformRect;
+ boundingRect.set(dirty);
+ childMatrix.mapRect(boundingRect);
+ dirty.set((int) boundingRect.left, (int) boundingRect.top,
+ (int) (boundingRect.right + 0.5f),
+ (int) (boundingRect.bottom + 0.5f));
}
- parent = parent.invalidateChildInParent(location, dirty);
- if (view != null) {
- // Account for transform on current parent
- Matrix m = view.getMatrix();
- if (!m.isIdentity()) {
- RectF boundingRect = attachInfo.mTmpTransformRect;
- boundingRect.set(dirty);
- m.mapRect(boundingRect);
- dirty.set((int) boundingRect.left, (int) boundingRect.top,
- (int) (boundingRect.right + 0.5f),
- (int) (boundingRect.bottom + 0.5f));
+ do {
+ View view = null;
+ if (parent instanceof View) {
+ view = (View) parent;
}
- }
- } while (parent != null);
+
+ if (drawAnimation) {
+ if (view != null) {
+ view.mPrivateFlags |= DRAW_ANIMATION;
+ } else if (parent instanceof ViewRoot) {
+ ((ViewRoot) parent).mIsAnimating = true;
+ }
+ }
+
+ // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
+ // flag coming from the child that initiated the invalidate
+ if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+ view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+ }
+
+ parent = parent.invalidateChildInParent(location, dirty);
+ if (view != null) {
+ // Account for transform on current parent
+ Matrix m = view.getMatrix();
+ if (!m.isIdentity()) {
+ RectF boundingRect = attachInfo.mTmpTransformRect;
+ boundingRect.set(dirty);
+ m.mapRect(boundingRect);
+ dirty.set((int) boundingRect.left, (int) boundingRect.top,
+ (int) (boundingRect.right + 0.5f),
+ (int) (boundingRect.bottom + 0.5f));
+ }
+ }
+ } while (parent != null);
+ }
}
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 06261bb..22a7773 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -543,6 +543,11 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
public void invalidateChild(View child, Rect dirty) {
checkThread();
if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+ if (dirty == null) {
+ // Fast invalidation for GL-enabled applications; GL must redraw everything
+ invalidate();
+ return;
+ }
if (mCurScrollY != 0 || mTranslator != null) {
mTempRect.set(dirty);
dirty = mTempRect;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e5f4b08..c657a1c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -794,7 +794,17 @@ public interface WindowManager extends ViewManager {
public int softInputMode;
/**
- * Placement of window within the screen as per {@link Gravity}
+ * Placement of window within the screen as per {@link Gravity}. Both
+ * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+ * android.graphics.Rect) Gravity.apply} and
+ * {@link Gravity#applyDisplay(int, android.graphics.Rect, android.graphics.Rect)
+ * Gravity.applyDisplay} are used during window layout, with this value
+ * given as the desired gravity. For example you can specify
+ * {@link Gravity#DISPLAY_CLIP_HORIZONTAL Gravity.DISPLAY_CLIP_HORIZONTAL} and
+ * {@link Gravity#DISPLAY_CLIP_VERTICAL Gravity.DISPLAY_CLIP_VERTICAL} here
+ * to control the behavior of
+ * {@link Gravity#applyDisplay(int, android.graphics.Rect, android.graphics.Rect)
+ * Gravity.applyDisplay}.
*
* @see Gravity
*/
@@ -802,13 +812,19 @@ public interface WindowManager extends ViewManager {
/**
* The horizontal margin, as a percentage of the container's width,
- * between the container and the widget.
+ * between the container and the widget. See
+ * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+ * android.graphics.Rect) Gravity.apply} for how this is used. This
+ * field is added with {@link #x} to supply the <var>xAdj</var> parameter.
*/
public float horizontalMargin;
/**
* The vertical margin, as a percentage of the container's height,
- * between the container and the widget.
+ * between the container and the widget. See
+ * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+ * android.graphics.Rect) Gravity.apply} for how this is used. This
+ * field is added with {@link #y} to supply the <var>yAdj</var> parameter.
*/
public float verticalMargin;
@@ -1168,14 +1184,22 @@ public interface WindowManager extends ViewManager {
sb.append('x');
sb.append((height== MATCH_PARENT ?"fill":(height==WRAP_CONTENT?"wrap":height)));
sb.append(")");
- if (softInputMode != 0) {
- sb.append(" sim=#");
- sb.append(Integer.toHexString(softInputMode));
+ if (horizontalMargin != 0) {
+ sb.append(" hm=");
+ sb.append(horizontalMargin);
+ }
+ if (verticalMargin != 0) {
+ sb.append(" vm=");
+ sb.append(verticalMargin);
}
if (gravity != 0) {
sb.append(" gr=#");
sb.append(Integer.toHexString(gravity));
}
+ if (softInputMode != 0) {
+ sb.append(" sim=#");
+ sb.append(Integer.toHexString(softInputMode));
+ }
sb.append(" ty=");
sb.append(type);
sb.append(" fl=#");
@@ -1190,6 +1214,18 @@ public interface WindowManager extends ViewManager {
sb.append(" or=");
sb.append(screenOrientation);
}
+ if (alpha != 1.0f) {
+ sb.append(" alpha=");
+ sb.append(alpha);
+ }
+ if (screenBrightness != BRIGHTNESS_OVERRIDE_NONE) {
+ sb.append(" sbrt=");
+ sb.append(screenBrightness);
+ }
+ if (buttonBrightness != BRIGHTNESS_OVERRIDE_NONE) {
+ sb.append(" bbrt=");
+ sb.append(buttonBrightness);
+ }
if ((flags & FLAG_COMPATIBLE_WINDOW) != 0) {
sb.append(" compatible=true");
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1fd31a3..1a341e1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -544,16 +544,18 @@ public interface WindowManagerPolicy {
* Generally, it's best to keep as little as possible in the queue thread
* because it's the most fragile.
* @param whenNanos The event time in uptime nanoseconds.
+ * @param action The key event action.
+ * @param flags The key event flags.
* @param keyCode The key code.
- * @param down True if the key is down.
+ * @param scanCode The key's scan code.
* @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on
*
* @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
* {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
*/
- public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
- boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+ int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
@@ -571,6 +573,7 @@ public interface WindowManagerPolicy {
* @param action The key event action.
* @param flags The key event flags.
* @param keyCode The key code.
+ * @param scanCode The key's scan code.
* @param metaState bit mask of meta keys that are held.
* @param repeatCount Number of times a key down has repeated.
* @param policyFlags The policy flags associated with the key.
@@ -578,7 +581,7 @@ public interface WindowManagerPolicy {
* not be further dispatched.
*/
public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
- int keyCode, int metaState, int repeatCount, int policyFlags);
+ int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
/**
* Called when layout of the windows is about to start.
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 3bcd483..14dc61d 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -370,6 +370,7 @@ import java.util.ArrayList;
int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
}
+ updateCursorControllerPositions();
}
@Override
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 72b4e36..f5affe5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3477,7 +3477,9 @@ public class WebView extends AbsoluteLayout
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
- if (inEditingMode()) mWebTextView.onDrawSubstitute();
+ if (inEditingMode()) {
+ mWebTextView.onDrawSubstitute();
+ }
mWebViewCore.signalRepaintDone();
// paint the highlight in the end
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 9a873b6..9edb267 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -472,6 +472,11 @@ final class WebViewCore {
*/
private native int nativeRecordContent(Region invalRegion, Point wh);
+ /**
+ * Update the layers' content
+ */
+ private native int nativeUpdateLayers();
+
private native boolean nativeFocusBoundsChanged();
/**
@@ -798,6 +803,7 @@ final class WebViewCore {
"FREE_MEMORY", // = 145
"VALID_NODE_BOUNDS", // = 146
"SAVE_WEBARCHIVE", // = 147
+ "WEBKIT_DRAW_LAYERS", // = 148;
};
class EventHub {
@@ -868,6 +874,9 @@ final class WebViewCore {
// Load and save web archives
static final int SAVE_WEBARCHIVE = 147;
+ // Update layers
+ static final int WEBKIT_DRAW_LAYERS = 148;
+
// Network-based messaging
static final int CLEAR_SSL_PREF_TABLE = 150;
@@ -953,6 +962,10 @@ final class WebViewCore {
webkitDraw();
break;
+ case WEBKIT_DRAW_LAYERS:
+ webkitDrawLayers();
+ break;
+
case DESTROY:
// Time to take down the world. Cancel all pending
// loads and destroy the native view and frame.
@@ -1800,6 +1813,7 @@ final class WebViewCore {
// Used to avoid posting more than one draw message.
private boolean mDrawIsScheduled;
+ private boolean mDrawLayersIsScheduled;
// Used to avoid posting more than one split picture message.
private boolean mSplitPictureIsScheduled;
@@ -1839,6 +1853,20 @@ final class WebViewCore {
boolean mFocusSizeChanged;
}
+ // Only update the layers' content, not the base surface
+ // PictureSet.
+ private void webkitDrawLayers() {
+ mDrawLayersIsScheduled = false;
+ if (mDrawIsScheduled) {
+ removeMessages(EventHub.WEBKIT_DRAW);
+ webkitDraw();
+ return;
+ }
+ DrawData draw = new DrawData();
+ draw.mBaseLayer = nativeUpdateLayers();
+ webkitDraw(draw);
+ }
+
private void webkitDraw() {
mDrawIsScheduled = false;
DrawData draw = new DrawData();
@@ -1848,6 +1876,10 @@ final class WebViewCore {
if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort");
return;
}
+ webkitDraw(draw);
+ }
+
+ private void webkitDraw(DrawData draw) {
if (mWebView != null) {
draw.mFocusSizeChanged = nativeFocusBoundsChanged();
draw.mViewSize = new Point(mCurrentViewWidth, mCurrentViewHeight);
@@ -1957,6 +1989,15 @@ final class WebViewCore {
}
}
+ // called from JNI
+ void layersDraw() {
+ synchronized (this) {
+ if (mDrawLayersIsScheduled) return;
+ mDrawLayersIsScheduled = true;
+ mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW_LAYERS));
+ }
+ }
+
// called by JNI
private void contentScrollBy(int dx, int dy, boolean animate) {
if (!mBrowserFrame.firstLayoutDone()) {
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 39b1377..be1234d 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -413,33 +413,46 @@ public class MediaController extends FrameLayout {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
- if (event.getRepeatCount() == 0 && event.isDown() && (
- keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
- keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
- keyCode == KeyEvent.KEYCODE_SPACE)) {
- doPauseResume();
- show(sDefaultTimeout);
- if (mPauseButton != null) {
- mPauseButton.requestFocus();
+ final boolean uniqueDown = event.getRepeatCount() == 0
+ && event.getAction() == KeyEvent.ACTION_DOWN;
+ if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
+ || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+ || keyCode == KeyEvent.KEYCODE_SPACE) {
+ if (uniqueDown) {
+ doPauseResume();
+ show(sDefaultTimeout);
+ if (mPauseButton != null) {
+ mPauseButton.requestFocus();
+ }
+ }
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+ if (uniqueDown && !mPlayer.isPlaying()) {
+ mPlayer.start();
+ updatePausePlay();
+ show(sDefaultTimeout);
}
return true;
- } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
- if (mPlayer.isPlaying()) {
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
+ || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+ if (uniqueDown && mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
+ show(sDefaultTimeout);
}
return true;
- } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
- keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+ } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
// don't show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
- hide();
-
+ if (uniqueDown) {
+ hide();
+ }
return true;
- } else {
- show(sDefaultTimeout);
}
+
+ show(sDefaultTimeout);
return super.dispatchKeyEvent(event);
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 35c50fd..6ba7b44 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -132,6 +132,25 @@ public class RemoteViews implements Parcelable, Filter {
// here
return;
}
+
+ protected boolean startIntentSafely(Context context, PendingIntent pendingIntent,
+ Intent fillInIntent) {
+ try {
+ // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
+ context.startIntentSender(
+ pendingIntent.getIntentSender(), fillInIntent,
+ Intent.FLAG_ACTIVITY_NEW_TASK,
+ Intent.FLAG_ACTIVITY_NEW_TASK, 0);
+ } catch (IntentSender.SendIntentException e) {
+ android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
+ return false;
+ } catch (Exception e) {
+ android.util.Log.e(LOG_TAG, "Cannot send pending intent due to " +
+ "unknown exception: ", e);
+ return false;
+ }
+ return true;
+ }
}
private class SetEmptyView extends Action {
@@ -236,15 +255,7 @@ public class RemoteViews implements Parcelable, Filter {
rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
fillInIntent.setSourceBounds(rect);
- try {
- // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
- v.getContext().startIntentSender(
- pendingIntent.getIntentSender(), fillInIntent,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- Intent.FLAG_ACTIVITY_NEW_TASK, 0);
- } catch (IntentSender.SendIntentException e) {
- android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
- }
+ startIntentSafely(v.getContext(), pendingIntent, fillInIntent);
}
};
@@ -326,16 +337,7 @@ public class RemoteViews implements Parcelable, Filter {
final Intent intent = new Intent();
intent.setSourceBounds(rect);
intent.putExtras(extras);
-
- try {
- // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
- v.getContext().startIntentSender(
- pendingIntent.getIntentSender(), intent,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- Intent.FLAG_ACTIVITY_NEW_TASK, 0);
- } catch (IntentSender.SendIntentException e) {
- android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
- }
+ startIntentSafely(v.getContext(), pendingIntent, intent);
}
};
@@ -441,15 +443,7 @@ public class RemoteViews implements Parcelable, Filter {
final Intent intent = new Intent();
intent.setSourceBounds(rect);
- try {
- // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
- v.getContext().startIntentSender(
- pendingIntent.getIntentSender(), intent,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- Intent.FLAG_ACTIVITY_NEW_TASK, 0);
- } catch (IntentSender.SendIntentException e) {
- android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
- }
+ startIntentSafely(v.getContext(), pendingIntent, intent);
}
};
target.setOnClickListener(listener);
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 36adacd..ce4e8e5 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -115,7 +115,6 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
}
private void initTabWidget() {
- setOrientation(LinearLayout.HORIZONTAL);
mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
final Context context = mContext;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9855d6e..2fcae1c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4277,6 +4277,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
canvas.restore();
+ updateCursorControllerPositions();
+ }
+
+ /**
+ * Update the positions of the CursorControllers. Needed by WebTextView,
+ * which does not draw.
+ * @hide
+ */
+ protected void updateCursorControllerPositions() {
if (mInsertionPointCursorController != null &&
mInsertionPointCursorController.isShowing()) {
mInsertionPointCursorController.updatePosition();
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 3d9cde4..2be7bca 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -529,10 +529,19 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaController.hide();
}
return true;
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+ if (mMediaPlayer.isPlaying()) {
+ start();
+ mMediaController.hide();
+ }
+ return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
- && mMediaPlayer.isPlaying()) {
- pause();
- mMediaController.show();
+ || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+ if (!mMediaPlayer.isPlaying()) {
+ pause();
+ mMediaController.show();
+ }
+ return true;
} else {
toggleMediaControlsVisiblity();
}
diff --git a/core/res/res/anim/fragment_close_enter.xml b/core/res/res/anim/fragment_close_enter.xml
index 7a9a3b9..edf1948 100644
--- a/core/res/res/anim/fragment_close_enter.xml
+++ b/core/res/res/anim/fragment_close_enter.xml
@@ -26,7 +26,7 @@
android:duration="@android:integer/config_mediumAnimTime"/>
<objectAnimator
android:interpolator="@anim/decelerate_interpolator"
- android:valueFrom="-400"
+ android:valueFrom="-100"
android:valueTo="0"
android:valueType="floatType"
android:propertyName="translationX"
diff --git a/core/res/res/anim/fragment_close_exit.xml b/core/res/res/anim/fragment_close_exit.xml
index 0743577..fbba476 100644
--- a/core/res/res/anim/fragment_close_exit.xml
+++ b/core/res/res/anim/fragment_close_exit.xml
@@ -27,7 +27,7 @@
<objectAnimator
android:interpolator="@anim/accelerate_interpolator"
android:valueFrom="0"
- android:valueTo="400"
+ android:valueTo="100"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/anim/fragment_open_enter.xml b/core/res/res/anim/fragment_open_enter.xml
index ac60494..334f4ef 100644
--- a/core/res/res/anim/fragment_open_enter.xml
+++ b/core/res/res/anim/fragment_open_enter.xml
@@ -24,7 +24,7 @@
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime"/>
<objectAnimator
- android:valueFrom="400"
+ android:valueFrom="100"
android:valueTo="0"
android:valueType="floatType"
android:propertyName="translationX"
diff --git a/core/res/res/anim/fragment_open_exit.xml b/core/res/res/anim/fragment_open_exit.xml
index 3bf1ad4..764fc39 100644
--- a/core/res/res/anim/fragment_open_exit.xml
+++ b/core/res/res/anim/fragment_open_exit.xml
@@ -25,7 +25,7 @@
android:duration="@android:integer/config_mediumAnimTime"/>
<objectAnimator
android:valueFrom="0"
- android:valueTo="-400"
+ android:valueTo="-100"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/layout/tab_content.xml b/core/res/res/layout/tab_content.xml
index 0ee87ce..79147fb 100644
--- a/core/res/res/layout/tab_content.xml
+++ b/core/res/res/layout/tab_content.xml
@@ -22,8 +22,9 @@
android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent" android:layout_height="match_parent">
- <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent"
- android:layout_height="wrap_content" android:layout_weight="0" />
+ <TabWidget android:id="@android:id/tabs"
+ android:orientation="horizontal" android:layout_width="match_parent"
+ android:layout_height="wrap_content" android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent" android:layout_height="0dip"
android:layout_weight="1"/>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 077ce26..80072f4 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -572,7 +572,7 @@
<style name="Theme.IconMenu">
<!-- Menu/item attributes -->
<item name="android:itemTextAppearance">@android:style/TextAppearance.Widget.IconMenu.Item</item>
- <item name="android:selectableItemBackground">@android:drawable/menu_selector</item>
+ <item name="android:itemBackground">@android:drawable/menu_selector</item>
<item name="android:itemIconDisabledAlpha">?android:attr/disabledAlpha</item>
<item name="android:horizontalDivider">@android:drawable/divider_horizontal_dark</item>
<item name="android:verticalDivider">@android:drawable/divider_vertical_dark</item>
diff --git a/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb b/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb
new file mode 100644
index 0000000..373b8e4
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb b/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb
new file mode 100644
index 0000000..aa531d8
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file1.obb b/core/tests/coretests/res/raw/obb_file1.obb
new file mode 100644
index 0000000..e71a680
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file1.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file2.obb b/core/tests/coretests/res/raw/obb_file2.obb
new file mode 100644
index 0000000..1c397df
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file2.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file2_nosign.obb b/core/tests/coretests/res/raw/obb_file2_nosign.obb
new file mode 100644
index 0000000..8292361
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file2_nosign.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file3.obb b/core/tests/coretests/res/raw/obb_file3.obb
new file mode 100644
index 0000000..7f97a88
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file3.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file3_bad_packagename.obb b/core/tests/coretests/res/raw/obb_file3_bad_packagename.obb
new file mode 100644
index 0000000..baa714a
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file3_bad_packagename.obb
Binary files differ
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index 340137c..8df37ad 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -83,6 +83,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000; // 1 second
protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes
+ protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes
// Just a few popular file types used to return from a download
protected enum DownloadFileType {
@@ -180,7 +181,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
* @return A Set<Long> with the ids of the completed downloads.
*/
public Set<Long> getDownloadIds() {
- synchronized(downloadIds) {
+ synchronized(this) {
Set<Long> returnIds = new HashSet<Long>(downloadIds);
return returnIds;
}
@@ -224,6 +225,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ Log.i(LOG_TAG, "WiFi Connection state is currently: " + info.isConnected());
return info.isConnected();
}
}
@@ -511,6 +513,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
* @param enable true if it should be enabled, false if it should be disabled
*/
protected void setWiFiStateOn(boolean enable) throws Exception {
+ Log.i(LOG_TAG, "Setting WiFi State to: " + enable);
WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
manager.setWifiEnabled(enable);
@@ -528,7 +531,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
while (receiver.getWiFiIsOn() != enable && !timedOut) {
try {
- receiver.wait(DEFAULT_MAX_WAIT_TIME);
+ receiver.wait(DEFAULT_WAIT_POLL_TIME);
if (SystemClock.elapsedRealtime() > timeoutTime) {
timedOut = true;
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index ddf138f..e0b28d0 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -24,7 +24,6 @@ import android.app.DownloadManager.Request;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -38,6 +37,7 @@ public class DownloadManagerStressTest extends DownloadManagerBaseTest {
public void setUp() throws Exception {
super.setUp();
mServer.play(0);
+ setWiFiStateOn(true);
removeAllCurrentDownloads();
}
@@ -71,7 +71,8 @@ public class DownloadManagerStressTest extends DownloadManagerBaseTest {
}
// wait for the download to complete or timeout
- waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
+ waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME,
+ MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME);
cursor = mDownloadManager.query(new Query());
assertEquals(NUM_FILES, cursor.getCount());
Log.i(LOG_TAG, "Verified number of downloads in download manager is what we expect.");
@@ -130,10 +131,11 @@ public class DownloadManagerStressTest extends DownloadManagerBaseTest {
}
/**
- * Tests trying to download a large file (~300M bytes) when there's not enough space in cache
+ * Tests trying to download a large file (~600M bytes) when there's not enough space in cache
*/
public void testInsufficientSpace() throws Exception {
- long fileSize = 300000000L;
+ // @TODO: Rework this to fill up cache partition with a dynamically calculated size
+ long fileSize = 600000000L;
File largeFile = createFileOnSD(null, fileSize, DataType.TEXT, null);
Cursor cursor = null;
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
new file mode 100644
index 0000000..90cb9a5
--- /dev/null
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.storage.OnObbStateChangeListener;
+import android.os.storage.StorageManager;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.StringReader;
+
+public class StorageManagerBaseTest extends InstrumentationTestCase {
+
+ protected Context mContext = null;
+ protected StorageManager mSm = null;
+ private static String LOG_TAG = "StorageManagerBaseTest";
+ protected static final long MAX_WAIT_TIME = 120*1000;
+ protected static final long WAIT_TIME_INCR = 5*1000;
+ protected static String OBB_FILE_1 = "obb_file1.obb";
+ protected static String OBB_FILE_1_CONTENTS_1 = "OneToOneThousandInts.bin";
+ protected static String OBB_FILE_2 = "obb_file2.obb";
+ protected static String OBB_FILE_3 = "obb_file3.obb";
+ protected static String OBB_FILE_1_PASSWORD = "password1";
+ protected static String OBB_FILE_1_ENCRYPTED = "obb_enc_file100_orig1.obb";
+ protected static String OBB_FILE_2_UNSIGNED = "obb_file2_nosign.obb";
+ protected static String OBB_FILE_3_PASSWORD = "password3";
+ protected static String OBB_FILE_3_ENCRYPTED = "obb_enc_file100_orig3.obb";
+ protected static String OBB_FILE_3_BAD_PACKAGENAME = "obb_file3_bad_packagename.obb";
+
+ protected static boolean FORCE = true;
+ protected static boolean DONT_FORCE = false;
+
+ private static final String SAMPLE1_TEXT = "This is sample text.\n\nTesting 1 2 3.";
+
+ private static final String SAMPLE2_TEXT =
+ "We the people of the United States, in order to form a more perfect union,\n"
+ + "establish justice, insure domestic tranquility, provide for the common\n"
+ + "defense, promote the general welfare, and secure the blessings of liberty\n"
+ + "to ourselves and our posterity, do ordain and establish this Constitution\n"
+ + "for the United States of America.\n\n";
+
+ class MountingObbThread extends Thread {
+ boolean mStop = false;
+ volatile boolean mFileOpenOnObb = false;
+ private String mObbFilePath = null;
+ private String mPathToContentsFile = null;
+ private String mOfficialObbFilePath = null;
+
+ /**
+ * Constructor
+ *
+ * @param obbFilePath path to the OBB image file
+ * @param pathToContentsFile path to a file on the mounted OBB volume to open after the OBB
+ * has been mounted
+ */
+ public MountingObbThread (String obbFilePath, String pathToContentsFile) {
+ assertTrue("obbFilePath cannot be null!", obbFilePath != null);
+ mObbFilePath = obbFilePath;
+ assertTrue("path to contents file cannot be null!", pathToContentsFile != null);
+ mPathToContentsFile = pathToContentsFile;
+ }
+
+ /**
+ * Runs the thread
+ *
+ * Mounts OBB_FILE_1, and tries to open a file on the mounted OBB (specified in the
+ * constructor). Once it's open, it waits until someone calls its doStop(), after which it
+ * closes the opened file.
+ */
+ public void run() {
+ // the official OBB file path and the mount-request file path should be the same, but
+ // let's distinguish the two as they may make for some interesting tests later
+ mOfficialObbFilePath = mountObb(mObbFilePath);
+ assertEquals("Expected and actual OBB file paths differ!", mObbFilePath,
+ mOfficialObbFilePath);
+
+ // open a file on OBB 1...
+ DataInputStream inputFile = openFileOnMountedObb(mOfficialObbFilePath,
+ mPathToContentsFile);
+ assertTrue("Failed to open file!", inputFile != null);
+
+ synchronized (this) {
+ mFileOpenOnObb = true;
+ notifyAll();
+ }
+
+ while (!mStop) {
+ try {
+ Thread.sleep(WAIT_TIME_INCR);
+ } catch (InterruptedException e) {
+ // nothing special to be done for interruptions
+ }
+ }
+ try {
+ inputFile.close();
+ } catch (IOException e) {
+ fail("Failed to close file on OBB due to error: " + e.toString());
+ }
+ }
+
+ /**
+ * Tells whether a file has yet been successfully opened on the OBB or not
+ *
+ * @return true if the specified file on the OBB was opened; false otherwise
+ */
+ public boolean isFileOpenOnObb() {
+ return mFileOpenOnObb;
+ }
+
+ /**
+ * Returns the official path of the OBB file that was mounted
+ *
+ * This is not the mount path, but the normalized path to the actual OBB file
+ *
+ * @return a {@link String} representation of the path to the OBB file that was mounted
+ */
+ public String officialObbFilePath() {
+ return mOfficialObbFilePath;
+ }
+
+ /**
+ * Requests the thread to stop running
+ *
+ * Closes the opened file and returns
+ */
+ public void doStop() {
+ mStop = true;
+ }
+ }
+
+ public class ObbListener extends OnObbStateChangeListener {
+ private String LOG_TAG = "StorageManagerBaseTest.ObbListener";
+
+ String mOfficialPath = null;
+ boolean mDone = false;
+ int mState = -1;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onObbStateChange(String path, int state) {
+ Log.i(LOG_TAG, "Storage state changing to: " + state);
+
+ synchronized (this) {
+ Log.i(LOG_TAG, "OfficialPath is now: " + path);
+ mState = state;
+ mOfficialPath = path;
+ mDone = true;
+ notifyAll();
+ }
+ }
+
+ /**
+ * Tells whether we are done or not (system told us the OBB has changed state)
+ *
+ * @return true if the system has told us this OBB's state has changed, false otherwise
+ */
+ public boolean isDone() {
+ return mDone;
+ }
+
+ /**
+ * The last state of the OBB, according to the system
+ *
+ * @return A {@link String} representation of the state of the OBB
+ */
+ public int state() {
+ return mState;
+ }
+
+ /**
+ * The normalized, official path to the OBB file (according to the system)
+ *
+ * @return A {@link String} representation of the official path to the OBB file
+ */
+ public String officialPath() {
+ return mOfficialPath;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp() throws Exception {
+ mContext = getInstrumentation().getContext();
+ mSm = (StorageManager)mContext.getSystemService(android.content.Context.STORAGE_SERVICE);
+
+ }
+
+ /**
+ * Helper to copy a raw resource file to an actual specified file
+ *
+ * @param rawResId The raw resource ID of the OBB resource file
+ * @param outFile A File representing the file we want to copy the OBB to
+ * @throws NotFoundException If the resource file could not be found
+ */
+ private void copyRawToFile(int rawResId, File outFile) throws NotFoundException {
+ Resources res = mContext.getResources();
+ InputStream is = null;
+ try {
+ is = res.openRawResource(rawResId);
+ } catch (NotFoundException e) {
+ Log.i(LOG_TAG, "Failed to load resource with id: " + rawResId);
+ throw e;
+ }
+ FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IRWXO, -1, -1);
+ assertTrue(FileUtils.copyToFile(is, outFile));
+ FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IRWXO, -1, -1);
+ }
+
+ /**
+ * Creates an OBB file (with the given name), into the app's standard files directory
+ *
+ * @param name The name of the OBB file we want to create/write to
+ * @param rawResId The raw resource ID of the OBB file in the package
+ * @return A {@link File} representing the file to write to
+ */
+ protected File createObbFile(String name, int rawResId) {
+ File outFile = null;
+ try {
+ final File filesDir = mContext.getFilesDir();
+ outFile = new File(filesDir, name);
+ copyRawToFile(rawResId, outFile);
+ } catch (NotFoundException e) {
+ if (outFile != null) {
+ outFile.delete();
+ }
+ }
+ return outFile;
+ }
+
+ /**
+ * Mounts an OBB file and opens a file located on it
+ *
+ * @param obbPath Path to OBB image
+ * @param fileName The full name and path to the file on the OBB to open once the OBB is mounted
+ * @return The {@link DataInputStream} representing the opened file, if successful in opening
+ * the file, or null of unsuccessful.
+ */
+ protected DataInputStream openFileOnMountedObb(String obbPath, String fileName) {
+
+ // get mSm obb mount path
+ assertTrue("Cannot open file when OBB is not mounted!", mSm.isObbMounted(obbPath));
+
+ String path = mSm.getMountedObbPath(obbPath);
+ assertTrue("Path should not be null!", path != null);
+
+ File inFile = new File(path, fileName);
+ DataInputStream inStream = null;
+ try {
+ inStream = new DataInputStream(new FileInputStream(inFile));
+ Log.i(LOG_TAG, "Opened file: " + fileName + " for read at path: " + path);
+ } catch (FileNotFoundException e) {
+ Log.e(LOG_TAG, e.toString());
+ return null;
+ } catch (SecurityException e) {
+ Log.e(LOG_TAG, e.toString());
+ return null;
+ }
+ return inStream;
+ }
+
+ /**
+ * Mounts an OBB file
+ *
+ * @param obbFilePath The full path to the OBB file to mount
+ * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption
+ * @param expectedState The expected state resulting from trying to mount the OBB
+ * @return A {@link String} representing the normalized path to OBB file that was mounted
+ */
+ protected String mountObb(String obbFilePath, String key, int expectedState) {
+ return doMountObb(obbFilePath, key, expectedState);
+ }
+
+ /**
+ * Mounts an OBB file with default options (no encryption, mounting succeeds)
+ *
+ * @param obbFilePath The full path to the OBB file to mount
+ * @return A {@link String} representing the normalized path to OBB file that was mounted
+ */
+ protected String mountObb(String obbFilePath) {
+ return doMountObb(obbFilePath, null, OnObbStateChangeListener.MOUNTED);
+ }
+
+ /**
+ * Synchronously waits for an OBB listener to be signaled of a state change, but does not throw
+ *
+ * @param obbListener The listener for the OBB file
+ * @return true if the listener was signaled of a state change by the system, else returns
+ * false if we time out.
+ */
+ protected boolean doWaitForObbStateChange(ObbListener obbListener) {
+ synchronized(obbListener) {
+ long waitTimeMillis = 0;
+ while (!obbListener.isDone()) {
+ try {
+ Log.i(LOG_TAG, "Waiting for listener...");
+ obbListener.wait(WAIT_TIME_INCR);
+ Log.i(LOG_TAG, "Awoke from waiting for listener...");
+ waitTimeMillis += WAIT_TIME_INCR;
+ if (waitTimeMillis > MAX_WAIT_TIME) {
+ fail("Timed out waiting for OBB state to change!");
+ }
+ } catch (InterruptedException e) {
+ Log.i(LOG_TAG, e.toString());
+ }
+ }
+ return obbListener.isDone();
+ }
+ }
+
+ /**
+ * Synchronously waits for an OBB listener to be signaled of a state change
+ *
+ * @param obbListener The listener for the OBB file
+ * @return true if the listener was signaled of a state change by the system; else a fail()
+ * is triggered if we timed out
+ */
+ protected String doMountObb_noThrow(String obbFilePath, String key, int expectedState) {
+ Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key);
+ assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+ assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+
+ ObbListener obbListener = new ObbListener();
+ boolean success = mSm.mountObb(obbFilePath, key, obbListener);
+ success &= obbFilePath.equals(doWaitForObbStateChange(obbListener));
+ success &= (expectedState == obbListener.state());
+
+ if (OnObbStateChangeListener.MOUNTED == expectedState) {
+ success &= obbFilePath.equals(obbListener.officialPath());
+ success &= mSm.isObbMounted(obbListener.officialPath());
+ } else {
+ success &= !mSm.isObbMounted(obbListener.officialPath());
+ }
+
+ if (success) {
+ return obbListener.officialPath();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Mounts an OBB file without throwing and synchronously waits for it to finish mounting
+ *
+ * @param obbFilePath The full path to the OBB file to mount
+ * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption
+ * @param expectedState The expected state resulting from trying to mount the OBB
+ * @return A {@link String} representing the actual normalized path to OBB file that was
+ * mounted, or null if the mounting failed
+ */
+ protected String doMountObb(String obbFilePath, String key, int expectedState) {
+ Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key);
+ assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+
+ ObbListener obbListener = new ObbListener();
+ assertTrue("mountObb call failed", mSm.mountObb(obbFilePath, key, obbListener));
+ assertTrue("Failed to get OBB mount status change for file: " + obbFilePath,
+ doWaitForObbStateChange(obbListener));
+ assertEquals("OBB mount state not what was expected!", expectedState, obbListener.state());
+
+ if (OnObbStateChangeListener.MOUNTED == expectedState) {
+ assertEquals(obbFilePath, obbListener.officialPath());
+ assertTrue("Obb should be mounted, but SM reports it is not!",
+ mSm.isObbMounted(obbListener.officialPath()));
+ } else if (OnObbStateChangeListener.UNMOUNTED == expectedState) {
+ assertFalse("Obb should not be mounted, but SM reports it is!",
+ mSm.isObbMounted(obbListener.officialPath()));
+ }
+
+ assertEquals("Mount state is not what was expected!", expectedState, obbListener.state());
+ return obbListener.officialPath();
+ }
+
+ /**
+ * Unmounts an OBB file without throwing, and synchronously waits for it to finish unmounting
+ *
+ * @param obbFilePath The full path to the OBB file to mount
+ * @param force true if we shuold force the unmount, false otherwise
+ * @return true if the unmount was successful, false otherwise
+ */
+ protected boolean unmountObb_noThrow(String obbFilePath, boolean force) {
+ Log.i(LOG_TAG, "doUnmountObb_noThrow() on " + obbFilePath);
+ assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+ boolean success = true;
+
+ ObbListener obbListener = new ObbListener();
+ assertTrue("unmountObb call failed", mSm.unmountObb(obbFilePath, force, obbListener));
+
+ boolean stateChanged = doWaitForObbStateChange(obbListener);
+ if (force) {
+ success &= stateChanged;
+ success &= (OnObbStateChangeListener.UNMOUNTED == obbListener.state());
+ success &= !mSm.isObbMounted(obbFilePath);
+ }
+ return success;
+ }
+
+ /**
+ * Unmounts an OBB file and synchronously waits for it to finish unmounting
+ *
+ * @param obbFilePath The full path to the OBB file to mount
+ * @param force true if we shuold force the unmount, false otherwise
+ */
+ protected void unmountObb(String obbFilePath, boolean force) {
+ Log.i(LOG_TAG, "doUnmountObb() on " + obbFilePath);
+ assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+
+ ObbListener obbListener = new ObbListener();
+ assertTrue("unmountObb call failed", mSm.unmountObb(obbFilePath, force, obbListener));
+
+ boolean stateChanged = doWaitForObbStateChange(obbListener);
+ if (force) {
+ assertTrue("Timed out waiting to unmount OBB file " + obbFilePath, stateChanged);
+ assertEquals("OBB failed to unmount", OnObbStateChangeListener.UNMOUNTED,
+ obbListener.state());
+ assertFalse("Obb should NOT be mounted, but SM reports it is!", mSm.isObbMounted(
+ obbFilePath));
+ }
+ }
+
+ /**
+ * Helper to validate the contents of an "int" file in an OBB.
+ *
+ * The format of the files are sequential int's, in the range of: [start..end)
+ *
+ * @param path The full path to the file (path to OBB)
+ * @param filename The filename containing the ints to validate
+ * @param start The first int expected to be found in the file
+ * @param end The last int + 1 expected to be found in the file
+ */
+ protected void doValidateIntContents(String path, String filename, int start, int end) {
+ File inFile = new File(path, filename);
+ DataInputStream inStream = null;
+ Log.i(LOG_TAG, "Validating file " + filename + " at " + path);
+ try {
+ inStream = new DataInputStream(new FileInputStream(inFile));
+
+ for (int i = start; i < end; ++i) {
+ if (inStream.readInt() != i) {
+ fail("Unexpected value read in OBB file");
+ }
+ }
+ if (inStream != null) {
+ inStream.close();
+ }
+ Log.i(LOG_TAG, "Successfully validated file " + filename);
+ } catch (FileNotFoundException e) {
+ fail("File " + inFile + " not found: " + e.toString());
+ } catch (IOException e) {
+ fail("IOError with file " + inFile + ":" + e.toString());
+ }
+ }
+
+ /**
+ * Helper to validate the contents of a text file in an OBB
+ *
+ * @param path The full path to the file (path to OBB)
+ * @param filename The filename containing the ints to validate
+ * @param contents A {@link String} containing the expected contents of the file
+ */
+ protected void doValidateTextContents(String path, String filename, String contents) {
+ File inFile = new File(path, filename);
+ BufferedReader fileReader = null;
+ BufferedReader textReader = null;
+ Log.i(LOG_TAG, "Validating file " + filename + " at " + path);
+ try {
+ fileReader = new BufferedReader(new FileReader(inFile));
+ textReader = new BufferedReader(new StringReader(contents));
+ String actual = null;
+ String expected = null;
+ while ((actual = fileReader.readLine()) != null) {
+ expected = textReader.readLine();
+ if (!actual.equals(expected)) {
+ fail("File " + filename + " in OBB " + path + " does not match expected value");
+ }
+ }
+ fileReader.close();
+ textReader.close();
+ Log.i(LOG_TAG, "File " + filename + " successfully verified.");
+ } catch (IOException e) {
+ fail("IOError with file " + inFile + ":" + e.toString());
+ }
+ }
+
+ /**
+ * Helper to validate the contents of a "long" file on our OBBs
+ *
+ * The format of the files are sequential 0's of type long
+ *
+ * @param path The full path to the file (path to OBB)
+ * @param filename The filename containing the ints to validate
+ * @param size The number of zero's expected in the file
+ * @param checkContents If true, the contents of the file are actually verified; if false,
+ * we simply verify that the file can be opened
+ */
+ protected void doValidateZeroLongFile(String path, String filename, long size,
+ boolean checkContents) {
+ File inFile = new File(path, filename);
+ DataInputStream inStream = null;
+ Log.i(LOG_TAG, "Validating file " + filename + " at " + path);
+ try {
+ inStream = new DataInputStream(new FileInputStream(inFile));
+
+ if (checkContents) {
+ for (long i = 0; i < size; ++i) {
+ if (inStream.readLong() != 0) {
+ fail("Unexpected value read in OBB file" + filename);
+ }
+ }
+ }
+
+ if (inStream != null) {
+ inStream.close();
+ }
+ Log.i(LOG_TAG, "File " + filename + " successfully verified for " + size + " zeros");
+ } catch (IOException e) {
+ fail("IOError with file " + inFile + ":" + e.toString());
+ }
+ }
+
+ /**
+ * Helper to synchronously wait until we can get a path for a given OBB file
+ *
+ * @param filePath The full normalized path to the OBB file
+ * @return The mounted path of the OBB, used to access contents in it
+ */
+ protected String doWaitForPath(String filePath) {
+ String path = null;
+
+ long waitTimeMillis = 0;
+ assertTrue("OBB " + filePath + " is not currently mounted!", mSm.isObbMounted(filePath));
+ while (path == null) {
+ try {
+ Thread.sleep(WAIT_TIME_INCR);
+ waitTimeMillis += WAIT_TIME_INCR;
+ if (waitTimeMillis > MAX_WAIT_TIME) {
+ fail("Timed out waiting to get path of OBB file " + filePath);
+ }
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ path = mSm.getMountedObbPath(filePath);
+ }
+ Log.i(LOG_TAG, "Got OBB path: " + path);
+ return path;
+ }
+
+ /**
+ * Verifies the pre-defined contents of our first OBB (OBB_FILE_1)
+ *
+ * The OBB contains 4 files and no subdirectories
+ *
+ * @param filePath The normalized path to the already-mounted OBB file
+ */
+ protected void verifyObb1Contents(String filePath) {
+ String path = null;
+ path = doWaitForPath(filePath);
+
+ // Validate contents of 2 files in this obb
+ doValidateIntContents(path, "OneToOneThousandInts.bin", 0, 1000);
+ doValidateIntContents(path, "SevenHundredInts.bin", 0, 700);
+ doValidateZeroLongFile(path, "FiveLongs.bin", 5, true);
+ }
+
+ /**
+ * Verifies the pre-defined contents of our second OBB (OBB_FILE_2)
+ *
+ * The OBB contains 2 files and no subdirectories
+ *
+ * @param filePath The normalized path to the already-mounted OBB file
+ */
+ protected void verifyObb2Contents(String filename) {
+ String path = null;
+ path = doWaitForPath(filename);
+
+ // Validate contents of file
+ doValidateTextContents(path, "sample.txt", SAMPLE1_TEXT);
+ doValidateTextContents(path, "sample2.txt", SAMPLE2_TEXT);
+ }
+
+ /**
+ * Verifies the pre-defined contents of our third OBB (OBB_FILE_3)
+ *
+ * The OBB contains nested files and subdirectories
+ *
+ * @param filePath The normalized path to the already-mounted OBB file
+ */
+ protected void verifyObb3Contents(String filename) {
+ String path = null;
+ path = doWaitForPath(filename);
+
+ // Validate contents of file
+ doValidateIntContents(path, "OneToOneThousandInts.bin", 0, 1000);
+ doValidateZeroLongFile(path, "TwoHundredLongs", 200, true);
+
+ // validate subdirectory 1
+ doValidateZeroLongFile(path + File.separator + "subdir1", "FiftyLongs", 50, true);
+
+ // validate subdirectory subdir2/
+ doValidateIntContents(path + File.separator + "subdir2", "OneToOneThousandInts", 0, 1000);
+
+ // validate subdirectory subdir2/subdir2a/
+ doValidateZeroLongFile(path + File.separator + "subdir2" + File.separator + "subdir2a",
+ "TwoHundredLongs", 200, true);
+
+ // validate subdirectory subdir2/subdir2a/subdir2a1/
+ doValidateIntContents(path + File.separator + "subdir2" + File.separator + "subdir2a"
+ + File.separator + "subdir2a1", "OneToOneThousandInts", 0, 1000);
+ }
+} \ No newline at end of file
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
new file mode 100644
index 0000000..71772d9
--- /dev/null
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.content.Context;
+import android.os.Environment;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import com.android.frameworks.coretests.R;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileInputStream;
+
+import junit.framework.AssertionFailedError;
+
+public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
+
+ private static String LOG_TAG = "StorageManagerBaseTest.StorageManagerIntegrationTest";
+ protected File mFile = null;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContext = getInstrumentation().getContext();
+ mFile = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ if (mFile != null) {
+ mFile.delete();
+ mFile = null;
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Tests mounting a single OBB file and verifies its contents.
+ */
+ @LargeTest
+ public void testMountSingleObb() {
+ mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String filePath = mFile.getAbsolutePath();
+ mountObb(filePath);
+ verifyObb1Contents(filePath);
+ unmountObb(filePath, DONT_FORCE);
+ }
+
+ /**
+ * Tests mounting several OBB files and verifies its contents.
+ */
+ @LargeTest
+ public void testMountMultipleObb() {
+ File file1 = null;
+ File file2 = null;
+ File file3 = null;
+ try {
+ file1 = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String filePath1 = file1.getAbsolutePath();
+ mountObb(filePath1);
+ verifyObb1Contents(filePath1);
+
+ file2 = createObbFile(OBB_FILE_2, R.raw.obb_file2);
+ String filePath2 = file2.getAbsolutePath();
+ mountObb(filePath2);
+ verifyObb2Contents(filePath2);
+
+ file3 = createObbFile(OBB_FILE_3, R.raw.obb_file3);
+ String filePath3 = file3.getAbsolutePath();
+ mountObb(filePath3);
+ verifyObb3Contents(filePath3);
+
+ unmountObb(filePath1, DONT_FORCE);
+ unmountObb(filePath2, DONT_FORCE);
+ unmountObb(filePath3, DONT_FORCE);
+ } finally {
+ if (file1 != null) {
+ file1.delete();
+ }
+ if (file2 != null) {
+ file2.delete();
+ }
+ if (file3 != null) {
+ file3.delete();
+ }
+ }
+ }
+
+ /**
+ * Tests mounting a single encrypted OBB file and verifies its contents.
+ */
+ @LargeTest
+ public void testMountSingleEncryptedObb() {
+ mFile = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
+ String filePath = mFile.getAbsolutePath();
+ mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
+ verifyObb3Contents(filePath);
+ unmountObb(filePath, DONT_FORCE);
+ }
+
+ /**
+ * Tests mounting a single encrypted OBB file using an invalid password.
+ */
+ @LargeTest
+ public void testMountSingleEncryptedObbInvalidPassword() {
+ mFile = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3);
+ String filePath = mFile.getAbsolutePath();
+ mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
+ unmountObb(filePath, DONT_FORCE);
+ }
+
+ /**
+ * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents.
+ */
+ @LargeTest
+ public void testMountTwoEncryptedObb() {
+ File file3 = null;
+ File file1 = null;
+ try {
+ file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
+ String filePath3 = file3.getAbsolutePath();
+ mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
+ verifyObb3Contents(filePath3);
+
+ file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1);
+ String filePath1 = file1.getAbsolutePath();
+ mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED);
+ verifyObb1Contents(filePath1);
+
+ unmountObb(filePath3, DONT_FORCE);
+ unmountObb(filePath1, DONT_FORCE);
+ } finally {
+ if (file3 != null) {
+ file3.delete();
+ }
+ if (file1 != null) {
+ file1.delete();
+ }
+ }
+ }
+
+ /**
+ * Tests that we can not force unmount when a file is currently open on the OBB.
+ */
+ @LargeTest
+ public void testUnmount_DontForce() {
+ mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String obbFilePath = mFile.getAbsolutePath();
+
+ MountingObbThread mountingThread = new MountingObbThread(obbFilePath,
+ OBB_FILE_1_CONTENTS_1);
+
+ try {
+ mountingThread.start();
+
+ long waitTime = 0;
+ while (!mountingThread.isFileOpenOnObb()) {
+ synchronized (mountingThread) {
+ Log.i(LOG_TAG, "Waiting for file to be opened on OBB...");
+ mountingThread.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ if (waitTime > MAX_WAIT_TIME) {
+ fail("Timed out waiting for file file to be opened on OBB!");
+ }
+ }
+ }
+
+ unmountObb(obbFilePath, DONT_FORCE);
+
+ // verify still mounted
+ assertTrue("mounted path should not be null!", obbFilePath != null);
+ assertTrue("mounted path should still be mounted!", mSm.isObbMounted(obbFilePath));
+
+ // close the opened file
+ mountingThread.doStop();
+
+ // try unmounting again (should succeed this time)
+ unmountObb(obbFilePath, DONT_FORCE);
+ assertFalse("mounted path should no longer be mounted!",
+ mSm.isObbMounted(obbFilePath));
+ } catch (InterruptedException e) {
+ fail("Timed out waiting for file on OBB to be opened...");
+ }
+ }
+
+ /**
+ * Tests mounting a single OBB that isn't signed.
+ */
+ @LargeTest
+ public void testMountUnsignedObb() {
+ mFile = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign);
+ String filePath = mFile.getAbsolutePath();
+ mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL);
+ }
+
+ /**
+ * Tests mounting a single OBB that is signed with a different package.
+ */
+ @LargeTest
+ public void testMountBadPackageNameObb() {
+ mFile = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
+ String filePath = mFile.getAbsolutePath();
+ mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME,
+ OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ }
+
+ /**
+ * Tests remounting a single OBB that has already been mounted.
+ */
+ @LargeTest
+ public void testRemountObb() {
+ mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String filePath = mFile.getAbsolutePath();
+ mountObb(filePath);
+ verifyObb1Contents(filePath);
+ mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
+ verifyObb1Contents(filePath);
+ unmountObb(filePath, DONT_FORCE);
+ }
+} \ No newline at end of file
diff --git a/docs/html/guide/developing/tools/MonkeyDevice.jd b/docs/html/guide/developing/tools/MonkeyDevice.jd
new file mode 100644
index 0000000..34bbba9
--- /dev/null
+++ b/docs/html/guide/developing/tools/MonkeyDevice.jd
@@ -0,0 +1,1353 @@
+page.title=MonkeyDevice
+@jd:body
+<style>
+ h4.jd-details-title {background-color: #DEE8F1;}
+</style>
+<p>
+ A monkeyrunner class that represents a device or emulator accessible by the workstation running
+<code><a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a></code>.
+</p>
+<p>
+ This class is used to control an Android device or emulator. The methods send UI events,
+ retrieve information, install and remove applications, and run applications.
+</p>
+<p>
+ You normally do not have to create an instance of <code>MonkeyDevice</code>. Instead, you
+ use
+<code><a href="{@docRoot}guide/developing/tools/MonkeyRunner.html#waitForConnection">
+MonkeyRunner.waitForConnection()</a></code> to create a new object from a connection to a device or
+emulator. For example, instead of
+using:</p>
+<pre>
+newdevice = MonkeyDevice()
+</pre>
+<p>
+ you would use:
+</p>
+<pre>
+newdevice = MonkeyRunner.waitForConnection()
+</pre>
+<h2>Summary</h2>
+ <table id="constants" class="jd-sumtable" style="background-color: white;">
+ <tr>
+ <th colspan="12" style="background-color: #E2E2E2">Constants</th>
+ </tr>
+ <tr class="api" style="background-color: white;">
+ <td class="jd-typecol"><em>string</em></td>
+ <td class="jd-linkcol"><a href="#ACTION_DOWN">DOWN</a></td>
+ <td class="jd-descrcol" width="100%">
+ Use this with the <code>type</code> argument of
+ <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a>
+ </code>
+ to send a DOWN event.
+ </td>
+ </tr>
+ <tr class="api" style="background-color: white;">
+ <td class="jd-typecol"><em>string</em></td>
+ <td class="jd-linkcol"><a href="#ACTION_UP">UP</a></td>
+ <td class="jd-descrcol" width="100%">
+ Use this with the <code>type</code> argument of
+ <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a>
+ </code>
+ to send an UP event.
+ </td>
+ </tr>
+ <tr class="api" style="background-color: white;">
+ <td class="jd-typecol"><em>string</em></td>
+ <td class="jd-linkcol"><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></td>
+ <td class="jd-descrcol" width="100%">
+ Use this with the <code>type</code> argument of
+ <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a>
+ </code>
+ to send a DOWN event immediately followed by an UP event.
+ </td>
+ </tr>
+ </table>
+<table id="pubmethods" class="jd-sumtable">
+ <tr>
+ <th colspan="12" style="background-color: #E2E2E2">Methods</th>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#broadcastIntent">broadcastIntent</a>
+ </span>
+ (<em>string</em> uri,
+ <em>string</em> action,
+ <em>string</em> data,
+ <em>string</em> mimetype,
+ <em>iterable</em> categories
+ <em>dictionary</em> extras,
+ <em>component</em> component,
+ <em>iterable</em> flags)
+ </nobr>
+ <div class="jd-descrdiv">
+ Broadcasts an Intent to this device, as if the Intent were coming from an
+ application.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#drag">drag</a>
+ </span>
+ (<em>tuple</em> start,
+ <em>tuple</em> end,
+ <em>float</em> duration,
+ <em>integer</em> steps)
+ </nobr>
+ <div class="jd-descrdiv">
+ Simulates a drag gesture (touch, hold, and move) on this device's screen.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>object</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#getProperty">getProperty</a>
+ </span>
+ (<em>string</em> key)
+ </nobr>
+ <div class="jd-descrdiv">
+ Given the name of a system environment variable, returns its value for this device.
+ The available variable names are listed in the <a href="#getProperty">
+ detailed description</a> of this method.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>object</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#getSystemProperty">getSystemProperty</a>
+ </span>
+ (<em>string</em> key)
+ </nobr>
+ <div class="jd-descrdiv">
+. The API equivalent of <code>adb shell getprop &lt;key&gt;. This is provided for use
+ by platform developers.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#installPackage">installPackage</a>
+ </span>
+ (<em>string</em> path)
+ </nobr>
+ <div class="jd-descrdiv">
+ Installs the Android application or test package contained in packageFile onto this
+ device. If the application or test package is already installed, it is replaced.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>dictionary</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#instrument">instrument</a>
+ </span>
+ (<em>string</em> className,
+ <em>dictionary</em> args)
+ </nobr>
+ <div class="jd-descrdiv">
+ Runs the specified component under Android instrumentation, and returns the results
+ in a dictionary whose exact format is dictated by the component being run. The
+ component must already be present on this device.
+ </div>
+ </td>
+ </tr>
+ <tr class="api">
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#press">press</a>
+ </span>
+ (<em>string</em> name,
+ <em>dictionary</em> type)
+ </nobr>
+ <div class="jd-descrdiv">
+ Sends the key event specified by type to the key specified by
+ keycode.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#reboot">reboot</a>
+ </span>
+ (<em>string</em> into)
+ </nobr>
+ <div class="jd-descrdiv">
+ Reboots this device into the bootloader specified by bootloadType.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#removePackage">removePackage</a>
+ </span>
+ (<em>string</em> package)
+ </nobr>
+ <div class="jd-descrdiv">
+ Deletes the specified package from this device, including its data and cache.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>object</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#shell">shell</a>
+ </span>
+ (<em>string</em> cmd)
+ </nobr>
+ <div class="jd-descrdiv">
+ Executes an <code>adb</code> shell command and returns the result, if any.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#startActivity">startActivity</a>
+ </span>
+ (<em>string</em> uri,
+ <em>string</em> action,
+ <em>string</em> data,
+ <em>string</em> mimetype,
+ <em>iterable</em> categories
+ <em>dictionary</em> extras,
+ <em>component</em> component,
+ <em>flags</em>)
+ </nobr>
+ <div class="jd-descrdiv">
+ Starts an Activity on this device by sending an Intent constructed from the
+ supplied arguments.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+ MonkeyImage
+ </a>
+ </code>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#takeSnapshot">takeSnapshot</a>()
+ </span>
+ </nobr>
+ <div class="jd-descrdiv">
+ Captures the entire screen buffer of this device, yielding a
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+ MonkeyImage
+ </a>
+ </code> object containing a screen capture of the current display.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#touch">touch</a>
+ </span>
+ (<em>integer</em> x,
+ <em>integer</em> y,
+ <em>integer</em> type)
+ </nobr>
+ <div class="jd-descrdiv">
+ Sends a touch event specified by type to the screen location specified
+ by x and y.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#touch">type</a>
+ </span>
+ (<em>string</em> message)
+ </nobr>
+ <div class="jd-descrdiv">
+ Sends the characters contained in message to this device, as if they
+ had been typed on the device's keyboard. This is equivalent to calling
+ <code><a href="#press">press()</a></code> for each keycode in <code>message</code>
+ using the key event type <code><a href="#ACTION_DOWN_AND_UP"></a>DOWN_AND_UP</code>.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#touch">wake</a>
+ </span>
+ ()
+ </nobr>
+ <div class="jd-descrdiv">
+ Wakes the screen of this device.
+ </div>
+ </td>
+ </tr>
+</table>
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Constants</h2>
+<A NAME="ACTION_DOWN"></a>
+<div class="jd-details api">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>string</em>
+ </span>
+ DOWN
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ <code><a href="#press">press()</a></code> or
+ <code><a href="#press">touch()</a></code> value.
+ Specifies that a DOWN event type should be sent to the device, corresponding to
+ pressing down on a key or touching the screen.
+ </p>
+ </div>
+ </div>
+</div>
+<A NAME="ACTION_UP"></A>
+<div class="jd-details api">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>string</em>
+ </span>
+ UP
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ <code><a href="#press">press()</a></code> or
+ <code><a href="#press">touch()</a></code> value.
+ Specifies that an UP event type should be sent to the device, corresponding to
+ releasing a key or lifting up from the screen.
+ </p>
+ </div>
+ </div>
+</div>
+<A NAME="ACTION_DOWN_AND_UP"></A>
+
+<div class="jd-details api">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>string</em>
+ </span>
+ DOWN_AND_UP
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ <code><a href="#press">press()</a></code>,
+ <code><a href="#press">touch()</a></code> or
+ <code><a href="#type">type()</a></code> value.
+ Specifies that a DOWN event type followed by an UP event type should be sent to the
+ device, corresponding to typing a key or clicking the screen.
+ </p>
+ </div>
+ </div>
+</div>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methods -->
+<h2>Public Methods</h2>
+<A NAME="broadcastIntent"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">broadcastIntent</span>
+ <span class="normal">
+ (
+ <em>string</em> uri,
+ <em>string</em> action,
+ <em>string</em> data,
+ <em>string</em> mimetype,
+ <em>iterable</em> categories
+ <em>dictionary</em> extras,
+ <em>component</em> component,
+ <em>iterable</em> flags)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Broadcasts an Intent to this device, as if the Intent were coming from an
+ application. See {@link android.content.Intent Intent} for more information about the
+ arguments.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>uri</th>
+ <td>
+ The URI for the Intent.
+ (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+ </td>
+ </tr>
+ <tr>
+ <th>action</th>
+ <td>
+ The action for this Intent
+ (see {@link android.content.Intent#setAction(java.lang.String) Intent.setAction()}).
+ </td>
+ </tr>
+ <tr>
+ <th>data</th>
+ <td>
+ The data URI for this Intent
+ (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+ </td>
+ </tr>
+ <tr>
+ <th>mimetype</th>
+ <td>
+ The MIME type for the Intent
+ (see {@link android.content.Intent#setType(java.lang.String) Intent.setType()}).
+ </td>
+ </tr>
+ <tr>
+ <th>categories</th>
+ <td>
+ An iterable data structure containing strings that define categories for this
+ Intent
+ (see
+ {@link android.content.Intent#addCategory(java.lang.String) Intent.addCategory()}).
+ </td>
+ </tr>
+ <tr>
+ <th>extras</th>
+ <td>
+ A dictionary of extra data for this Intent
+ (see {@link android.content.Intent#putExtra(java.lang.String,java.lang.String)
+ Intent.putExtra()}
+ for an example).
+ <p>
+ The key for each dictionary item should be a <em>string</em>. The item's value
+ can be any simple or structured data type.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <th>component</th>
+ <td>
+ The component for this Intent (see {@link android.content.ComponentName}).
+ Using this argument will direct the Intent to a specific class within a specific
+ Android package.
+ </td>
+ </tr>
+ <tr>
+ <th>flags</th>
+ <td>
+ An iterable data structure containing flags that control how the Intent is handled
+ (see {@link android.content.Intent#setFlags(int) Intent.setFlags()}).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="drag"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">drag</span>
+ <span class="normal">
+ (
+ <em>tuple</em> start,
+ <em>tuple</em> end,
+ <em>float</em> duration,
+ <em>integer</em> steps)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Simulates a drag gesture (touch, hold, and move) on this device's screen.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>start</th>
+ <td>
+ The starting point of the drag gesture, in the form of a <em>tuple</em>
+ (x,y) where x and y are <em>integers</em>.
+ </td>
+ </tr>
+ <tr>
+ <th>end</th>
+ <td>
+ The end point of the drag gesture, in the form of a <em>tuple</em> (x,y)
+ where x and y are <em>integers</em>.
+ </td>
+ </tr>
+ <tr>
+ <th>duration</th>
+ <td>The duration of the drag gesture in seconds. The default is 1.0 seconds.</td>
+ </tr>
+ <tr>
+ <th>steps</th>
+ <td>The number of steps to take when interpolating points. The default is 10.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="getProperty"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>object</em>
+ </span>
+ <span class="sympad">getProperty</span>
+ <span class="normal">
+ (<em>string</em> key)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Given the name of a system environment variable, returns its value for this device.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>key</th>
+ <td>
+ The name of the system environment variable. The available variable names are listed in
+ <a href="#table1">Table 1. Property variable names</a> at the end of this topic.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ The value of the variable. The data format varies according to the variable requested.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="getSystemProperty"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>object</em>
+ </span>
+ <span class="sympad">getSystemProperty</span>
+ <span class="normal">
+ (<em>string</em> key)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Synonym for <code><a href="#getProperty">getProperty()</a></code>.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>key</th>
+ <td>
+ The name of the system environment variable. The available variable names are listed in
+ <a href="#table1">Table 1. Property Variable Names</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ The value of the variable. The data format varies according to the variable requested.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="installPackage"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">installPackage</span>
+ <span class="normal">
+ (<em>string</em> path)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Installs the Android application or test package contained in packageFile
+ onto this device. If the application or test package is already installed, it is
+ replaced.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>path</th>
+ <td>
+ The fully-qualified path and filename of the <code>.apk</code> file to install.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="instrument"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>dictionary</em>
+ </span>
+ <span class="sympad">instrument</span>
+ <span class="normal">
+ (
+ <em>string</em> className,
+ <em>dictionary</em> args)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Runs the specified component with Android instrumentation, and returns the results
+ in a dictionary whose exact format is dictated by the component being run. The
+ component must already be present on this device.
+ </p>
+ <p>
+ Use this method to start a test case that uses one of Android's test case classes.
+ See <a href="{@docRoot}guide/topics/testing/testing_android.html">Testing
+ Fundamentals</a> to learn more about unit testing with the Android testing
+ framework.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>className</th>
+ <td>
+ The name of an Android component that is already installed on this device, in the
+ standard form packagename/classname, where packagename is the
+ Android package name of a <code>.apk</code> file on this device, and
+ classname is the class name of an Android component (Activity,
+ ContentProvider, Service, or BroadcastReceiver) in that file. Both
+ packagename and classname must be fully qualified. See
+ {@link android.content.ComponentName} for more details.
+ </td>
+ </tr>
+ <tr>
+ <th>args</th>
+ <td>
+ A dictionary containing flags and their values. These are passed to the component as it
+ is started. If the flag does not take a value, set its dictionary value to an empty
+ string.
+ </td>
+ </tr>
+ </table>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ <p>
+ A dictionary containing the component's output. The contents of the dictionary
+ are defined by the component itself.
+ </p>
+ <p>
+ If you use {@link android.test.InstrumentationTestRunner} as the class name in
+ the componentName argument, then the result dictionary contains
+ the single key "stream". The value of "stream" is a <em>string</em> containing
+ the test output, as if <code>InstrumentationTestRunner</code> was run from the
+ command line. The format of this output is described in
+ <a href="{@docRoot}guide/developing/testing/testing_otheride.html">
+ Testing in Other IDEs</a>.
+ </p>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</div>
+<A NAME="press"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">press</span>
+ <span class="normal">
+ (<em>string</em> name,
+ <em>integer</em> type)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Sends the key event specified by <code>type</code> to the key specified by
+ <code>keycode</code>.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>name</th>
+ <td>
+ The name of the keycode to send. See {@link android.view.KeyEvent} for a list of
+ keycode names. Use the keycode name, not its integer value.
+ </td>
+ </tr>
+ <tr>
+ <th>type</th>
+ <td>
+ The type of key event to send. The allowed values are <code><a href="#ACTION_DOWN">
+ DOWN</a></code>, <code><a href="#ACTION_UP">UP</a></code>, and
+ <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="reboot"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">reboot</span>
+ <span class="normal">
+ (<em>string</em> bootloadType)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Reboots this device into the bootloader specified by <code>bootloadType</code>.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>into</th>
+ <td>
+ The type of bootloader to reboot into. The allowed values are
+ "bootloader", "recovery", or "None".
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="removePackage"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">removePackage</span>
+ <span class="normal">
+ (<em>string</em> package)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Deletes the specified package from this device, including its data and cache.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>package</th>
+ <td>
+ The Android package name of an <code>.apk</code> file on this device.
+ </td>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="shell"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>object</em>
+ </span>
+ <span class="sympad">shell</span>
+ <span class="normal">
+ (<em>string</em> cmd)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Executes an <code>adb</code> shell command and returns the result, if any.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>cmd</th>
+ <td>
+ The command to execute in the <code>adb</code> shell. The form of these commands is
+ described in the topic <a href="{@docRoot}guide/developing/tools/adb.html">Android
+ Debug Bridge</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ The results of the command, if any. The format of the results is determined by the
+ command.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="startActivity"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">startActivity</span>
+ <span class="normal">
+ (
+ <em>string</em> uri,
+ <em>string</em> action,
+ <em>string</em> data,
+ <em>string</em> mimetype,
+ <em>iterable</em> categories
+ <em>dictionary</em> extras,
+ <em>component</em> component,
+ <em>iterable</em> flags)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Starts an Activity on this device by sending an Intent constructed from the
+ supplied arguments.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>uri</th>
+ <td>
+ The URI for the Intent.
+ (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+ </td>
+ </tr>
+ <tr>
+ <th>action</th>
+ <td>
+ The action for the Intent
+ (see {@link android.content.Intent#setAction(java.lang.String) Intent.setAction()}).
+ </td>
+ </tr>
+ <tr>
+ <th>data</th>
+ <td>
+ The data URI for the Intent
+ (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+ </td>
+ </tr>
+ <tr>
+ <th>mimetype</th>
+ <td>
+ The MIME type for the Intent
+ (see {@link android.content.Intent#setType(java.lang.String) Intent.setType()}).
+ </td>
+ </tr>
+ <tr>
+ <th>categories</th>
+ <td>
+ An iterable data structure containing strings that define categories for the
+ Intent
+ (see
+ {@link android.content.Intent#addCategory(java.lang.String) Intent.addCategory()}).
+ </td>
+ </tr>
+ <tr>
+ <th>extras</th>
+ <td>
+ A dictionary of extra data for the Intent
+ (see
+ {@link android.content.Intent#putExtra(java.lang.String,java.lang.String)
+ Intent.putExtra()}
+ for an example).
+ <p>
+ The key for each dictionary item should be a <em>string</em>. The item's value
+ can be any simple or structured data type.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <th>component</th>
+ <td>
+ The component for the Intent
+ (see {@link android.content.ComponentName}). Using this argument will direct the
+ Intent to a specific class within a specific Android package.
+ </td>
+ </tr>
+ <tr>
+ <th>flags</th>
+ <td>
+ An iterable data structure containing flags that control how the Intent is handled
+ (see {@link android.content.Intent#setFlags(int) Intent.setFlags()}).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="takeSnapshot"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+ MonkeyImage
+ </a>
+ </code>
+ </span>
+ <span class="sympad">takeSnapshot</span>
+ <span class="normal">
+ ()
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Captures the entire screen buffer of this device, yielding a
+ screen capture of the current display.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ A <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+ MonkeyImage</a> object containing the image of the current display.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="touch"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">touch</span>
+ <span class="normal">
+ (
+ <em>integer</em> x,
+ <em>integer</em> y,
+ <em>string</em> type)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Sends a touch event specified by type to the screen location specified
+ by x and y.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>x</th>
+ <td>
+ The horizontal position of the touch in actual device pixels, starting from the left of
+ the screen in its current orientation.
+ </td>
+ </tr>
+ <tr>
+ <th>y</th>
+ <td>
+ The vertical position of the touch in actual device pixels, starting from the top of
+ the screen in its current orientation.
+ </td>
+ </tr>
+ <tr>
+ <th>type</th>
+ <td>
+ The type of key event to send. The allowed values are <code><a href="#ACTION_DOWN">
+ DOWN</a></code>, <code><a href="#ACTION_UP">UP</a></code>, and
+ <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="type"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">type</span>
+ <span class="normal">
+ (<em>string</em> message)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Sends the characters contained in message to this device, as if they
+ had been typed on the device's keyboard. This is equivalent to calling
+ <code><a href="#press">press()</a></code> for each keycode in <code>message</code>
+ using the key event type <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>message</th>
+ <td>
+ A string containing the characters to send.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="wake"></A>
+<div class="jd-details api">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">wake</span>
+ <span class="normal">
+ ()
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Wakes the screen of this device.
+ </p>
+ </div>
+ </div>
+</div>
+<hr></hr>
+<h2>Appendix</h2>
+ <p class="table-caption" id="table1">
+ <strong>Table 1.</strong>Property variable names used with
+ <span class="sympad"><a href="#getProperty">getProperty()</a></span> and
+ <span class="sympad"><a href="#getSystemProperty">getSystemProperty()</a></span>.
+ </p>
+ <table>
+ <tr>
+ <th>
+ Property Group
+ </th>
+ <th>
+ Property
+ </th>
+ <th>
+ Description
+ </th>
+ <th>
+ Notes
+ </th>
+ </tr>
+ <tr>
+ <td rowspan="17"><code>build</code></td>
+ <td><code>board</code></td>
+ <td>Code name for the device's system board</td>
+ <td rowspan="17">
+ See {@link android.os.Build}
+ </td>
+ </tr>
+ <tr>
+ <td><code>brand</code></td>
+ <td>The carrier or provider for which the OS is customized.</td>
+ </tr>
+ <tr>
+ <td><code>device</code></td>
+ <td>The device design name.</td>
+ </tr>
+ <tr>
+ <td><code>fingerprint</code></td>
+ <td>A unique identifier for the currently-running build.</td>
+ </tr>
+ <tr>
+ <td><code>host</code></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><code>ID</code></td>
+ <td>A changelist number or label.</td>
+ </tr>
+ <tr>
+ <td><code>model</code></td>
+ <td>The end-user-visible name for the device.</td>
+ </tr>
+ <tr>
+ <td><code>product</code></td>
+ <td>The overall product name.</td>
+ </tr>
+ <tr>
+ <td><code>tags</code></td>
+ <td>Comma-separated tags that describe the build, such as "unsigned" and "debug".</td>
+ </tr>
+ <tr>
+ <td><code>type</code></td>
+ <td>The build type, such as "user" or "eng".</td>
+ </tr>
+ <tr>
+ <td><code>user</code></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><code>CPU_ABI</code></td>
+ <td>
+ The name of the native code instruction set, in the form CPU type plus
+ ABI convention.
+ </td>
+ </tr>
+ <tr>
+ <td><code>manufacturer</code></td>
+ <td>The product/hardware manufacturer.</td>
+ </tr>
+ <tr>
+ <td><code>version.incremental</code></td>
+ <td>
+ The internal code used by the source control system to represent this version
+ of the software.
+ </td>
+ </tr>
+ <tr>
+ <td><code>version.release</code></td>
+ <td>The user-visible name of this version of the software.</td>
+ </tr>
+ <tr>
+ <td><code>version.sdk</code></td>
+ <td>The user-visible SDK version associated with this version of the OS.</td>
+ </tr>
+ <tr>
+ <td><code>version.codename</code></td>
+ <td>
+ The current development codename, or "REL" if this version of the software has been
+ released.
+ </td>
+ </tr>
+ <tr>
+ <td rowspan="3"><code>display</code></td>
+ <td><code>width</code></td>
+ <td>The device's display width in pixels.</td>
+ <td rowspan="3">
+ See
+ {@link android.util.DisplayMetrics} for details.
+ </td>
+ </tr>
+ <tr>
+ <td><code>height</code></td>
+ <td>The device's display height in pixels.</td>
+ </tr>
+ <tr>
+ <td><code>density</code></td>
+ <td>
+ The logical density of the display. This is a factor that scales
+ DIP (Density-Independent Pixel) units to the device's resolution. DIP is adjusted so
+ that 1 DIP is equivalent to one pixel on a 160 pixel-per-inch display. For example,
+ on a 160-dpi screen, density = 1.0, while on a 120-dpi screen, density = .75.
+ <p>
+ The value does not exactly follow the real screen size, but is adjusted to
+ conform to large changes in the display DPI. See
+ {@link android.util.DisplayMetrics#density} for more details.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td rowspan="6"><code>am.current</code></td>
+ <td><code>package</code></td>
+ <td>The Android package name of the currently running package.</td>
+ <td rowspan="6">
+ The <code>am.current</code> keys return information about the currently-running
+ Activity.
+ </td>
+ </tr>
+ <tr>
+ <td><code>action</code></td>
+ <td>
+ The current activity's action. This has the same format as the <code>name</code>
+ attribute of the <code>action</code> element in a package manifest.
+ </td>
+ </tr>
+ <tr>
+ <td><code>comp.class</code></td>
+ <td>
+ The class name of the component that started the current Activity. See
+ <code><a href="#comppackage">comp.package</a></code> for more details.</td>
+ </tr>
+ <tr>
+ <td><a name="comppackage"><code>comp.package</code></a></td>
+ <td>
+ The package name of the component that started the current Activity. A component
+ is specified by a package name and the name of class that the package contains.
+ </td>
+ </tr>
+ <tr>
+ <td><code>data</code></td>
+ <td>The data (if any) contained in the Intent that started the current Activity.</td>
+ </tr>
+ <tr>
+ <td><code>categories</code></td>
+ <td>The categories specified by the Intent that started the current Activity.</td>
+ </tr>
+ <tr>
+ <td rowspan="3"><code>clock</code></td>
+ <td><code>realtime</code></td>
+ <td>
+ The number of milliseconds since the device rebooted, including deep-sleep
+ time.
+ </td>
+ <td rowspan="3">
+ See {@link android.os.SystemClock} for more information.
+ </td>
+ </tr>
+ <tr>
+ <td><code>uptime</code></td>
+ <td>
+ The number of milliseconds since the device rebooted, <em>not</em> including
+ deep-sleep time
+ </td>
+ </tr>
+ <tr>
+ <td><code>millis</code></td>
+ <td>current time since the UNIX epoch, in milliseconds.</td>
+ </tr>
+ </table>
diff --git a/docs/html/guide/developing/tools/MonkeyImage.jd b/docs/html/guide/developing/tools/MonkeyImage.jd
new file mode 100644
index 0000000..ae85cb5
--- /dev/null
+++ b/docs/html/guide/developing/tools/MonkeyImage.jd
@@ -0,0 +1,435 @@
+page.title=MonkeyImage
+@jd:body
+<style>
+ h4.jd-details-title {background-color: #DEE8F1;}
+</style>
+
+<p>
+ A monkeyrunner class to hold an image of the device or emulator's screen. The image is
+ copied from the screen buffer during a screenshot. This object's methods allow you to
+ convert the image into various storage formats, write the image to a file, copy parts of
+ the image, and compare this object to other <code>MonkeyImage</code> objects.
+</p>
+<p>
+ You do not need to create new instances of <code>MonkeyImage</code>. Instead, use
+<code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html#takeSnapshot">
+MonkeyDevice.takeSnapshot()</a></code> to create a new instance from a screenshot. For example, use:
+</p>
+<pre>
+newimage = MonkeyDevice.takeSnapshot()
+</pre>
+<h2>Summary</h2>
+<table id="pubmethods" class="jd-sumtable">
+ <tr>
+ <th colspan="12" style="background-color: #E2E2E2">Methods</th>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>string</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#convertToBytes">convertToBytes</a>
+ </span>
+ (<em>string</em> format)
+ </nobr>
+ <div class="jd-descrdiv">
+ Converts the current image to a particular format and returns it as a
+ <em>string</em> that you can then access as an <em>iterable</em> of binary bytes.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>tuple</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#getRawPixel">getRawPixel</a>
+ </span>
+ (<em>integer</em> x,
+ <em>integer</em> y)
+ </nobr>
+ <div class="jd-descrdiv">
+ Returns the single pixel at the image location (x,y), as an
+ a <em>tuple</em> of <em>integer</em>, in the form (a,r,g,b).
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>integer</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#getRawPixelInt">getRawPixelInt</a>
+ </span>
+ (<em>integer</em> x,
+ <em>integer</em> y)
+ </nobr>
+ <div class="jd-descrdiv">
+ Returns the single pixel at the image location (x,y), as
+ a 32-bit <em>integer</em>.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a>
+ </code>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#getSubImage">getSubImage</a>
+ </span>
+ (<em>tuple</em> rect)
+ </nobr>
+ <div class="jd-descrdiv">
+ Creates a new <code>MonkeyImage</code> object from a rectangular selection of the
+ current image.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>boolean</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#sameAs">sameAs</a>
+ </span>
+ (<code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code>
+ other,
+ <em>float</em> percent)
+ </nobr>
+ <div class="jd-descrdiv">
+ Compares this <code>MonkeyImage</code> object to another and returns the result of
+ the comparison. The <code>percent</code> argument specifies the percentage
+ difference that is allowed for the two images to be "equal".
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>void</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#writeToFile">writeToFile</a>
+ </span>
+ (<em>string</em> path,
+ <em>string</em> format)
+ </nobr>
+ <div class="jd-descrdiv">
+ Writes the current image to the file specified by <code>filename</code>, in the
+ format specified by <code>format</code>.
+ </div>
+ </td>
+ </tr>
+</table>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methods -->
+<h2>Public Methods</h2>
+<A NAME="convertToBytes"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>string</em>
+ </span>
+ <span class="sympad">convertToBytes</span>
+ <span class="normal">
+ (
+ <em>string</em> format)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Converts the current image to a particular format and returns it as a <em>string</em>
+ that you can then access as an <em>iterable</em> of binary bytes.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>format</th>
+ <td>
+ The desired output format. All of the common raster output formats are supported.
+ The default value is "png" (Portable Network Graphics).
+ </td>
+ </tr>
+ </table>
+ </div>
+</div>
+</div>
+<A NAME="getRawPixel"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>tuple</em>
+ </span>
+ <span class="sympad">getRawPixel</span>
+ <span class="normal">
+ (<em>integer</em> x,
+ <em>integer</em> y)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Returns the single pixel at the image location (x,y), as an
+ a <em>tuple</em> of <em>integer</em>, in the form (a,r,g,b).
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>x</th>
+ <td>
+ The horizontal position of the pixel, starting with 0 at the left of the screen in the
+ orientation it had when the screenshot was taken.
+ </td>
+ </tr>
+ <tr>
+ <th>y</th>
+ <td>
+ The vertical position of the pixel, starting with 0 at the top of the screen in the
+ orientation it had when the screenshot was taken.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ A tuple of integers representing the pixel, in the form (a,r,g,b) where
+ a is the alpha channel value, and r, g, and b are the red, green, and blue values,
+ respectively.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="getRawPixelInt"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>tuple</em>
+ </span>
+ <span class="sympad">getRawPixelInt</span>
+ <span class="normal">
+ (<em>integer</em> x,
+ <em>integer</em> y)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Returns the single pixel at the image location (x,y), as an
+ an <em>integer</em>. Use this method to economize on memory.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>x</th>
+ <td>
+ The horizontal position of the pixel, starting with 0 at the left of the screen in the
+ orientation it had when the screenshot was taken.
+ </td>
+ </tr>
+ <tr>
+ <th>y</th>
+ <td>
+ The vertical position of the pixel, starting with 0 at the top of the screen in the
+ orientation it had when the screenshot was taken.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ The a,r,g, and b values of the pixel as 8-bit values combined into a 32-bit
+ integer, with a as the leftmost 8 bits, r the next rightmost, and so forth.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="getSubImage"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a>
+ </code>
+ </span>
+ <span class="sympad">getSubImage</span>
+ <span class="normal">
+ (<em>tuple</em> rect)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Creates a new <code>MonkeyImage</code> object from a rectangular selection of the
+ current image.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>rect</th>
+ <td>
+ A tuple (x, y, w, h) specifying the selection. x and y specify the 0-based pixel
+ position of the upper left-hand corner of the selection. w specifies the width of the
+ region, and h specifies its height, both in units of pixels.
+ <p>
+ The image's orientation is the same as the screen orientation at the time the
+ screenshot was made.
+ </p>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ A new <code>MonkeyImage</code> object containing the selection.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="sameAs"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>boolean</em>
+ </span>
+ <span class="sympad">sameAs</span>
+ <span class="normal">
+ (
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a>
+ </code> otherImage,
+ <em>float</em> percent
+ )
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Compares this <code>MonkeyImage</code> object to another and returns the result of
+ the comparison. The <code>percent</code> argument specifies the percentage
+ difference that is allowed for the two images to be "equal".
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>other</th>
+ <td>
+ Another <code>MonkeyImage</code> object to compare to this one.
+ </td>
+ </tr>
+ <tr>
+ <th>
+ percent
+ </th>
+ <td>
+ A float in the range 0.0 to 1.0, inclusive, indicating
+ the percentage of pixels that need to be the same for the method to return
+ <code>true</code>. The default is 1.0, indicating that all the pixels
+ must match.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ Boolean <code>true</code> if the images match, or boolean <code>false</code> otherwise.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="writeToFile"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">writeToFile</span>
+ <span class="normal">
+ (<em>string</em> filename,
+ <em>string</em> format)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Writes the current image to the file specified by <code>filename</code>, in the
+ format specified by <code>format</code>.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>path</th>
+ <td>
+ The fully-qualified filename and extension of the output file.
+ </td>
+ </tr>
+ <tr>
+ <th>
+ format
+ </th>
+ <td>
+ The output format to use for the file. If no format is provided, then the
+ method tries to guess the format from the filename's extension. If no
+ extension is provided and no format is specified, then the default format of
+ "png" (Portable Network Graphics) is used.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/docs/html/guide/developing/tools/MonkeyRunner.jd b/docs/html/guide/developing/tools/MonkeyRunner.jd
new file mode 100644
index 0000000..871e06d
--- /dev/null
+++ b/docs/html/guide/developing/tools/MonkeyRunner.jd
@@ -0,0 +1,445 @@
+page.title=MonkeyRunner
+@jd:body
+<style>
+ h4.jd-details-title {background-color: #DEE8F1;}
+</style>
+<p>
+ A monkeyrunner class that contains static utility methods.
+</p>
+<h2>Summary</h2>
+<table id="pubmethods" class="jd-sumtable">
+ <tr>
+ <th colspan="12" style="background-color: #E2E2E2">Methods</th>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#alert">alert</a>
+ </span>
+ (<em>string</em> message,
+ <em>string</em> title,
+ <em>string</em> okTitle)
+ </nobr>
+ <div class="jd-descrdiv">
+ Displays an alert dialog to the process running the current
+ program.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>integer</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#choice">choice</a>
+ </span>
+ (<em>string</em> message,
+ <em>iterable</em> choices,
+ <em>string</em> title)
+ </nobr>
+ <div class="jd-descrdiv">
+ Displays a dialog with a list of choices to the process running the current program.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#help">help</a>
+ </span>
+ (<em>string</em> format)
+ </nobr>
+ <div class="jd-descrdiv">
+ Displays the monkeyrunner API reference in a style similar to that of Python's
+ <code>pydoc</code> tool, using the specified format.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <em>string</em>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#input">input</a>
+ </span>
+ (<em>string</em> message,
+ <em>string</em> initialValue,
+ <em>string</em> title,
+ <em>string</em> okTitle,
+ <em>string</em> cancelTitle)
+ </nobr>
+ <div class="jd-descrdiv">
+ Displays a dialog that accepts input.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ void
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#sleep">sleep</a>
+ </span>
+ (<em>float</em> seconds)
+ </nobr>
+ <div class="jd-descrdiv">
+ Pauses the current program for the specified number of seconds.
+ </div>
+ </td>
+ </tr>
+ <tr class="api" >
+ <td class="jd-typecol">
+ <nobr>
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a>
+ </code>
+ </nobr>
+ </td>
+ <td class="jd-linkcol" width="100%">
+ <nobr>
+ <span class="sympad">
+ <a href="#waitForConnection">waitForConnection</a>
+ </span>
+ (<em>float</em> timeout,
+ <em>string</em> deviceId)
+ </nobr>
+ <div class="jd-descrdiv">
+ Tries to make a connection between the <code>monkeyrunner</code> backend and the
+ specified device or emulator.
+ </div>
+ </td>
+ </tr>
+</table>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methods -->
+<h2>Public Methods</h2>
+<A NAME="alert"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>string</em>
+ </span>
+ <span class="sympad">alert</span>
+ <span class="normal">
+ (
+ <em>string</em> message,
+ <em>string</em> title,
+ <em>string</em> okTitle)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Displays an alert dialog to the process running the current
+ program. The dialog is modal, so the program pauses until the user clicks the dialog's
+ button.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>message</th>
+ <td>
+ The message to display in the dialog.
+ </td>
+ </tr>
+ <tr>
+ <th>title</th>
+ <td>
+ The dialog's title. The default value is "Alert".
+ </td>
+ </tr>
+ <tr>
+ <th>okTitle</th>
+ <td>
+ The text displayed in the dialog button. The default value is "OK".
+ </td>
+ </tr>
+ </table>
+ </div>
+</div>
+</div>
+<A NAME="choice"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>integer</em>
+ </span>
+ <span class="sympad">choice</span>
+ <span class="normal">
+ (<em>string</em> message,
+ <em>iterable</em> choices,
+ <em>string</em> title)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Displays a dialog with a list of choices to the process running the current program. The
+ dialog is modal, so the program pauses until the user clicks one of the dialog's
+ buttons.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>message</th>
+ <td>
+ The prompt message displayed in the dialog.
+ </td>
+ </tr>
+ <tr>
+ <th>choices</th>
+ <td>
+ A Python iterable containing one or more objects that are displayed as strings. The
+ recommended form is an array of strings.
+ </td>
+ </tr>
+ <tr>
+ <th>
+ title
+ </th>
+ <td>
+ The dialog's title. The default is "Input".
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ If the user makes a selection and clicks the "OK" button, the method returns
+ the 0-based index of the selection within the iterable.
+ If the user clicks the "Cancel" button, the method returns -1.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="help"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">help</span>
+ <span class="normal">
+ (<em>string</em> format)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Displays the monkeyrunner API reference in a style similar to that of Python's
+ <code>pydoc</code> tool, using the specified format.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>format</th>
+ <td>
+ The markup format to use in the output. The possible values are "text" for plain text
+ or "html" for HTML.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="input"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <em>string</em>
+ </span>
+ <span class="sympad">input</span>
+ <span class="normal">
+ (<em>string</em> message
+ <em>string</em> initialValue,
+ <em>string</em> title,
+ <em>string</em> okTitle,
+ <em>string</em> cancelTitle)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Displays a dialog that accepts input and returns it to the program. The dialog is
+ modal, so the program pauses until the user clicks one of the dialog's buttons.
+ </p>
+ <p>
+ The dialog contains two buttons, one of which displays the okTitle value
+ and the other the cancelTitle value. If the user clicks the okTitle button,
+ the current value of the input box is returned. If the user clicks the cancelTitle
+ button, an empty string is returned.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>message</th>
+ <td>
+ The prompt message displayed in the dialog.
+ </td>
+ </tr>
+ <tr>
+ <th>initialValue</th>
+ <td>
+ The initial value to display in the dialog. The default is an empty string.
+ </td>
+ </tr>
+ <tr>
+ <th>title</th>
+ <td>
+ The dialog's title. The default is "Input".
+ </td>
+ </tr>
+ <tr>
+ <th>okTitle</th>
+ <td>
+ The text displayed in the okTitle button. The default is "OK".
+ </td>
+ </tr>
+ <tr>
+ <th>cancelTitle</th>
+ <td>
+ The text displayed in the cancelTitle button. The default is "Cancel".
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ If the user clicks the okTitle button, then the method returns the current value of
+ the dialog's input box. If the user clicks the cancelTitle button, the method returns
+ an empty string.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+<A NAME="sleep"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ void
+ </span>
+ <span class="sympad">sleep</span>
+ <span class="normal">
+ (
+ <em>float</em> seconds
+ )
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Pauses the current program for the specified number of seconds.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>seconds</th>
+ <td>
+ The number of seconds to pause.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
+<A NAME="waitForConnection"></A>
+<div class="jd-details api ">
+ <h4 class="jd-details-title">
+ <span class="normal">
+ <code>
+ <a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a>
+ </code>
+ </span>
+ <span class="sympad">waitForConnection</span>
+ <span class="normal">
+ (<em>float</em> timeout,
+ <em>string</em> deviceId)
+ </span>
+ </h4>
+ <div class="jd-details-descr">
+
+ <div class="jd-tagdata jd-tagdescr">
+ <p>
+ Tries to make a connection between the <code>monkeyrunner</code> backend and the
+ specified device or emulator.
+ </p>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Arguments</h5>
+ <table class="jd-tagtable">
+ <tr>
+ <th>timeout</th>
+ <td>
+ The number of seconds to wait for a connection. The default is to wait forever.
+ </td>
+ </tr>
+ <tr>
+ <th>
+ deviceId
+ </th>
+ <td>
+ A regular expression that specifies the serial number of the device or emulator. See
+ the topic
+ <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>
+ for a description of device and emulator serial numbers.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="jd-tagdata">
+ <h5 class="jd-tagtitle">Returns</h5>
+ <ul class="nolist">
+ <li>
+ A <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>
+ instance for the device or emulator. Use this object to control and communicate with the
+ device or emulator.
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
diff --git a/docs/html/guide/developing/tools/index.jd b/docs/html/guide/developing/tools/index.jd
index 6e9fde1..0e10377 100644
--- a/docs/html/guide/developing/tools/index.jd
+++ b/docs/html/guide/developing/tools/index.jd
@@ -3,27 +3,27 @@ page.title=Tools Overview
<img src="{@docRoot}assets/images/android_wrench.png" alt="" align="right">
-<p>The Android SDK includes a variety of custom tools that help you develop mobile
-applications on the Android platform. The most important of these are the Android
-Emulator and the Android Development Tools plugin for Eclipse, but the SDK also
-includes a variety of other tools for debugging, packaging, and installing your
+<p>The Android SDK includes a variety of custom tools that help you develop mobile
+applications on the Android platform. The most important of these are the Android
+Emulator and the Android Development Tools plugin for Eclipse, but the SDK also
+includes a variety of other tools for debugging, packaging, and installing your
applications on the emulator. </p>
-
+
<dl>
<dt><a href="adt.html">Android Development Tools Plugin</a> (for the Eclipse IDE)</dt>
- <dd>The ADT plugin adds powerful extensions to the Eclipse integrated environment,
- making creating and debugging your Android applications easier and faster. If you
- use Eclipse, the ADT plugin gives you an incredible boost in developing Android
+ <dd>The ADT plugin adds powerful extensions to the Eclipse integrated environment,
+ making creating and debugging your Android applications easier and faster. If you
+ use Eclipse, the ADT plugin gives you an incredible boost in developing Android
applications.</dd>
<dt><a href="emulator.html">Android Emulator</a></dt>
- <dd>A QEMU-based device-emulation tool that you can use to design,
+ <dd>A QEMU-based device-emulation tool that you can use to design,
debug, and test your applications in an actual Android run-time environment. </dd>
<dt><a href="avd.html">Android Virtual Devices (AVDs)</a></dt>
<dd>Virtual device configurations that you create, to model device
characteristics in the Android Emulator. In each configuration, you can
specify the Android platform to run, the hardware options, and the
- emulator skin to use. Each AVD functions as an independent device with
+ emulator skin to use. Each AVD functions as an independent device with
it's own storage for user data, SD card, and so on. </dd>
<dt><a href="hierarchy-viewer.html">Hierarchy Viewer</a></dt>
@@ -37,53 +37,53 @@ applications on the emulator. </p>
efficiency.
</dd>
- <dt><a href="draw9patch.html">Draw 9-patch</a></dt>
- <dd>The Draw 9-patch tool allows you to easily create a
- {@link android.graphics.NinePatch} graphic using a WYSIWYG editor. It also previews stretched
- versions of the image, and highlights the area in which content is allowed.
- </dd>
+ <dt><a href="draw9patch.html">Draw 9-patch</a></dt>
+ <dd>The Draw 9-patch tool allows you to easily create a
+ {@link android.graphics.NinePatch} graphic using a WYSIWYG editor. It also previews stretched
+ versions of the image, and highlights the area in which content is allowed.
+ </dd>
- <dt><a href="ddms.html" >Dalvik Debug Monitor
+ <dt><a href="ddms.html" >Dalvik Debug Monitor
Service</a> (ddms)</dt>
- <dd>Integrated with Dalvik, the Android platform's custom VM, this tool
- lets you manage processes on an emulator or device and assists in debugging.
- You can use it to kill processes, select a specific process to debug,
- generate trace data, view heap and thread information, take screenshots
- of the emulator or device, and more. </dd>
-
+ <dd>Integrated with Dalvik, the Android platform's custom VM, this tool
+ lets you manage processes on an emulator or device and assists in debugging.
+ You can use it to kill processes, select a specific process to debug,
+ generate trace data, view heap and thread information, take screenshots
+ of the emulator or device, and more. </dd>
+
<dt><a href="adb.html" >Android Debug Bridge</a> (adb)</dt>
- <dd>The adb tool lets you install your application's .apk files on an
- emulator or device and access the emulator or device from a command line.
- You can also use it to link a standard debugger to application code running
+ <dd>The adb tool lets you install your application's .apk files on an
+ emulator or device and access the emulator or device from a command line.
+ You can also use it to link a standard debugger to application code running
on an Android emulator or device.</dd>
- <dt><a href="aapt.html">Android Asset
+ <dt><a href="aapt.html">Android Asset
Packaging Tool</a> (aapt)</dt>
- <dd>The aapt tool lets you create .apk files containing the binaries and
+ <dd>The aapt tool lets you create .apk files containing the binaries and
resources of Android applications.</dd>
- <dt><a href="aidl.html" >Android Interface
+ <dt><a href="aidl.html" >Android Interface
Description Language</a> (aidl)</dt>
<dd>Lets you generate code for an interprocess interface, such as what
a service might use.</dd>
<dt><a href="adb.html#sqlite">sqlite3</a></dt>
- <dd>Included as a convenience, this tool lets you access the SQLite data
+ <dd>Included as a convenience, this tool lets you access the SQLite data
files created and used by Android applications.</dd>
<dt><a href="traceview.html" >Traceview</a></dt>
- <dd> This tool produces graphical analysis views of trace log data that you
+ <dd> This tool produces graphical analysis views of trace log data that you
can generate from your Android application. </dd>
<dt><a href="othertools.html#mksdcard">mksdcard</a></dt>
- <dd>Helps you create a disk image that you can use with the emulator,
+ <dd>Helps you create a disk image that you can use with the emulator,
to simulate the presence of an external storage card (such as an SD card).</dd>
<dt><a href="othertools.html#dx">dx</a></dt>
- <dd>The dx tool rewrites .class bytecode into Android bytecode
+ <dd>The dx tool rewrites .class bytecode into Android bytecode
(stored in .dex files.)</dd>
- <dt><a href="monkey.html">UI/Application
+ <dt><a href="monkey.html">UI/Application
Exerciser Monkey</a></dt>
<dd>The Monkey is a program that runs on your emulator or device and generates pseudo-random
streams of user events such as clicks, touches, or gestures, as well as a number of system-
@@ -92,9 +92,9 @@ efficiency.
<dt><a href="othertools.html#android">android</a></dt>
<dd>A script that lets you manage AVDs and generate <a
- href="http://ant.apache.org/" title="Ant">Ant</a> build files that
+ href="http://ant.apache.org/" title="Ant">Ant</a> build files that
you can use to compile your Android applications. </dd>
-
+
<dt><a href="zipalign.html">zipalign</a></dt>
<dd>An important .apk optimization tool. This tool ensures that all uncompressed data starts
with a particular alignment relative to the start of the file. This should always be used
diff --git a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
new file mode 100644
index 0000000..1838905
--- /dev/null
+++ b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
@@ -0,0 +1,308 @@
+page.title=monkeyrunner
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li>
+ <a href="#SampleProgram">A Simple monkeyrunner Program</a>
+ </li>
+ <li>
+ <a href="#APIClasses">The monkeyrunner API</a>
+ </li>
+ <li>
+ <a href="#RunningMonkeyRunner">Running monkeyrunner</a>
+ </li>
+ <li>
+ <a href="#Help">monkeyrunner Built-in Help</a>
+ </li>
+ <li>
+ <a href="#Plugins">Extending monkeyrunner with Plugins</a>
+ </li>
+ </ol>
+ <h2>See Also</h2>
+ <ol>
+ <li>
+ <a href="{@docRoot}guide/topics/testing/testing_android.html">Testing Fundamentals</a>
+ </li>
+ </ol>
+ </div>
+</div>
+<p>
+ The monkeyrunner tool provides an API for writing programs that control an Android device
+ or emulator from outside of Android code. With monkeyrunner, you can write a Python program
+ that installs an Android application or test package, runs it, sends keystrokes to it,
+ takes screenshots of its user interface, and stores screenshots on the workstation. The
+ monkeyrunner tool is primarily designed to test applications and devices at the
+ functional/framework level and for running unit test suites, but you are free to use it for
+ other purposes.
+</p>
+<p>
+ The monkeyrunner tool is not related to the
+ <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+ also known as the <code>monkey</code> tool. The <code>monkey</code> tool runs in an
+ <code><a href="{@docRoot}guide/developing/tools/adb.html">adb</a></code> shell directly on the
+ device or emulator and generates pseudo-random streams of user and system events. In comparison,
+ the monkeyrunner tool controls devices and emulators from a workstation by sending specific
+ commands and events from an API.
+</p>
+<p>
+ The monkeyrunner tool provides these unique features for Android testing:
+</p>
+<ul>
+ <li>
+ Multiple device control: The monkeyrunner API can apply one or more
+ test suites across multiple devices or emulators. You can physically attach all the devices
+ or start up all the emulators (or both) at once, connect to each one in turn
+ programmatically, and then run one or more tests. You can also start up an emulator
+ configuration programmatically, run one or more tests, and then shut down the emulator.
+ </li>
+ <li>
+ Functional testing: monkeyrunner can run an automated start-to-finish test of an Android
+ application. You provide input values with keystrokes or touch events, and view the results
+ as screenshots.
+ </li>
+ <li>
+ Regression testing - monkeyrunner can test application stability by running an application
+ and comparing its output screenshots to a set of screenshots that are known to be correct.
+ </li>
+ <li>
+ Extensible automation - Since monkeyrunner is an API toolkit, you can develop an entire
+ system of Python-based modules and programs for controlling Android devices. Besides using
+ the monkeyrunner API itself, you can use the standard Python
+ <code><a href="http://docs.python.org/library/os.html">os</a></code> and
+ <code><a href="http://docs.python.org/library/subprocess.html">subprocess</a></code>
+ modules to call Android tools such as
+ <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>.
+ <p>
+ You can also add your own classes to the monkeyrunner API. This is described
+ in more detail in the section
+ <a href="#Plugins">Extending monkeyrunner with plugins</a>.
+ </p>
+ </li>
+</ul>
+<p>
+ The monkeyrunner tool uses <a href="http://www.jython.org/">Jython</a>, a
+ implementation of Python that uses the Java programming language. Jython allows the
+ monkeyrunner API to interact easily with the Android framework. With Jython you can
+ use Python syntax to access the constants, classes, and methods of the API.
+</p>
+
+<h2 id="SampleProgram">A Simple monkeyrunner Program</h2>
+<p>
+ Here is a simple monkeyrunner program that connects to a device, creating a
+ <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>
+ object. Using the <code>MonkeyDevice</code> object, the program installs an Android application
+ package, runs one of its activities, and sends key events to the activity.
+ The program then takes a screenshot of the result, creating a
+ <code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code> object.
+ From this object, the program writes out a <code>.png</code> file containing the screenshot.
+</p>
+<pre>
+# Imports the monkeyrunner modules used by this program
+from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
+
+# Connects to the current device, returning a MonkeyDevice object
+device = MonkeyRunner.waitForConnection()
+
+# Installs the Android package. Notice that this method returns a boolean, so you can test
+# to see if the installation worked.
+device.installPackage('myproject/bin/MyApplication.apk')
+
+# Runs an activity in the application
+device.startActivity(component='com.example.android.myapplication.MainActivity')
+
+# Presses the Menu button
+device.press('KEYCODE_MENU','DOWN_AND_UP')
+
+# Takes a screenshot
+result = device.takeSnapShot
+
+# Writes the screenshot to a file
+result.writeToFile('myproject/shot1.png','png')
+</pre>
+
+<h2 id="APIClasses">The monkeyrunner API</h2>
+<p>
+ The monkeyrunner API is contained in three modules in the package
+ <code>com.android.monkeyrunner</code>:
+</p>
+<ul>
+ <li>
+ <code><a href="{@docRoot}guide/developing/tools/MonkeyRunner.html">MonkeyRunner</a></code>:
+ A class of utility methods for monkeyrunner programs. This class provides a method for
+ connecting monkeyrunner to a device or emulator. It also provides methods for
+ creating UIs for a monkeyrunner program and for displaying the built-in help.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>:
+ Represents a device or emulator. This class provides methods for installing and
+ uninstalling packages, starting an Activity, and sending keyboard or touch events to an
+ application. You also use this class to run test packages.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code>:
+ Represents a screen capture image. This class provides methods for capturing screens,
+ converting bitmap images to various formats, comparing two MonkeyImage objects, and
+ writing an image to a file.
+ </li>
+</ul>
+<p>
+ In a Python program, you access each class as a Python module. The monkeyrunner tool
+ does not import these modules automatically. To import a module, use the
+ Python <code>from</code> statement:
+</p>
+<pre>
+from com.android.monkeyrunner import &lt;module&gt;
+</pre>
+<p>
+ where <code>&lt;module&gt;</code> is the class name you want to import. You can import more
+ than one module in the same <code>from</code> statement by separating the module names with
+ commas.
+</p>
+<h2 id="RunningMonkeyRunner">Running monkeyrunner</h2>
+<p>
+ You can either run monkeyrunner programs from a file, or enter monkeyrunner statements in
+ an interactive session. You do both by invoking the <code>monkeyrunner</code> command
+ which is found in the <code>tools/</code> subdirectory of your SDK directory.
+ If you provide a filename as an argument, the <code>monkeyrunner</code> command
+ runs the file's contents as a Python program; otherwise, it starts an interactive session.
+</p>
+<p>
+ The syntax of the <code>monkeyrunner</code> command is
+</p>
+<pre>
+monkeyrunner -plugin &lt;plugin_jar&gt; &lt;program_filename&gt; &lt;program_options&gt;
+</pre>
+<p>
+Table 1 explains the flags and arguments.
+</p>
+<p class="table-caption" id="table1">
+ <strong>Table 1.</strong> <code>monkeyrunner</code> flags and arguments.</p>
+
+<table>
+ <tr>
+ <th>Argument</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>
+ <nobr>
+ <code>-plugin &lt;plugin_jar&gt;</code>
+ </nobr>
+ </td>
+ <td>
+ (Optional) Specifies a <code>.jar</code> file containing a plugin for monkeyrunner.
+ To learn more about monkeyrunner plugins, see
+ <a href="#Plugins">Extending monkeyrunner with plugins</a>. To specify more than one
+ file, include the argument multiple times.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <nobr>
+ <code>&lt;program_filename&gt;</code>
+ </nobr>
+ </td>
+ <td>
+ If you provide this argument, the <code>monkeyrunner</code> command runs the contents
+ of the file as a Python program. If the argument is not provided, the command starts an
+ interactive session.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <code>&lt;program_options&gt;</code>
+ </td>
+ <td>
+ (Optional) Flags and arguments for the program in &lt;program_file&gt;.
+ </td>
+ </tr>
+</table>
+<h2 id="Help">monkeyrunner Built-in Help</h2>
+<p>
+ You can generate an API reference for monkeyrunner by running:
+</p>
+<pre>
+monkeyrunner &lt;format&gt; help.py &lt;outfile&gt;
+</pre>
+<p>
+The arguments are:
+</p>
+ <ul>
+ <li>
+ <code>&lt;format&gt;</code> is either <code>text</code> for plain text output
+ or <code>html</code> for HTML output.
+ </li>
+ <li>
+ <code>&lt;outfile&gt;</code> is a path-qualified name for the output file.
+ </li>
+ </ul>
+<h2 id="Plugins">Extending monkeyrunner with Plugins</h2>
+<p>
+ You can extend the monkeyrunner API with classes you write in the Java programming language
+ and build into one or more <code>.jar</code> files. You can use this feature to extend the
+ monkeyrunner API with your own classes or to extend the existing classes. You can also use this
+ feature to initialize the monkeyrunner environment.
+</p>
+<p>
+ To provide a plugin to monkeyrunner, invoke the <code>monkeyrunner</code> command with the
+ <code>-plugin &lt;plugin_jar&gt;</code> argument described in
+ <a href="#table1">table 1</a>.
+</p>
+<p>
+ In your plugin code, you can import and extend the the main monkeyrunner classes
+ <code>MonkeyDevice</code>, <code>MonkeyImage</code>, and <code>MonkeyRunner</code> in
+ <code>com.android.monkeyrunner</code> (see <a href="#APIClasses">The monkeyrunner API</a>).
+</p>
+<p>
+ Note that plugins do not give you access to the Android SDK. You can't import packages
+ such as <code>com.android.app</code>. This is because monkeyrunner interacts with the
+ device or emulator below the level of the framework APIs.
+</p>
+<h3>The plugin startup class</h3>
+<p>
+ The <code>.jar</code> file for a plugin can specify a class that is instantiated before
+ script processing starts. To specify this class, add the key
+ <code>MonkeyRunnerStartupRunner</code> to the <code>.jar</code> file's
+ manifest. The value should be the name of the class to run at startup. The following
+ snippet shows how you would do this within an <code>ant</code> build script:
+</p>
+<pre>
+&lt;jar jarfile=&quot;myplugin&quot; basedir="&#36;&#123;build.dir&#125;&quot;&gt;
+&lt;manifest&gt;
+&lt;attribute name=&quot;MonkeyRunnerStartupRunner&quot; value=&quot;com.myapp.myplugin&quot;/&gt;
+&lt;/manifest&gt;
+&lt;/jar&gt;
+
+
+</pre>
+<p>
+ To get access to monkeyrunner's runtime environment, the startup class can implement
+ <code>com.google.common.base.Predicate&lt;PythonInterpreter&gt;</code>. For example, this
+ class sets up some variables in the default namespace:
+</p>
+<pre>
+package com.android.example;
+
+import com.google.common.base.Predicate;
+import org.python.util.PythonInterpreter;
+
+public class Main implements Predicate&lt;PythonInterpreter&gt; {
+ &#64;Override
+ public boolean apply(PythonInterpreter anInterpreter) {
+
+ /*
+ * Examples of creating and initializing variables in the monkeyrunner environment's
+ * namespace. During execution, the monkeyrunner program can refer to the variables "newtest"
+ * and "use_emulator"
+ *
+ */
+ anInterpreter.set("newtest", "enabled");
+ anInterpreter.set("use_emulator", 1);
+
+ return true;
+ }
+}
+</pre>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 2b80342..a43e334 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -254,34 +254,45 @@
<li><a href="<?cs var:toroot?>guide/topics/search/searchable-config.html">Searchable Configuration</a></li>
</ul>
</li>
+ <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
+ <span class="en">Device Administration</span>
+ </a> <span class="new">new!</span>
+ </li>
<li class="toggle-list">
<div>
- <a href="<?cs var:toroot ?>guide/topics/testing/index.html">
+ <a href="<?cs var:toroot?>guide/topics/testing/index.html">
<span class="en">Testing</span>
- </a> <span class="new">new!</span>
+ </a>
</div>
<ul>
- <li><a href="<?cs var:toroot?>guide/topics/testing/testing_android.html">
+ <li>
+ <a href="<?cs var:toroot?>guide/topics/testing/testing_android.html">
<span class="en">Testing Fundamentals</span></a>
+ <span class="new">new!</span>
</li>
- <li><a href="<?cs var:toroot?>guide/topics/testing/activity_testing.html">
+ <li>
+ <a href="<?cs var:toroot?>guide/topics/testing/activity_testing.html">
<span class="en">Activity Testing</span></a>
+ <span class="new">new!</span>
</li>
- <li><a href="<?cs var:toroot ?>guide/topics/testing/contentprovider_testing.html">
+ <li>
+ <a href="<?cs var:toroot?>guide/topics/testing/contentprovider_testing.html">
<span class="en">Content Provider Testing</span></a>
+ <span class="new">new!</span>
</li>
- <li><a href="<?cs var:toroot ?>guide/topics/testing/service_testing.html">
+ <li>
+ <a href="<?cs var:toroot?>guide/topics/testing/service_testing.html">
<span class="en">Service Testing</span></a>
+ <span class="new">new!</span>
</li>
- <li><a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
+ <li>
+ <a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
<span class="en">What To Test</span></a>
+ <span class="new">new!</span>
</li>
+
</ul>
</li>
- <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
- <span class="en">Device Administration</span>
- </a> <span class="new">new!</span>
- </li>
</ul>
</li>
@@ -336,6 +347,7 @@
<span class="en">Testing in Eclipse, with ADT</span>
</a>
</li>
+
<li>
<a href="<?cs var:toroot ?>guide/developing/testing/testing_otheride.html">
<span class="en">Testing in Other IDEs</span>
@@ -363,6 +375,34 @@
<li><a href="<?cs var:toroot ?>guide/developing/tools/layoutopt.html">layoutopt</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#mksdcard">mksdcard</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/monkey.html">Monkey</a></li>
+ <li class="toggle-list">
+ <div>
+ <a href="<?cs var:toroot?>guide/developing/tools/monkeyrunner_concepts.html">
+ <span class="en">monkeyrunner</span>
+ </a>
+ <span class="new">new!</span>
+ </div>
+ <ul>
+ <li>
+ <a href="<?cs var:toroot?>guide/developing/tools/MonkeyDevice.html">
+ <span class="en">MonkeyDevice</span>
+ </a>
+ <span class="new">new!</span>
+ </li>
+ <li>
+ <a href="<?cs var:toroot?>guide/developing/tools/MonkeyImage.html">
+ <span class="en">MonkeyImage</span>
+ </a>
+ <span class="new">new!</span>
+ </li>
+ <li>
+ <a href="<?cs var:toroot?>guide/developing/tools/MonkeyRunner.html">
+ <span class="en">MonkeyRunner</span>
+ </a>
+ <span class="new">new!</span>
+ </li>
+ </ul>
+ </li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/adb.html#sqlite">sqlite3</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/traceview.html" >Traceview</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/zipalign.html" >zipalign</a></li>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 1d6ab25..d868599 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -129,9 +129,8 @@ Menu. See <a href="menu-resource.html">Menu Resource</a>.</td>
<tr>
<td><code>raw/</code></td>
- <td><p>Arbitrary files to save in their raw form. Files in here are not compressed by the
-system. To open these resources with a raw {@link java.io.InputStream}, call {@link
-android.content.res.Resources#openRawResource(int)
+ <td><p>Arbitrary files to save in their raw form. To open these resources with a raw
+{@link java.io.InputStream}, call {@link android.content.res.Resources#openRawResource(int)
Resources.openRawResource()} with the resource ID, which is {@code R.raw.<em>filename</em>}.</p>
<p>However, if you need access to original file names and file hierarchy, you might consider
saving some resources in the {@code
diff --git a/docs/html/guide/topics/testing/index.jd b/docs/html/guide/topics/testing/index.jd
index b75656f..762a897 100644
--- a/docs/html/guide/topics/testing/index.jd
+++ b/docs/html/guide/topics/testing/index.jd
@@ -59,6 +59,20 @@ page.title=Testing
which guides you through a more complex testing scenario.
</li>
</ul>
+<h4>Tools</h4>
+<ul>
+ <li>
+ The
+ <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+ usually called Monkey, is a command-line tool that sends pseudo-random
+ streams of keystrokes, touches, and gestures to a device.
+ </li>
+ <li>
+ The <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a> tool
+ is an API and execution environment. You use monkeyrunner with Python programs
+ to test applications and devices.
+ </li>
+</ul>
<h4>Samples</h4>
<ul>
<li>
diff --git a/docs/html/guide/topics/testing/testing_android.jd b/docs/html/guide/topics/testing/testing_android.jd
index 2a4c949..d4b0dcc 100755
--- a/docs/html/guide/topics/testing/testing_android.jd
+++ b/docs/html/guide/topics/testing/testing_android.jd
@@ -38,7 +38,7 @@ page.title=Testing Fundamentals
<a href="#TestResults">Seeing Test Results</a>
</li>
<li>
- <a href="#Monkeys">Monkey and MonkeyRunner</a>
+ <a href="#Monkeys">monkey and monkeyrunner</a>
</li>
<li>
<a href="#PackageNames">Working With Package Names</a>
@@ -77,6 +77,13 @@ page.title=Testing Fundamentals
<a href="{@docRoot}guide/developing/testing/testing_otheride.html">
Testing in Other IDEs</a>
</li>
+ <li>
+ <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">
+ monkeyrunner</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>
+ </li>
</ol>
</div>
</div>
@@ -112,10 +119,10 @@ page.title=Testing Fundamentals
</li>
<li>
The SDK also provides
- <a href="{@docRoot}guide/topics/testing/monkeyrunner.html">MonkeyRunner</a>, an API for
- testing devices with Jython scripts, and <a
- href="{@docRoot}guide/developing/tools/monkey.html">Monkey</a>, a command-line tool for
- stress-testing UIs by sending pseudo-random events to a device.
+ <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a>, an API
+ testing devices with Python programs, and <a
+ href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+ a command-line tool for stress-testing UIs by sending pseudo-random events to a device.
</li>
</ul>
<p>
@@ -540,25 +547,28 @@ page.title=Testing Fundamentals
<a href="{@docRoot}guide/developing/testing/testing_otheride.html#RunTestsCommand">
Testing in Other IDEs</a>.
</p>
-<h2 id="Monkeys">Monkey and MonkeyRunner</h2>
+<h2 id="Monkeys">monkey and monkeyrunner</h2>
<p>
The SDK provides two tools for functional-level application testing:
</p>
<ul>
<li>
- <a href="{@docRoot}guide/developing/tools/monkey.html">Monkey</a> is a command-line
- tool that sends pseudo-random streams of keystrokes, touches, and gestures to a
- device. You run it with the <a href="{@docRoot}guide/developing/tools/adb.html">
- Android Debug Bridge</a> (adb) tool. You use it to stress-test your application and
- report back errors that are encountered. You can repeat a stream of events by
- running the tool each time with the same random number seed.
+The <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+ usually called "monkey", is a command-line tool that sends pseudo-random streams of
+ keystrokes, touches, and gestures to a device. You run it with the
+ <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> (adb) tool.
+ You use it to stress-test your application and report back errors that are encountered.
+ You can repeat a stream of events by running the tool each time with the same random
+ number seed.
</li>
<li>
- <a href="{@docRoot}guide/topics/testing/monkeyrunner.html">MonkeyRunner</a> is a
- Jython API that you use in test programs written in Python. The API includes functions
- for connecting to a device, installing and uninstalling packages, taking screenshots,
- comparing two images, and running a test package against an application. Using the API
- with Python, you can write a wide range of large, powerful, and complex tests.
+ The <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a> tool
+ is an API and execution environment for test programs written in Python. The API
+ includes functions for connecting to a device, installing and uninstalling packages,
+ taking screenshots, comparing two images, and running a test package against an
+ application. Using the API, you can write a wide range of large, powerful, and complex
+ tests. You run programs that use the API with the <code>monkeyrunner</code> command-line
+ tool.
</li>
</ul>
<h2 id="PackageNames">Working With Package names</h2>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 3b4ccb0..cef057e 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@ Android Market within a 14-day period ending on the data collection date noted b
<div class="dashboard-panel">
<img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:9.7,16.4,0.1,40.4,33.4&chl=
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:7.9,15.0,0.1,40.8,36.2&chl=
Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
6fad0c" />
@@ -62,13 +62,13 @@ Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>9.7%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>16.4%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>40.4%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>33.4%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>7.9%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>15.0%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>40.8%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>36.2%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on October 1, 2010</em></p>
+<p><em>Data collected during two weeks ending on November 1, 2010</em></p>
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
</div><!-- end dashboard-panel -->
@@ -96,19 +96,18 @@ Android Market within a 14-day period ending on the date indicated on the x-axis
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
-chxl=0:|2010/04/01|04/15|05/01|05/15|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|2010/10/01|1:|0
-%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&
-chxtc=0,5&chd=t:99.6,99.6,99.6,99.7,100.6,101.1,99.9,100.0,100.0,99.8,99.9,100.0,100.0|61.5,61.7,62.
-3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,88.0,89.3,90.3|29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68.
-2,70.4,72.2,73.9|4.0,28.3,32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8|0.0,0.0,0.0,0.0,0.8
-,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4&chm=tAndroid+1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid+1
-.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|tAndroid+2.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid+2
-.1,2f4708,3,1,15,,t:-30:-40|b,89cf19,3,4,0|tAndroid+2.2,131d02,4,9,15,,t::-5|B,6fad0c,4,5,0&chg=7,25
-&chdl=Android+1.5|Android+1.6|Android+2.0.1|Android+2.1|Android+2.2&chco=add274,9ad145,84c323,6ba213
-,507d08" />
-
-<p><em>Last historical dataset collected during two weeks ending on October 1, 2010</em></p>
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
+chxl=0%3A%7C2010/05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/
+01%7C10/15%7C2010/11/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
+%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.9,99.3,100.3,100.8,99.7,99.
+8,99.8,99.7,99.8,99.9,99.9,99.9,99.9|61.6,63.1,72.7,76.1,78.4,80.9,84.3,86.5,87.9,89.2,90.2,91.1,92.
+0|32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77.0|0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3,
+27.8,32.1,33.4,34.5,36.2&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,
+5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202.
+2,131d02,3,7,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|
+Android%202.2&chco=add274,94d134,73ad18,507d08" />
+
+<p><em>Last historical dataset collected during two weeks ending on November 1, 2010</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/faq/framework.jd b/docs/html/resources/faq/framework.jd
index f4b8db0..4a7a3fc 100644
--- a/docs/html/resources/faq/framework.jd
+++ b/docs/html/resources/faq/framework.jd
@@ -68,12 +68,17 @@ Preferences</a> storage mechanism.</p>
<p>For sharing complex non-persistent user-defined objects for short
duration, the following approaches are recommended:
</p>
- <h4>The android.app.Application class</h4>
- <p>The android.app.Application is a base class for those who need to
-maintain global application state. It can be accessed via
-getApplication() from any Activity or Service. It has a couple of
-life-cycle methods and will be instantiated by Android automatically if
-your register it in AndroidManifest.xml.</p>
+ <h4>Singleton class</h4>
+ <p>You can take advantage of the fact that your application
+components run in the same process through the use of a singleton.
+This is a class that is designed to have only one instance. It
+has a static method with a name such as <code>getInstance()</code>
+that returns the instance; the first time this method is called,
+it creates the global instance. Because all callers get the same
+instance, they can use this as a point of interaction. For
+example activity A may retrieve the instance and call setValue(3);
+later activity B may retrieve the instance and call getValue() to
+retrieve the last set value.</p>
<h4>A public static field/method</h4>
<p>An alternate way to make data accessible across Activities/Services is to use <em>public static</em>
@@ -90,18 +95,6 @@ Long based on a counter or time stamp) to the recipient activity via
intent extras. The recipient activity retrieves the object using this
key.</p>
- <h4>A Singleton class</h4>
- <p>There are advantages to using a static Singleton, such as you can
-refer to them without casting getApplication() to an
-application-specific class, or going to the trouble of hanging an
-interface on all your Application subclasses so that your various
-modules can refer to that interface instead. </p>
-<p>But, the life cycle of a static is not well under your control; so
-to abide by the life-cycle model, the application class should initiate and
-tear down these static objects in the onCreate() and onTerminate() methods
-of the Application Class</p>
-</p>
-
<h3>Persistent Objects</h3>
<p>Even while an application appears to continue running, the system
@@ -146,15 +139,11 @@ call.</p>
<h2>If an Activity starts a remote service, is there any way for the
Service to pass a message back to the Activity?</h2>
-<p>The remote service can define a callback interface and register it with the
-clients to callback into the clients. The
-{@link android.os.RemoteCallbackList RemoteCallbackList} class provides methods to
-register and unregister clients with the service, and send and receive
-messages.</p>
-
-<p>The sample code for remote service callbacks is given in <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">ApiDemos/RemoteService</a></p>
-
+<p>See the {@link android.app.Service} documentation's for examples of
+how clients can interact with a service. You can take advantage of the
+fact that your components run in the same process to greatly simplify
+service interaction from the generic remote case, as shown by the "Local
+Service Sample". In some cases techniques like singletons may also make sense.
<a name="6" id="6"></a>
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index a25fad4..289348a 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -51,7 +51,7 @@ public class ColorDrawable extends Drawable {
*/
public ColorDrawable(int color) {
this(null);
- mState.mBaseColor = mState.mUseColor = color;
+ setColor(color);
}
private ColorDrawable(ColorState state) {
@@ -72,6 +72,25 @@ public class ColorDrawable extends Drawable {
}
/**
+ * Gets the drawable's color value.
+ *
+ * @return int The color to draw.
+ */
+ public int getColor() {
+ return mState.mUseColor;
+ }
+
+ /**
+ * Sets the drawable's color value. This action will clobber the results of prior calls to
+ * {@link #setAlpha(int)} on this object, which side-affected the underlying color.
+ *
+ * @param color The color to draw.
+ */
+ public void setColor(int color) {
+ mState.mBaseColor = mState.mUseColor = color;
+ }
+
+ /**
* Returns the alpha value of this drawable's color.
*
* @return A value between 0 and 255.
@@ -131,7 +150,7 @@ public class ColorDrawable extends Drawable {
}
final static class ColorState extends ConstantState {
- int mBaseColor; // initial color. never changes
+ int mBaseColor; // base color, independent of setAlpha()
int mUseColor; // basecolor modulated by setAlpha()
int mChangingConfigurations;
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index f8ad5cc..dfd6ac8 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -199,6 +199,7 @@ public class Allocation extends BaseObj {
throw new IllegalStateException("Resize only support for 1D allocations at this time.");
}
mRS.nAllocationResize1D(mID, dimX);
+ mRS.finish(); // Necessary because resize is fifoed and update is async.
int typeID = mRS.nAllocationGetType(mID);
mType = new Type(typeID, mRS);
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 9fd905f..1081c35 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -262,11 +262,15 @@ public:
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
DEVICE_OUT_AUX_DIGITAL = 0x400,
+ DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
+ DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
DEVICE_OUT_DEFAULT = 0x8000,
DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL |
+ DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET |
+ DEVICE_OUT_DEFAULT),
DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
@@ -309,6 +313,8 @@ public:
FORCE_WIRED_ACCESSORY,
FORCE_BT_CAR_DOCK,
FORCE_BT_DESK_DOCK,
+ FORCE_ANALOG_DOCK,
+ FORCE_DIGITAL_DOCK,
NUM_FORCE_CONFIG,
FORCE_DEFAULT = FORCE_NONE
};
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index b009e1b..4fd281b 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -37,11 +37,11 @@ namespace android {
// buffers. This is the mode that will be used when CPU access to the buffer is
// required.
//
-// When Android native buffer use has been enabled, the OMX node must support
-// only color formats in the range [OMX_COLOR_FormatAndroidPrivateStart,
-// OMX_COLOR_FormatAndroidPrivateEnd). The node should then expect to receive
+// When Android native buffer use has been enabled for a given port, the video
+// color format for the port is to be interpreted as an Android pixel format
+// rather than an OMX color format. The node should then expect to receive
// UseAndroidNativeBuffer calls (via OMX_SetParameter) rather than UseBuffer
-// calls.
+// calls for that port.
struct EnableAndroidNativeBuffersParams {
OMX_U32 nSize;
OMX_VERSIONTYPE nVersion;
@@ -75,16 +75,6 @@ struct StoreMetaDataInBuffersParams {
OMX_BOOL bStoreMetaData;
};
-// Color formats in the range [OMX_COLOR_FormatAndroidPrivateStart,
-// OMX_COLOR_FormatAndroidPrivateEnd) will be converted to a gralloc pixel
-// format when used to allocate Android native buffers via gralloc. The
-// conversion is done by subtracting OMX_COLOR_FormatAndroidPrivateStart from
-// the color format reported by the codec.
-enum {
- OMX_COLOR_FormatAndroidPrivateStart = 0xA0000000,
- OMX_COLOR_FormatAndroidPrivateEnd = 0xB0000000,
-};
-
// A pointer to this struct is passed to OMX_SetParameter when the extension
// index for the 'OMX.google.android.index.useAndroidNativeBuffer' extension is
// given. This call will only be performed if a prior call was made with the
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 1f5ed7c..c692bc1 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -78,10 +78,6 @@ void ScriptC::setupScript(Context *rsc)
if (dest) {
*dest = ptr;
- } else {
- if (rsc->props.mLogScripts) {
- LOGV("ScriptC::setupScript, NULL var binding address.");
- }
}
}
}
@@ -404,16 +400,14 @@ static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name)
const ScriptCState::SymbolTable_t *sym;
ScriptC *s = (ScriptC *)pContext;
sym = ScriptCState::lookupSymbol(name);
- if (sym) {
- return sym->mPtr;
+ if (!sym) {
+ sym = ScriptCState::lookupSymbolCL(name);
}
- sym = ScriptCState::lookupSymbolCL(name);
- if (sym) {
- return sym->mPtr;
+ if (!sym) {
+ sym = ScriptCState::lookupSymbolGL(name);
}
- s->mEnviroment.mIsThreadable = false;
- sym = ScriptCState::lookupSymbolGL(name);
if (sym) {
+ s->mEnviroment.mIsThreadable &= sym->threadable;
return sym->mPtr;
}
LOGE("ScriptC sym lookup failed for %s", name);
@@ -425,7 +419,6 @@ extern unsigned rs_runtime_lib_bc_size;
void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
{
- LOGV("%p ScriptCState::runCompiler ", rsc);
{
StopWatch compileTimer("RenderScript compile time");
s->mBccScript = bccCreateScript();
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index e5b5ba9..86a7ad3 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -89,6 +89,7 @@ public:
struct SymbolTable_t {
const char * mName;
void * mPtr;
+ bool threadable;
};
//static SymbolTable_t gSyms[];
static const SymbolTable_t * lookupSymbol(const char *);
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 9fadee0..ecae306 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -436,120 +436,120 @@ void SC_ForEach2(RsScript vs,
// ::= d # double
static ScriptCState::SymbolTable_t gSyms[] = {
- { "__divsi3", (void *)&SC_divsi3 },
+ { "__divsi3", (void *)&SC_divsi3, true },
// allocation
- { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX },
- { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY },
- { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ },
- { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD },
- { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces },
- { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation },
+ { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true },
+ { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true },
+ { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true },
+ { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true },
+ { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true },
+ { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true },
- { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX },
- { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY },
- { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ },
+ { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true },
+ { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true },
+ { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true },
- { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject },
- { "_Z10rsIsObject10rs_element", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject },
- { "_Z10rsIsObject7rs_type", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject },
- { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject },
- { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject },
- { "_Z10rsIsObject9rs_script", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject },
- { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject },
- { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject },
- { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject },
- { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject },
- { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true },
- { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject },
- { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject },
- { "_Z10rsIsObject7rs_font", (void *)&SC_isObject },
+ { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true },
+ { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true },
+ { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true },
- { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty },
+ { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true },
// Debug
- { "_Z7rsDebugPKcf", (void *)&SC_debugF },
- { "_Z7rsDebugPKcff", (void *)&SC_debugFv2 },
- { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3 },
- { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4 },
- { "_Z7rsDebugPKcd", (void *)&SC_debugD },
- { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4 },
- { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3 },
- { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2 },
- { "_Z7rsDebugPKci", (void *)&SC_debugI32 },
- { "_Z7rsDebugPKcj", (void *)&SC_debugU32 },
+ { "_Z7rsDebugPKcf", (void *)&SC_debugF, true },
+ { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true },
+ { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true },
+ { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true },
+ { "_Z7rsDebugPKcd", (void *)&SC_debugD, true },
+ { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true },
+ { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true },
+ { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true },
+ { "_Z7rsDebugPKci", (void *)&SC_debugI32, true },
+ { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true },
// Both "long" and "unsigned long" need to be redirected to their
// 64-bit counterparts, since we have hacked Slang to use 64-bit
// for "long" on Arm (to be similar to Java).
- { "_Z7rsDebugPKcl", (void *)&SC_debugLL64 },
- { "_Z7rsDebugPKcm", (void *)&SC_debugULL64 },
- { "_Z7rsDebugPKcx", (void *)&SC_debugLL64 },
- { "_Z7rsDebugPKcy", (void *)&SC_debugULL64 },
- { "_Z7rsDebugPKcPKv", (void *)&SC_debugP },
+ { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true },
+ { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true },
+ { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true },
+ { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true },
+ { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true },
// RS Math
- { "_Z6rsRandi", (void *)&SC_randi },
- { "_Z6rsRandii", (void *)&SC_randi2 },
- { "_Z6rsRandf", (void *)&SC_randf },
- { "_Z6rsRandff", (void *)&SC_randf2 },
- { "_Z6rsFracf", (void *)&SC_frac },
+ { "_Z6rsRandi", (void *)&SC_randi, true },
+ { "_Z6rsRandii", (void *)&SC_randi2, true },
+ { "_Z6rsRandf", (void *)&SC_randf, true },
+ { "_Z6rsRandff", (void *)&SC_randf2, true },
+ { "_Z6rsFracf", (void *)&SC_frac, true },
// time
- { "_Z8rsSecondv", (void *)&SC_second },
- { "_Z8rsMinutev", (void *)&SC_minute },
- { "_Z6rsHourv", (void *)&SC_hour },
- { "_Z5rsDayv", (void *)&SC_day },
- { "_Z7rsMonthv", (void *)&SC_month },
- { "_Z6rsYearv", (void *)&SC_year },
- { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis },
- { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos },
- { "_Z7rsGetDtv", (void*)&SC_getDt },
-
- { "_Z14rsSendToClienti", (void *)&SC_toClient },
- { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2 },
- { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking },
- { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2 },
-
- { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach },
- //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2 },
+ { "_Z8rsSecondv", (void *)&SC_second, true },
+ { "_Z8rsMinutev", (void *)&SC_minute, true },
+ { "_Z6rsHourv", (void *)&SC_hour, true },
+ { "_Z5rsDayv", (void *)&SC_day, true },
+ { "_Z7rsMonthv", (void *)&SC_month, true },
+ { "_Z6rsYearv", (void *)&SC_year, true },
+ { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
+ { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
+ { "_Z7rsGetDtv", (void*)&SC_getDt, false },
+
+ { "_Z14rsSendToClienti", (void *)&SC_toClient, false },
+ { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2, false },
+ { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking, false },
+ { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false },
+
+ { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false },
+ //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true },
////////////////////////////////////////////////////////////////////
- //{ "sinf_fast", (void *)&SC_sinf_fast },
- //{ "cosf_fast", (void *)&SC_cosf_fast },
+ //{ "sinf_fast", (void *)&SC_sinf_fast, true },
+ //{ "cosf_fast", (void *)&SC_cosf_fast, true },
- { NULL, NULL }
+ { NULL, NULL, false }
};
const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
index 1b1a752..7031f84 100644
--- a/libs/rs/rsScriptC_LibCL.cpp
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -88,11 +88,6 @@ static float SC_tanpi(float v) {
return tanf(v * M_PI);
}
- //{ "logb", (void *)& },
- //{ "mad", (void *)& },
- //{ "nan", (void *)& },
- //{ "tgamma", (void *)& },
-
//////////////////////////////////////////////////////////////////////////////
// Integer
//////////////////////////////////////////////////////////////////////////////
@@ -198,105 +193,105 @@ static float SC_sign_f32(float value)
static ScriptCState::SymbolTable_t gSyms[] = {
// OpenCL math
- { "_Z4acosf", (void *)&acosf },
- { "_Z5acoshf", (void *)&acoshf },
- { "_Z6acospif", (void *)&SC_acospi },
- { "_Z4asinf", (void *)&asinf },
- { "_Z5asinhf", (void *)&asinhf },
- { "_Z6asinpif", (void *)&SC_asinpi },
- { "_Z4atanf", (void *)&atanf },
- { "_Z5atan2ff", (void *)&atan2f },
- { "_Z6atanpif", (void *)&SC_atanpi },
- { "_Z7atan2piff", (void *)&SC_atan2pi },
- { "_Z4cbrtf", (void *)&cbrtf },
- { "_Z4ceilf", (void *)&ceilf },
- { "_Z8copysignff", (void *)&copysignf },
- { "_Z3cosf", (void *)&cosf },
- { "_Z4coshf", (void *)&coshf },
- { "_Z5cospif", (void *)&SC_cospi },
- { "_Z4erfcf", (void *)&erfcf },
- { "_Z3erff", (void *)&erff },
- { "_Z3expf", (void *)&expf },
- { "_Z4exp2f", (void *)&exp2f },
- { "_Z5exp10f", (void *)&SC_exp10 },
- { "_Z5expm1f", (void *)&expm1f },
- { "_Z4fabsf", (void *)&fabsf },
- { "_Z4fdimff", (void *)&fdimf },
- { "_Z5floorf", (void *)&floorf },
- { "_Z3fmafff", (void *)&fmaf },
- { "_Z4fmaxff", (void *)&fmaxf },
- { "_Z4fminff", (void *)&fminf }, // float fmin(float, float)
- { "_Z4fmodff", (void *)&fmodf },
- { "_Z5fractfPf", (void *)&SC_fract },
- { "_Z5frexpfPi", (void *)&frexpf },
- { "_Z5hypotff", (void *)&hypotf },
- { "_Z5ilogbf", (void *)&ilogbf },
- { "_Z5ldexpfi", (void *)&ldexpf },
- { "_Z6lgammaf", (void *)&lgammaf },
- { "_Z3logf", (void *)&logf },
- { "_Z4log2f", (void *)&SC_log2 },
- { "_Z5log10f", (void *)&log10f },
- { "_Z5log1pf", (void *)&log1pf },
- //{ "logb", (void *)& },
- //{ "mad", (void *)& },
- { "modf", (void *)&modff },
- //{ "nan", (void *)& },
- { "_Z9nextafterff", (void *)&nextafterf },
- { "_Z3powff", (void *)&powf },
- { "_Z4pownfi", (void *)&SC_pown },
- { "_Z4powrff", (void *)&SC_powr },
- { "_Z9remainderff", (void *)&remainderf },
- { "remquo", (void *)&remquof },
- { "_Z4rintf", (void *)&rintf },
- { "_Z5rootnfi", (void *)&SC_rootn },
- { "_Z5roundf", (void *)&roundf },
- { "_Z5rsqrtf", (void *)&SC_rsqrt },
- { "_Z3sinf", (void *)&sinf },
- { "sincos", (void *)&SC_sincos },
- { "_Z4sinhf", (void *)&sinhf },
- { "_Z5sinpif", (void *)&SC_sinpi },
- { "_Z4sqrtf", (void *)&sqrtf },
- { "_Z3tanf", (void *)&tanf },
- { "_Z4tanhf", (void *)&tanhf },
- { "_Z5tanpif", (void *)&SC_tanpi },
- //{ "tgamma", (void *)& },
- { "_Z5truncf", (void *)&truncf },
+ { "_Z4acosf", (void *)&acosf, true },
+ { "_Z5acoshf", (void *)&acoshf, true },
+ { "_Z6acospif", (void *)&SC_acospi, true },
+ { "_Z4asinf", (void *)&asinf, true },
+ { "_Z5asinhf", (void *)&asinhf, true },
+ { "_Z6asinpif", (void *)&SC_asinpi, true },
+ { "_Z4atanf", (void *)&atanf, true },
+ { "_Z5atan2ff", (void *)&atan2f, true },
+ { "_Z6atanpif", (void *)&SC_atanpi, true },
+ { "_Z7atan2piff", (void *)&SC_atan2pi, true },
+ { "_Z4cbrtf", (void *)&cbrtf, true },
+ { "_Z4ceilf", (void *)&ceilf, true },
+ { "_Z8copysignff", (void *)&copysignf, true },
+ { "_Z3cosf", (void *)&cosf, true },
+ { "_Z4coshf", (void *)&coshf, true },
+ { "_Z5cospif", (void *)&SC_cospi, true },
+ { "_Z4erfcf", (void *)&erfcf, true },
+ { "_Z3erff", (void *)&erff, true },
+ { "_Z3expf", (void *)&expf, true },
+ { "_Z4exp2f", (void *)&exp2f, true },
+ { "_Z5exp10f", (void *)&SC_exp10, true },
+ { "_Z5expm1f", (void *)&expm1f, true },
+ { "_Z4fabsf", (void *)&fabsf, true },
+ { "_Z4fdimff", (void *)&fdimf, true },
+ { "_Z5floorf", (void *)&floorf, true },
+ { "_Z3fmafff", (void *)&fmaf, true },
+ { "_Z4fmaxff", (void *)&fmaxf, true },
+ { "_Z4fminff", (void *)&fminf, true }, // float fmin(float, float)
+ { "_Z4fmodff", (void *)&fmodf, true },
+ { "_Z5fractfPf", (void *)&SC_fract, true },
+ { "_Z5frexpfPi", (void *)&frexpf, true },
+ { "_Z5hypotff", (void *)&hypotf, true },
+ { "_Z5ilogbf", (void *)&ilogbf, true },
+ { "_Z5ldexpfi", (void *)&ldexpf, true },
+ { "_Z6lgammaf", (void *)&lgammaf, true },
+ { "_Z3logf", (void *)&logf, true },
+ { "_Z4log2f", (void *)&SC_log2, true },
+ { "_Z5log10f", (void *)&log10f, true },
+ { "_Z5log1pf", (void *)&log1pf, true },
+ //{ "logb", (void *)&, true },
+ //{ "mad", (void *)&, true },
+ { "modf", (void *)&modff, true },
+ //{ "nan", (void *)&, true },
+ { "_Z9nextafterff", (void *)&nextafterf, true },
+ { "_Z3powff", (void *)&powf, true },
+ { "_Z4pownfi", (void *)&SC_pown, true },
+ { "_Z4powrff", (void *)&SC_powr, true },
+ { "_Z9remainderff", (void *)&remainderf, true },
+ { "remquo", (void *)&remquof, true },
+ { "_Z4rintf", (void *)&rintf, true },
+ { "_Z5rootnfi", (void *)&SC_rootn, true },
+ { "_Z5roundf", (void *)&roundf, true },
+ { "_Z5rsqrtf", (void *)&SC_rsqrt, true },
+ { "_Z3sinf", (void *)&sinf, true },
+ { "sincos", (void *)&SC_sincos, true },
+ { "_Z4sinhf", (void *)&sinhf, true },
+ { "_Z5sinpif", (void *)&SC_sinpi, true },
+ { "_Z4sqrtf", (void *)&sqrtf, true },
+ { "_Z3tanf", (void *)&tanf, true },
+ { "_Z4tanhf", (void *)&tanhf, true },
+ { "_Z5tanpif", (void *)&SC_tanpi, true },
+ //{ "tgamma", (void *)&, true },
+ { "_Z5truncf", (void *)&truncf, true },
// OpenCL Int
- { "_Z3absi", (void *)&SC_abs_i32 },
- { "_Z3abss", (void *)&SC_abs_i16 },
- { "_Z3absc", (void *)&SC_abs_i8 },
- { "_Z3clzj", (void *)&SC_clz_u32 },
- { "_Z3clzt", (void *)&SC_clz_u16 },
- { "_Z3clzh", (void *)&SC_clz_u8 },
- { "_Z3clzi", (void *)&SC_clz_i32 },
- { "_Z3clzs", (void *)&SC_clz_i16 },
- { "_Z3clzc", (void *)&SC_clz_i8 },
- { "_Z3maxjj", (void *)&SC_max_u32 },
- { "_Z3maxtt", (void *)&SC_max_u16 },
- { "_Z3maxhh", (void *)&SC_max_u8 },
- { "_Z3maxii", (void *)&SC_max_i32 },
- { "_Z3maxss", (void *)&SC_max_i16 },
- { "_Z3maxcc", (void *)&SC_max_i8 },
- { "_Z3minjj", (void *)&SC_min_u32 },
- { "_Z3mintt", (void *)&SC_min_u16 },
- { "_Z3minhh", (void *)&SC_min_u8 },
- { "_Z3minii", (void *)&SC_min_i32 },
- { "_Z3minss", (void *)&SC_min_i16 },
- { "_Z3mincc", (void *)&SC_min_i8 },
+ { "_Z3absi", (void *)&SC_abs_i32, true },
+ { "_Z3abss", (void *)&SC_abs_i16, true },
+ { "_Z3absc", (void *)&SC_abs_i8, true },
+ { "_Z3clzj", (void *)&SC_clz_u32, true },
+ { "_Z3clzt", (void *)&SC_clz_u16, true },
+ { "_Z3clzh", (void *)&SC_clz_u8, true },
+ { "_Z3clzi", (void *)&SC_clz_i32, true },
+ { "_Z3clzs", (void *)&SC_clz_i16, true },
+ { "_Z3clzc", (void *)&SC_clz_i8, true },
+ { "_Z3maxjj", (void *)&SC_max_u32, true },
+ { "_Z3maxtt", (void *)&SC_max_u16, true },
+ { "_Z3maxhh", (void *)&SC_max_u8, true },
+ { "_Z3maxii", (void *)&SC_max_i32, true },
+ { "_Z3maxss", (void *)&SC_max_i16, true },
+ { "_Z3maxcc", (void *)&SC_max_i8, true },
+ { "_Z3minjj", (void *)&SC_min_u32, true },
+ { "_Z3mintt", (void *)&SC_min_u16, true },
+ { "_Z3minhh", (void *)&SC_min_u8, true },
+ { "_Z3minii", (void *)&SC_min_i32, true },
+ { "_Z3minss", (void *)&SC_min_i16, true },
+ { "_Z3mincc", (void *)&SC_min_i8, true },
// OpenCL 6.11.4
- { "_Z5clampfff", (void *)&SC_clamp_f32 },
- { "_Z7degreesf", (void *)&SC_degrees },
- { "_Z3maxff", (void *)&SC_max_f32 },
- { "_Z3minff", (void *)&SC_min_f32 },
- { "_Z3mixfff", (void *)&SC_mix_f32 },
- { "_Z7radiansf", (void *)&SC_radians },
- { "_Z4stepff", (void *)&SC_step_f32 },
- //{ "smoothstep", (void *)& },
- { "_Z4signf", (void *)&SC_sign_f32 },
-
- { NULL, NULL }
+ { "_Z5clampfff", (void *)&SC_clamp_f32, true },
+ { "_Z7degreesf", (void *)&SC_degrees, true },
+ { "_Z3maxff", (void *)&SC_max_f32, true },
+ { "_Z3minff", (void *)&SC_min_f32, true },
+ { "_Z3mixfff", (void *)&SC_mix_f32, true },
+ { "_Z7radiansf", (void *)&SC_radians, true },
+ { "_Z4stepff", (void *)&SC_step_f32, true },
+ //{ "smoothstep", (void *)&, true },
+ { "_Z4signf", (void *)&SC_sign_f32, true },
+
+ { NULL, NULL, false }
};
const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolCL(const char *sym)
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index b991cab..5b07e7b 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -441,53 +441,53 @@ static void SC_FontColor(float r, float g, float b, float a)
// ::= d # double
static ScriptCState::SymbolTable_t gSyms[] = {
- { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment },
- { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore },
- { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex },
- { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster },
- { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler },
- { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture },
+ { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment, false },
+ { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore, false },
+ { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex, false },
+ { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster, false },
+ { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler, false },
+ { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture, false },
- { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix },
- { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix },
- { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix },
+ { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix, false },
+ { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix, false },
+ { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix, false },
- { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix },
+ { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix, false },
- { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor },
+ { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor, false },
- { "_Z11rsgGetWidthv", (void *)&SC_getWidth },
- { "_Z12rsgGetHeightv", (void *)&SC_getHeight },
+ { "_Z11rsgGetWidthv", (void *)&SC_getWidth, false },
+ { "_Z12rsgGetHeightv", (void *)&SC_getHeight, false },
- { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2 },
- { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture },
- { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject },
+ { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2, false },
+ { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture, false },
+ { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject, false },
- { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect },
- { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad },
- { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords },
- { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace },
+ { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect, false },
+ { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad, false },
+ { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords, false },
+ { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace, false },
- { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh },
- { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive },
- { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange },
- { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox },
+ { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh, false },
+ { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive, false },
+ { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange, false },
+ { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox, false },
- { "_Z13rsgClearColorffff", (void *)&SC_ClearColor },
- { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth },
+ { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
+ { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
- { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText },
- { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc },
- { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText },
- { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc },
+ { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText, false },
+ { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc, false },
+ { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText, false },
+ { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc, false },
- { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont },
- { "_Z12rsgFontColorffff", (void *)&SC_FontColor },
+ { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont, false },
+ { "_Z12rsgFontColorffff", (void *)&SC_FontColor, false },
// misc
- { "_Z5colorffff", (void *)&SC_color },
+ { "_Z5colorffff", (void *)&SC_color, false },
- { NULL, NULL }
+ { NULL, NULL, false }
};
const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolGL(const char *sym)
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b936c4d..58d4c56 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -1408,8 +1408,13 @@ String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication*
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
int32_t eventType = POWER_MANAGER_BUTTON_EVENT;
- if (eventEntry->type == EventEntry::TYPE_MOTION) {
+ switch (eventEntry->type) {
+ case EventEntry::TYPE_MOTION: {
const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
+ if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+ return;
+ }
+
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
switch (motionEntry->action) {
case AMOTION_EVENT_ACTION_DOWN:
@@ -1427,6 +1432,15 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
break;
}
}
+ break;
+ }
+ case EventEntry::TYPE_KEY: {
+ const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
+ if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
+ return;
+ }
+ break;
+ }
}
CommandEntry* commandEntry = postCommandLocked(
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 23f34d2..a49bb37 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -307,10 +307,13 @@ public class AudioService extends IAudioService.Stub {
// Register for device connection intent broadcasts.
IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+
intentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
+ intentFilter.addAction(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+ intentFilter.addAction(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
context.registerReceiver(mReceiver, intentFilter);
// Register for media button intent broadcasts.
@@ -1816,6 +1819,12 @@ public class AudioService extends IAudioService.Stub {
case Intent.EXTRA_DOCK_STATE_CAR:
config = AudioSystem.FORCE_BT_CAR_DOCK;
break;
+ case Intent.EXTRA_DOCK_STATE_LE_DESK:
+ config = AudioSystem.FORCE_ANALOG_DOCK;
+ break;
+ case Intent.EXTRA_DOCK_STATE_HE_DESK:
+ config = AudioSystem.FORCE_DIGITAL_DOCK;
+ break;
case Intent.EXTRA_DOCK_STATE_UNDOCKED:
default:
config = AudioSystem.FORCE_NONE;
@@ -1927,6 +1936,32 @@ public class AudioService extends IAudioService.Stub {
mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
}
}
+ } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) {
+ int state = intent.getIntExtra("state", 0);
+ Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state);
+ boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+ if (state == 0 && isConnected) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+ } else if (state == 1 && !isConnected) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
+ AudioSystem.DEVICE_STATE_AVAILABLE, "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), "");
+ }
+ } else if (action.equals(Intent.ACTION_USB_DGTL_HEADSET_PLUG)) {
+ int state = intent.getIntExtra("state", 0);
+ Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_DGTL_HEADSET_PLUG, state = "+state);
+ boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
+ if (state == 0 && isConnected) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
+ } else if (state == 1 && !isConnected) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
+ AudioSystem.DEVICE_STATE_AVAILABLE, "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), "");
+ }
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
synchronized (mScoClients) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index a4818ff..5442791 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -243,6 +243,8 @@ public class AudioSystem
public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
+ public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
+ public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
public static final int DEVICE_OUT_DEFAULT = 0x8000;
// input devices
public static final int DEVICE_IN_COMMUNICATION = 0x10000;
@@ -273,6 +275,8 @@ public class AudioSystem
public static final int FORCE_WIRED_ACCESSORY = 5;
public static final int FORCE_BT_CAR_DOCK = 6;
public static final int FORCE_BT_DESK_DOCK = 7;
+ public static final int FORCE_ANALOG_DOCK = 8;
+ public static final int FORCE_DIGITAL_DOCK = 9;
public static final int FORCE_DEFAULT = FORCE_NONE;
// usage for serForceUse
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 381b77a..532a2df 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -83,6 +83,11 @@ public class MediaFile {
private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U;
private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL;
+ // Drm file types
+ public static final int FILE_TYPE_FL = 51;
+ private static final int FIRST_DRM_FILE_TYPE = FILE_TYPE_FL;
+ private static final int LAST_DRM_FILE_TYPE = FILE_TYPE_FL;
+
// Other popular file types
public static final int FILE_TYPE_TEXT = 100;
public static final int FILE_TYPE_HTML = 101;
@@ -189,6 +194,8 @@ public class MediaFile {
addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST);
addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST);
+ addFileType("FL", FILE_TYPE_FL, "application/x-android-drm-fl");
+
addFileType("TXT", FILE_TYPE_TEXT, "text/plain", MtpConstants.FORMAT_TEXT);
addFileType("HTM", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML);
addFileType("HTML", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML);
@@ -222,6 +229,11 @@ public class MediaFile {
fileType <= LAST_PLAYLIST_FILE_TYPE);
}
+ public static boolean isDrmFileType(int fileType) {
+ return (fileType >= FIRST_DRM_FILE_TYPE &&
+ fileType <= LAST_DRM_FILE_TYPE);
+ }
+
public static MediaFileType getFileType(String path) {
int lastDot = path.lastIndexOf(".");
if (lastDot < 0)
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index e5fa0f8..5aabddf 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.IContentProvider;
import android.database.Cursor;
import android.database.SQLException;
+import android.drm.DrmManagerClient;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Process;
@@ -360,6 +361,7 @@ public class MediaScanner
private ArrayList<FileCacheEntry> mPlayLists;
private HashMap<String, Uri> mGenreCache;
+ private DrmManagerClient mDrmManagerClient = null;
public MediaScanner(Context c) {
native_setup();
@@ -447,6 +449,11 @@ public class MediaScanner
}
}
+ if (System.getProperty("drm.service.enabled").equals("true")
+ && MediaFile.isDrmFileType(mFileType)) {
+ mFileType = getFileTypeFromDrm(path);
+ }
+
String key = path;
if (mCaseInsensitivePaths) {
key = path.toLowerCase();
@@ -874,6 +881,27 @@ public class MediaScanner
}
}
+ private int getFileTypeFromDrm(String path) {
+ if (!System.getProperty("drm.service.enabled").equals("true")) {
+ return 0;
+ }
+
+ int resultFileType = 0;
+
+ if (mDrmManagerClient == null) {
+ mDrmManagerClient = new DrmManagerClient(mContext);
+ }
+
+ if (mDrmManagerClient.canHandle(path, null)) {
+ String drmMimetype = mDrmManagerClient.getOriginalMimeType(path);
+ if (drmMimetype != null) {
+ mMimeType = drmMimetype;
+ resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype);
+ }
+ }
+ return resultFileType;
+ }
+
}; // end of anonymous MediaScannerClient instance
private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 51647434..57ab3a1 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
+import android.os.Environment;
import android.os.RemoteException;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Files;
@@ -45,6 +46,7 @@ public class MtpDatabase {
private final String mVolumeName;
private final Uri mObjectsUri;
private final String mMediaStoragePath;
+ private final String mExternalStoragePath;
// true if the database has been modified in the current MTP session
private boolean mDatabaseModified;
@@ -77,7 +79,6 @@ public class MtpDatabase {
Files.FileColumns.DATE_MODIFIED, // 5
};
private static final String ID_WHERE = Files.FileColumns._ID + "=?";
- private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
+ Files.FileColumns.FORMAT + "=?";
@@ -98,6 +99,7 @@ public class MtpDatabase {
mMediaProvider = context.getContentResolver().acquireProvider("media");
mVolumeName = volumeName;
mMediaStoragePath = storagePath;
+ mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
mObjectsUri = Files.getMtpObjectsUri(volumeName);
mMediaScanner = new MediaScanner(context);
openDevicePropertiesDatabase(context);
@@ -112,6 +114,16 @@ public class MtpDatabase {
}
}
+ private String externalToMediaPath(String path) {
+ // convert external storage path to media path
+ if (path != null && mMediaStoragePath != null
+ && mExternalStoragePath != null
+ && path.startsWith(mExternalStoragePath)) {
+ path = mMediaStoragePath + path.substring(mExternalStoragePath.length());
+ }
+ return path;
+ }
+
private void openDevicePropertiesDatabase(Context context) {
mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
int version = mDevicePropDb.getVersion();
@@ -482,7 +494,7 @@ public class MtpDatabase {
try {
c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null);
if (c != null && c.moveToNext()) {
- path = c.getString(1);
+ path = externalToMediaPath(c.getString(1));
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in getObjectFilePath", e);
@@ -763,7 +775,7 @@ public class MtpDatabase {
return true;
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getObjectProperty", e);
+ Log.e(TAG, "RemoteException in getObjectInfo", e);
} finally {
if (c != null) {
c.close();
@@ -786,7 +798,7 @@ public class MtpDatabase {
c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null);
if (c != null && c.moveToNext()) {
- String path = c.getString(1);
+ String path = externalToMediaPath(c.getString(1));
path.getChars(0, path.length(), outFilePath, 0);
outFilePath[path.length()] = 0;
outFileLength[0] = c.getLong(2);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 0d8abe2..9e1b436 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1710,16 +1710,11 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
return err;
}
- // Check that the color format is in the correct range.
- CHECK(OMX_COLOR_FormatAndroidPrivateStart <= def.format.video.eColorFormat);
- CHECK(def.format.video.eColorFormat < OMX_COLOR_FormatAndroidPrivateEnd);
-
err = native_window_set_buffers_geometry(
mNativeWindow.get(),
def.format.video.nFrameWidth,
def.format.video.nFrameHeight,
- def.format.video.eColorFormat
- - OMX_COLOR_FormatAndroidPrivateStart);
+ def.format.video.eColorFormat);
if (err != 0) {
LOGE("native_window_set_buffers_geometry failed: %s (%d)",
@@ -2109,6 +2104,17 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
CODEC_LOGV(
"output crop (%ld, %ld, %ld, %ld)",
rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
+
+ if (mNativeWindow != NULL) {
+ android_native_rect_t crop;
+ crop.left = rect.nLeft;
+ crop.top = rect.nTop;
+ crop.right = crop.left + rect.nWidth - 1;
+ crop.bottom = crop.top + rect.nHeight - 1;
+
+ CHECK_EQ(0, native_window_set_crop(
+ mNativeWindow.get(), &crop));
+ }
} else {
CODEC_LOGE("getConfig(OMX_IndexConfigCommonOutputCrop) "
"returned error 0x%08x", err);
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 1629e9f..6c05e03 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -39,7 +39,7 @@ static bool FileHasAcceptableExtension(const char *extension) {
".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
- ".mkv", ".mka", ".webm", ".ts"
+ ".mkv", ".mka", ".webm", ".ts", ".fl"
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index 91dc2b2..0f1aa4e 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -145,7 +145,7 @@ public abstract class KeyguardViewBase extends FrameLayout {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- /* Suppress PLAYPAUSE toggle when phone is ringing or
+ /* Suppress PLAY/PAUSE toggle when phone is ringing or
* in-call to avoid music playback */
if (mTelephonyManager == null) {
mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -155,11 +155,13 @@ public abstract class KeyguardViewBase extends FrameLayout {
mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
return true; // suppress key event
}
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -191,12 +193,15 @@ public abstract class KeyguardViewBase extends FrameLayout {
} else if (event.getAction() == KeyEvent.ACTION_UP) {
switch (keyCode) {
case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index c034ec9..c870503 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -795,6 +795,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_CAMERA:
return false;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 1383354..4644a7c 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -209,7 +209,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label
: R.string.lockscreen_sound_off_label);
}
- mCallback.pokeWakelock();
+ // Don't poke the wake lock when returning to a state where the handle is
+ // not grabbed since that can happen when the system (instead of the user)
+ // cancels the grab.
+ if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) {
+ mCallback.pokeWakelock();
+ }
}
}
@@ -231,10 +236,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
/** {@inheritDoc} */
public void onGrabbedStateChange(View v, int grabbedState) {
+ // Don't poke the wake lock when returning to a state where the handle is
+ // not grabbed since that can happen when the system (instead of the user)
+ // cancels the grab.
if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) {
mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
- } else {
- mCallback.pokeWakelock();
}
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 3691d97..e944f9d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -627,13 +627,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// should be executed... do it!
mPanelChordingKey = 0;
mPanelMayLongPress = false;
- InputMethodManager imm = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- if (imm != null) {
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
- }
-
}
return false;
@@ -1259,7 +1252,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- /* Suppress PLAYPAUSE toggle when phone is ringing or in-call
+ /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
* to avoid music playback */
if (mTelephonyManager == null) {
mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -1275,6 +1268,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -1455,6 +1449,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -1462,6 +1457,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7f49da9..e950ae5 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -54,6 +54,7 @@ import com.android.internal.telephony.ITelephony;
import com.android.internal.view.BaseInputHandler;
import com.android.internal.widget.PointerLocationView;
+import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
@@ -63,6 +64,7 @@ import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
import android.view.InputChannel;
+import android.view.InputDevice;
import android.view.InputQueue;
import android.view.InputHandler;
import android.view.KeyEvent;
@@ -217,7 +219,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mKeyguard = null;
KeyguardViewMediator mKeyguardMediator;
GlobalActions mGlobalActions;
- boolean mShouldTurnOffOnKeyUp;
+ volatile boolean mPowerKeyHandled;
RecentApplicationsDialog mRecentAppsDialog;
Handler mHandler;
@@ -477,28 +479,47 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- Runnable mPowerLongPress = new Runnable() {
+ private void interceptPowerKeyDown(boolean handled) {
+ mPowerKeyHandled = handled;
+ if (!handled) {
+ mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+ }
+ }
+
+ private boolean interceptPowerKeyUp(boolean canceled) {
+ if (!mPowerKeyHandled) {
+ mHandler.removeCallbacks(mPowerLongPress);
+ return !canceled;
+ } else {
+ mPowerKeyHandled = true;
+ return false;
+ }
+ }
+
+ private final Runnable mPowerLongPress = new Runnable() {
public void run() {
- // The context isn't read
- if (mLongPressOnPowerBehavior < 0) {
- mLongPressOnPowerBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior);
- }
- switch (mLongPressOnPowerBehavior) {
- case LONG_PRESS_POWER_NOTHING:
- break;
- case LONG_PRESS_POWER_GLOBAL_ACTIONS:
- mShouldTurnOffOnKeyUp = false;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
- break;
- case LONG_PRESS_POWER_SHUT_OFF:
- mShouldTurnOffOnKeyUp = false;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- ShutdownThread.shutdown(mContext, true);
- break;
+ if (!mPowerKeyHandled) {
+ // The context isn't read
+ if (mLongPressOnPowerBehavior < 0) {
+ mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnPowerBehavior);
+ }
+ switch (mLongPressOnPowerBehavior) {
+ case LONG_PRESS_POWER_NOTHING:
+ break;
+ case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+ mPowerKeyHandled = true;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+ showGlobalActionsDialog();
+ break;
+ case LONG_PRESS_POWER_SHUT_OFF:
+ mPowerKeyHandled = true;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+ ShutdownThread.shutdown(mContext, true);
+ break;
+ }
}
}
};
@@ -1111,12 +1132,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.anim.lock_screen_behind_enter);
}
- static ITelephony getPhoneInterface() {
- return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+ static ITelephony getTelephonyService() {
+ ITelephony telephonyService = ITelephony.Stub.asInterface(
+ ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+ if (telephonyService == null) {
+ Log.w(TAG, "Unable to find ITelephony interface.");
+ }
+ return telephonyService;
}
- static IAudioService getAudioInterface() {
- return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
+ static IAudioService getAudioService() {
+ IAudioService audioService = IAudioService.Stub.asInterface(
+ ServiceManager.checkService(Context.AUDIO_SERVICE));
+ if (audioService == null) {
+ Log.w(TAG, "Unable to find IAudioService interface.");
+ }
+ return audioService;
}
boolean keyguardOn() {
@@ -1131,7 +1162,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
- int keyCode, int metaState, int repeatCount, int policyFlags) {
+ int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
final boolean keyguardOn = keyguardOn();
final boolean down = (action == KeyEvent.ACTION_DOWN);
final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@@ -1164,11 +1195,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// and his ONLY options are to answer or reject the call.)
boolean incomingRinging = false;
try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- incomingRinging = phoneServ.isRinging();
- } else {
- Log.w(TAG, "Unable to find ITelephony interface");
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ incomingRinging = telephonyService.isRinging();
}
} catch (RemoteException ex) {
Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
@@ -1824,23 +1853,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
- * @return Whether a telephone call is in progress right now.
- */
- boolean isInCall() {
- final ITelephony phone = getPhoneInterface();
- if (phone == null) {
- Log.w(TAG, "couldn't get ITelephony reference");
- return false;
- }
- try {
- return phone.isOffhook();
- } catch (RemoteException e) {
- Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
- return false;
- }
- }
-
- /**
* @return Whether music is being played right now.
*/
boolean isMusicActive() {
@@ -1857,9 +1869,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @param keycode
*/
void handleVolumeKey(int stream, int keycode) {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
+ IAudioService audioService = getAudioService();
+ if (audioService == null) {
return;
}
try {
@@ -1867,7 +1878,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// during the call, but we do it as a precaution for the rare possibility
// that the music stops right before we call this
mBroadcastWakeLock.acquire();
- audio.adjustStreamVolume(stream,
+ audioService.adjustStreamVolume(stream,
keycode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER,
@@ -1878,41 +1889,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBroadcastWakeLock.release();
}
}
-
- static boolean isMediaKey(int code) {
- if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
- code == KeyEvent.KEYCODE_MEDIA_PLAY ||
- code == KeyEvent.KEYCODE_MEDIA_PAUSE ||
- code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
- code == KeyEvent.KEYCODE_MEDIA_STOP ||
- code == KeyEvent.KEYCODE_MEDIA_NEXT ||
- code == KeyEvent.KEYCODE_MEDIA_PREVIOUS ||
- code == KeyEvent.KEYCODE_MEDIA_REWIND ||
- code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
- return true;
- }
- return false;
- }
-
+
/** {@inheritDoc} */
@Override
- public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
- int policyFlags, boolean isScreenOn) {
- int result = ACTION_PASS_TO_USER;
+ public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+ int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+ final boolean down = action == KeyEvent.ACTION_DOWN;
+ final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;
- if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
- }
-
- final boolean isWakeKey = (policyFlags
- & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-
- // If the key is injected, pretend that the screen is on and don't let the
- // device go to sleep. This feature is mainly used for testing purposes.
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
- if (isInjected) {
- isScreenOn = true;
- }
// If screen is off then we treat the case where the keyguard is open but hidden
// the same as if it were open and in front.
@@ -1927,202 +1912,210 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
}
- if (keyguardActive) {
- if (isScreenOn) {
- // when the screen is on, always give the event to the keyguard
- result |= ACTION_PASS_TO_USER;
- } else {
- // otherwise, don't pass it to the user
- result &= ~ACTION_PASS_TO_USER;
+ if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
- if (isWakeKey && down) {
-
- // tell the mediator about a wake key, it may decide to
- // turn on the screen depending on whether the key is
- // appropriate.
- if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
- && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
- // when keyguard is showing and screen off, we need
- // to handle the volume key for calls and music here
- if (isInCall()) {
- handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
- } else if (isMusicActive()) {
- handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+ // Basic policy based on screen state and keyguard.
+ // FIXME: This policy isn't quite correct. We shouldn't care whether the screen
+ // is on or off, really. We should care about whether the device is in an
+ // interactive state or is in suspend pretending to be "off".
+ // The primary screen might be turned off due to proximity sensor or
+ // because we are presenting media on an auxiliary screen or remotely controlling
+ // the device some other way (which is why we have an exemption here for injected
+ // events).
+ int result;
+ if (isScreenOn || isInjected) {
+ // When the screen is on or if the key is injected pass the key to the application.
+ result = ACTION_PASS_TO_USER;
+ } else {
+ // When the screen is off and the key is not injected, determine whether
+ // to wake the device but don't pass the key to the application.
+ result = 0;
+
+ final boolean isWakeKey = (policyFlags
+ & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+ if (down && isWakeKey) {
+ if (keyguardActive) {
+ // If the keyguard is showing, let it decide what to do with the wake key.
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
+ } else {
+ // Otherwise, wake the device ourselves.
+ result |= ACTION_POKE_USER_ACTIVITY;
+ }
+ }
+ }
+
+ // Handle special keys.
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_UP: {
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ try {
+ if (telephonyService.isRinging()) {
+ // If an incoming call is ringing, either VOLUME key means
+ // "silence ringer". We handle these keys here, rather than
+ // in the InCallScreen, to make sure we'll respond to them
+ // even if the InCallScreen hasn't come to the foreground yet.
+ // Look for the DOWN event here, to agree with the "fallback"
+ // behavior in the InCallScreen.
+ Log.i(TAG, "interceptKeyBeforeQueueing:"
+ + " VOLUME key-down while ringing: Silence ringer!");
+
+ // Silence the ringer. (It's safe to call this
+ // even if the ringer has already been silenced.)
+ telephonyService.silenceRinger();
+
+ // And *don't* pass this key thru to the current activity
+ // (which is probably the InCallScreen.)
+ result &= ~ACTION_PASS_TO_USER;
+ break;
+ }
+ if (telephonyService.isOffhook()
+ && (result & ACTION_PASS_TO_USER) == 0) {
+ // If we are in call but we decided not to pass the key to
+ // the application, handle the volume change here.
+ handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
+ break;
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
+
+ if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
+ // If music is playing but we decided not to pass the key to the
+ // application, handle the volume change here.
+ handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+ break;
+ }
}
+ break;
}
- } else if (!isScreenOn) {
- // If we are in-call with screen off and keyguard is not showing,
- // then handle the volume key ourselves.
- // This is necessary because the phone app will disable the keyguard
- // when the proximity sensor is in use.
- if (isInCall() &&
- (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
- result &= ~ACTION_PASS_TO_USER;
- handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
- }
- if (isWakeKey) {
- // a wake key has a sole purpose of waking the device; don't pass
- // it to the user
- result |= ACTION_POKE_USER_ACTIVITY;
+
+ case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ boolean hungUp = false;
+ if (telephonyService != null) {
+ try {
+ hungUp = telephonyService.endCall();
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
+ }
+ }
+ interceptPowerKeyDown(!isScreenOn || hungUp);
+ } else {
+ if (interceptPowerKeyUp(canceled)) {
+ if ((mEndcallBehavior
+ & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
+ if (goHome()) {
+ break;
+ }
+ }
+ if ((mEndcallBehavior
+ & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+ result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
+ }
+ }
+ }
+ break;
}
- }
- if (keyCode == KeyEvent.KEYCODE_ENDCALL
- || keyCode == KeyEvent.KEYCODE_POWER) {
- if (down) {
- boolean handled = false;
- boolean hungUp = false;
- // key repeats are generated by the window manager, and we don't see them
- // here, so unless the driver is doing something it shouldn't be, we know
- // this is the real press event.
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- try {
- if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
- handled = hungUp = phoneServ.endCall();
- } else if (keyCode == KeyEvent.KEYCODE_POWER) {
- if (phoneServ.isRinging()) {
+ case KeyEvent.KEYCODE_POWER: {
+ result &= ~ACTION_PASS_TO_USER;
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ boolean hungUp = false;
+ if (telephonyService != null) {
+ try {
+ if (telephonyService.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
- phoneServ.silenceRinger();
- handled = true;
- } else if (phoneServ.isOffhook() &&
- ((mIncallPowerBehavior
- & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
- != 0)) {
+ telephonyService.silenceRinger();
+ } else if ((mIncallPowerBehavior
+ & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+ && telephonyService.isOffhook()) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
- handled = hungUp = phoneServ.endCall();
+ hungUp = telephonyService.endCall();
}
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
}
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony threw RemoteException" + ex);
}
+ interceptPowerKeyDown(!isScreenOn || hungUp);
} else {
- Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
- }
-
- if (!isScreenOn
- || (handled && keyCode != KeyEvent.KEYCODE_POWER)
- || (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
- mShouldTurnOffOnKeyUp = false;
- } else {
- // Only try to turn off the screen if we didn't already hang up.
- mShouldTurnOffOnKeyUp = true;
- mHandler.postDelayed(mPowerLongPress,
- ViewConfiguration.getGlobalActionKeyTimeout());
- result &= ~ACTION_PASS_TO_USER;
- }
- } else {
- mHandler.removeCallbacks(mPowerLongPress);
- if (mShouldTurnOffOnKeyUp) {
- mShouldTurnOffOnKeyUp = false;
- boolean gohome, sleeps;
- if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
- gohome = (mEndcallBehavior
- & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
- sleeps = (mEndcallBehavior
- & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
- } else {
- gohome = false;
- sleeps = true;
- }
- if (keyguardActive
- || (sleeps && !gohome)
- || (gohome && !goHome() && sleeps)) {
- // They must already be on the keyguard or home screen,
- // go to sleep instead unless the event was injected.
- if (!isInjected) {
- Log.d(TAG, "I'm tired mEndcallBehavior=0x"
- + Integer.toHexString(mEndcallBehavior));
- result &= ~ACTION_POKE_USER_ACTIVITY;
- result |= ACTION_GO_TO_SLEEP;
- }
+ if (interceptPowerKeyUp(canceled)) {
+ result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
}
- result &= ~ACTION_PASS_TO_USER;
}
+ break;
}
- } else if (isMediaKey(keyCode)) {
- // This key needs to be handled even if the screen is off.
- // If others need to be handled while it's off, this is a reasonable
- // pattern to follow.
- if ((result & ACTION_PASS_TO_USER) == 0) {
- // Only do this if we would otherwise not pass it to the user. In that
- // case, the PhoneWindow class will do the same thing, except it will
- // only do it if the showing app doesn't process the key on its own.
- long when = whenNanos / 1000000;
- KeyEvent keyEvent = new KeyEvent(when, when,
- down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
- keyCode, 0);
- mBroadcastWakeLock.acquire();
- mHandler.post(new PassHeadsetKey(keyEvent));
- }
- } else if (keyCode == KeyEvent.KEYCODE_CALL) {
- // If an incoming call is ringing, answer it!
- // (We handle this key here, rather than in the InCallScreen, to make
- // sure we'll respond to the key even if the InCallScreen hasn't come to
- // the foreground yet.)
-
- // We answer the call on the DOWN event, to agree with
- // the "fallback" behavior in the InCallScreen.
- if (down) {
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- if (phoneServ.isRinging()) {
- Log.i(TAG, "interceptKeyTq:"
- + " CALL key-down while ringing: Answer the call!");
- phoneServ.answerRingingCall();
-
- // And *don't* pass this key thru to the current activity
- // (which is presumably the InCallScreen.)
- result &= ~ACTION_PASS_TO_USER;
+
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ try {
+ if (!telephonyService.isIdle()) {
+ // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+ // to avoid music playback.
+ break;
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
}
- } else {
- Log.w(TAG, "CALL button: Unable to find ITelephony interface");
}
- } catch (RemoteException ex) {
- Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
}
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+ if ((result & ACTION_PASS_TO_USER) == 0) {
+ // Only do this if we would otherwise not pass it to the user. In that
+ // case, the PhoneWindow class will do the same thing, except it will
+ // only do it if the showing app doesn't process the key on its own.
+ long when = whenNanos / 1000000;
+ KeyEvent keyEvent = new KeyEvent(when, when, action, keyCode, 0, 0,
+ 0, scanCode, flags, InputDevice.SOURCE_KEYBOARD);
+ mBroadcastWakeLock.acquire();
+ mHandler.post(new PassHeadsetKey(keyEvent));
+ }
+ break;
}
- } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
- || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
- // If an incoming call is ringing, either VOLUME key means
- // "silence ringer". We handle these keys here, rather than
- // in the InCallScreen, to make sure we'll respond to them
- // even if the InCallScreen hasn't come to the foreground yet.
-
- // Look for the DOWN event here, to agree with the "fallback"
- // behavior in the InCallScreen.
- if (down) {
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- if (phoneServ.isRinging()) {
- Log.i(TAG, "interceptKeyTq:"
- + " VOLUME key-down while ringing: Silence ringer!");
- // Silence the ringer. (It's safe to call this
- // even if the ringer has already been silenced.)
- phoneServ.silenceRinger();
-
- // And *don't* pass this key thru to the current activity
- // (which is probably the InCallScreen.)
- result &= ~ACTION_PASS_TO_USER;
+
+ case KeyEvent.KEYCODE_CALL: {
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ try {
+ if (telephonyService.isRinging()) {
+ Log.i(TAG, "interceptKeyBeforeQueueing:"
+ + " CALL key-down while ringing: Answer the call!");
+ telephonyService.answerRingingCall();
+
+ // And *don't* pass this key thru to the current activity
+ // (which is presumably the InCallScreen.)
+ result &= ~ACTION_PASS_TO_USER;
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
}
- } else {
- Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
}
- } catch (RemoteException ex) {
- Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
}
+ break;
}
}
-
return result;
}
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 65d9ef7..86d4c9f 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -356,7 +356,9 @@ void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSyst
break;
case AudioSystem::FOR_MEDIA:
if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
- config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE) {
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE) {
LOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
return;
}
@@ -372,7 +374,10 @@ void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSyst
break;
case AudioSystem::FOR_DOCK:
if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
- config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) {
+ config != AudioSystem::FORCE_BT_DESK_DOCK &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
LOGW("setForceUse() invalid config %d for FOR_DOCK", config);
}
forceVolumeReeval = true;
@@ -1366,6 +1371,7 @@ status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devi
void AudioPolicyManagerBase::closeA2dpOutputs()
{
+
LOGV("setDeviceConnectionState() closing A2DP and duplicated output!");
if (mDuplicatedOutput != 0) {
@@ -1558,6 +1564,8 @@ uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
if (device) break;
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
#ifdef WITH_A2DP
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (mPhoneState != AudioSystem::MODE_IN_CALL) {
@@ -1617,6 +1625,12 @@ uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
}
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
#ifdef WITH_A2DP
if (mA2dpOutput != 0) {
if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
@@ -1797,7 +1811,9 @@ float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_hand
(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AudioSystem::DEVICE_OUT_WIRED_HEADSET |
- AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+ AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
+ AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) &&
(getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) &&
streamDesc.mCanBeMuted) {
volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index bee8872..f993093 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -103,7 +103,6 @@ class DockObserver extends UEventObserver {
FileReader file = new FileReader(DOCK_STATE_PATH);
int len = file.read(buffer, 0, 1024);
mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
} catch (FileNotFoundException e) {
Slog.w(TAG, "This kernel does not have dock station support");
} catch (Exception e) {
@@ -158,13 +157,17 @@ class DockObserver extends UEventObserver {
{
String whichSound = null;
if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+ (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+ (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
whichSound = Settings.System.DESK_UNDOCK_SOUND;
} else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
whichSound = Settings.System.CAR_UNDOCK_SOUND;
}
} else {
- if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+ (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+ (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
whichSound = Settings.System.DESK_DOCK_SOUND;
} else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
whichSound = Settings.System.CAR_DOCK_SOUND;
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
deleted file mode 100644
index 6f0a91d..0000000
--- a/services/java/com/android/server/HeadsetObserver.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.ActivityManagerNative;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.UEventObserver;
-import android.util.Slog;
-import android.media.AudioManager;
-
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-
-/**
- * <p>HeadsetObserver monitors for a wired headset.
- */
-class HeadsetObserver extends UEventObserver {
- private static final String TAG = HeadsetObserver.class.getSimpleName();
- private static final boolean LOG = true;
-
- private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w";
- private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
- private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
-
- private static final int BIT_HEADSET = (1 << 0);
- private static final int BIT_HEADSET_NO_MIC = (1 << 1);
- private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC);
- private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
-
- private int mHeadsetState;
- private int mPrevHeadsetState;
- private String mHeadsetName;
-
- private final Context mContext;
- private final WakeLock mWakeLock; // held while there is a pending route change
-
- public HeadsetObserver(Context context) {
- mContext = context;
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetObserver");
- mWakeLock.setReferenceCounted(false);
-
- startObserving(HEADSET_UEVENT_MATCH);
-
- init(); // set initial status
- }
-
- @Override
- public void onUEvent(UEventObserver.UEvent event) {
- if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
-
- try {
- update(event.get("SWITCH_NAME"), Integer.parseInt(event.get("SWITCH_STATE")));
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Could not parse switch state from event " + event);
- }
- }
-
- private synchronized final void init() {
- char[] buffer = new char[1024];
-
- String newName = mHeadsetName;
- int newState = mHeadsetState;
- mPrevHeadsetState = mHeadsetState;
- try {
- FileReader file = new FileReader(HEADSET_STATE_PATH);
- int len = file.read(buffer, 0, 1024);
- newState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
- file = new FileReader(HEADSET_NAME_PATH);
- len = file.read(buffer, 0, 1024);
- newName = new String(buffer, 0, len).trim();
-
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "This kernel does not have wired headset support");
- } catch (Exception e) {
- Slog.e(TAG, "" , e);
- }
-
- update(newName, newState);
- }
-
- private synchronized final void update(String newName, int newState) {
- // Retain only relevant bits
- int headsetState = newState & SUPPORTED_HEADSETS;
- int newOrOld = headsetState | mHeadsetState;
- int delay = 0;
- // reject all suspect transitions: only accept state changes from:
- // - a: 0 heaset to 1 headset
- // - b: 1 headset to 0 headset
- if (mHeadsetState == headsetState || ((newOrOld & (newOrOld - 1)) != 0)) {
- return;
- }
-
- mHeadsetName = newName;
- mPrevHeadsetState = mHeadsetState;
- mHeadsetState = headsetState;
-
- if (headsetState == 0) {
- Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
- // It can take hundreds of ms flush the audio pipeline after
- // apps pause audio playback, but audio route changes are
- // immediate, so delay the route change by 1000ms.
- // This could be improved once the audio sub-system provides an
- // interface to clear the audio pipeline.
- delay = 1000;
- } else {
- // Insert the same delay for headset connection so that the connection event is not
- // broadcast before the disconnection event in case of fast removal/insertion
- if (mHandler.hasMessages(0)) {
- delay = 1000;
- }
- }
- mWakeLock.acquire();
- mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
- mHeadsetState,
- mPrevHeadsetState,
- mHeadsetName),
- delay);
- }
-
- private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
- int allHeadsets = SUPPORTED_HEADSETS;
- for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
- if ((curHeadset & allHeadsets) != 0) {
- sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
- allHeadsets &= ~curHeadset;
- }
- }
- }
-
- private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
- if ((headsetState & headset) != (prevHeadsetState & headset)) {
- // Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- int state = 0;
- int microphone = 0;
-
- if ((headset & HEADSETS_WITH_MIC) != 0) {
- microphone = 1;
- }
- if ((headsetState & headset) != 0) {
- state = 1;
- }
- intent.putExtra("state", state);
- intent.putExtra("name", headsetName);
- intent.putExtra("microphone", microphone);
-
- if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
- // TODO: Should we require a permission?
- ActivityManagerNative.broadcastStickyIntent(intent, null);
- }
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
- mWakeLock.release();
- }
- };
-}
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index cb4071a..e7eb129 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -404,17 +404,18 @@ public class InputManager {
}
@SuppressWarnings("unused")
- public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
- int policyFlags, boolean isScreenOn) {
+ public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+ int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
- whenNanos, keyCode, down, policyFlags, isScreenOn);
+ whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
}
@SuppressWarnings("unused")
public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
- int flags, int keyCode, int metaState, int repeatCount, int policyFlags) {
+ int flags, int keyCode, int scanCode, int metaState, int repeatCount,
+ int policyFlags) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
- action, flags, keyCode, metaState, repeatCount, policyFlags);
+ action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
}
@SuppressWarnings("unused")
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 07da0fa..20e8bbe 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1881,11 +1881,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
String id = pair.first;
ArrayList<String> subtypes = pair.second;
builder.append(id);
- if (subtypes.size() > 0) {
- builder.append(subtypes.get(0));
- for (int i = 1; i < subtypes.size(); ++i) {
- builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypes.get(i));
- }
+ // Inputmethod and subtypes are saved in the settings as follows:
+ // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1
+ for (String subtypeId: subtypes) {
+ builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 237ab80..54f7441 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -121,7 +121,7 @@ class ServerThread extends Thread {
WindowManagerService wm = null;
BluetoothService bluetooth = null;
BluetoothA2dpService bluetoothA2dp = null;
- HeadsetObserver headset = null;
+ WiredAccessoryObserver wiredAccessory = null;
DockObserver dock = null;
UsbObserver usb = null;
UiModeManagerService uiMode = null;
@@ -388,14 +388,6 @@ class ServerThread extends Thread {
}
try {
- Slog.i(TAG, "Headset Observer");
- // Listen for wired headset changes
- headset = new HeadsetObserver(context);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting HeadsetObserver", e);
- }
-
- try {
Slog.i(TAG, "Dock Observer");
// Listen for dock station changes
dock = new DockObserver(context, power);
@@ -404,6 +396,14 @@ class ServerThread extends Thread {
}
try {
+ Slog.i(TAG, "Wired Accessory Observer");
+ // Listen for wired headset changes
+ wiredAccessory = new WiredAccessoryObserver(context);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting WiredAccessoryObserver", e);
+ }
+
+ try {
Slog.i(TAG, "USB Observer");
// Listen for USB changes
usb = new UsbObserver(context);
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 747af26..a7a0c68 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -103,6 +103,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private int mDataConnectionNetworkType;
+ private int mOtaspMode;
+
static final int PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
PhoneStateListener.LISTEN_CALL_STATE |
@@ -225,6 +227,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+ try {
+ r.callback.onOtaspChanged(mOtaspMode);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -467,6 +476,25 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ public void notifyOtaspChanged(int otaspMode) {
+ if (!checkNotifyPermission("notifyOtaspChanged()" )) {
+ return;
+ }
+ synchronized (mRecords) {
+ mOtaspMode = otaspMode;
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+ try {
+ r.callback.onOtaspChanged(otaspMode);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index c29e4a9..55ebded 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5706,20 +5706,20 @@ public class WindowManagerService extends IWindowManager.Stub
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
- public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
- int policyFlags, boolean isScreenOn) {
- return mPolicy.interceptKeyBeforeQueueing(whenNanos,
- keyCode, down, policyFlags, isScreenOn);
+ public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+ int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+ return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
+ keyCode, scanCode, policyFlags, isScreenOn);
}
/* Provides an opportunity for the window manager policy to process a key before
* ordinary dispatch. */
public boolean interceptKeyBeforeDispatching(InputChannel focus,
- int action, int flags, int keyCode, int metaState, int repeatCount,
+ int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
int policyFlags) {
WindowState windowState = getWindowStateForInputChannel(focus);
return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
- keyCode, metaState, repeatCount, policyFlags);
+ keyCode, scanCode, metaState, repeatCount, policyFlags);
}
/* Called when the current input focus changes.
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
new file mode 100644
index 0000000..ab92fdf
--- /dev/null
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.UEventObserver;
+import android.util.Slog;
+import android.media.AudioManager;
+import android.util.Log;
+
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+
+/**
+ * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock.
+ */
+class WiredAccessoryObserver extends UEventObserver {
+ private static final String TAG = WiredAccessoryObserver.class.getSimpleName();
+ private static final boolean LOG = true;
+ private static final int MAX_AUDIO_PORTS = 2; /* h2w & USB Audio */
+ private static final String uEventInfo[][] = { {"DEVPATH=/devices/virtual/switch/h2w",
+ "/sys/class/switch/h2w/state",
+ "/sys/class/switch/h2w/name"},
+ {"DEVPATH=/devices/virtual/switch/usb_audio",
+ "/sys/class/switch/usb_audio/state",
+ "/sys/class/switch/usb_audio/name"} };
+
+ private static final int BIT_HEADSET = (1 << 0);
+ private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int BIT_USB_HEADSET_ANLG = (1 << 2);
+ private static final int BIT_USB_HEADSET_DGTL = (1 << 3);
+ private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+ BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL);
+ private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
+
+ private int mHeadsetState;
+ private int mPrevHeadsetState;
+ private String mHeadsetName;
+ private int switchState;
+
+ private final Context mContext;
+ private final WakeLock mWakeLock; // held while there is a pending route change
+
+ public WiredAccessoryObserver(Context context) {
+ mContext = context;
+ PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver");
+ mWakeLock.setReferenceCounted(false);
+
+ // At any given time both headsets could be inserted
+ // one on the board and one on the dock
+ // observe two UEVENTs
+ for (int i = 0; i <= MAX_AUDIO_PORTS; i++) {
+ startObserving(uEventInfo[i][0]);
+ }
+ init(); // set initial status
+ }
+
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
+
+ try {
+ if ((event.get("SWITCH_NAME")).equals("usb_audio")) {
+ if (Integer.parseInt(event.get("SWITCH_STATE")) == 1) {
+ switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+ BIT_USB_HEADSET_DGTL)) |
+ (Integer.parseInt(event.get("SWITCH_STATE")) << 2));
+ } else if (Integer.parseInt(event.get("SWITCH_STATE")) == 2) {
+ switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+ BIT_USB_HEADSET_ANLG)) |
+ (Integer.parseInt(event.get("SWITCH_STATE")) << 3));
+ }
+ else switchState = (mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC));
+ }
+ else {
+ switchState = ((mHeadsetState & (BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL)) |
+ (Integer.parseInt(event.get("SWITCH_STATE"))));
+ }
+ update(event.get("SWITCH_NAME"), switchState);
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Could not parse switch state from event " + event);
+ }
+ }
+
+ private synchronized final void init() {
+ char[] buffer = new char[1024];
+
+ String newName = mHeadsetName;
+ int newState = mHeadsetState;
+ mPrevHeadsetState = mHeadsetState;
+
+ for (int i = 0; i <= MAX_AUDIO_PORTS; i++) {
+ try {
+ FileReader file = new FileReader(uEventInfo[i][1]);
+ int len = file.read(buffer, 0, 1024);
+ newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+ file = new FileReader(uEventInfo[i][2]);
+ len = file.read(buffer, 0, 1024);
+ newName = new String(buffer, 0, len).trim();
+
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "This kernel does not have wired headset support");
+ } catch (Exception e) {
+ Slog.e(TAG, "" , e);
+ }
+
+ update(newName, newState);
+ }
+ }
+
+ private synchronized final void update(String newName, int newState) {
+ // Retain only relevant bits
+ int headsetState = newState & SUPPORTED_HEADSETS;
+ int newOrOld = headsetState | mHeadsetState;
+ int delay = 0;
+ int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
+ int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
+ int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC);
+ boolean h2wStateChange = true;
+ boolean usbStateChange = true;
+ // reject all suspect transitions: only accept state changes from:
+ // - a: 0 heaset to 1 headset
+ // - b: 1 headset to 0 headset
+ Log.v(TAG, "newState = "+newState+", headsetState = "+headsetState+", mHeadsetState = "+mHeadsetState);
+ if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) {
+ Log.e(TAG, "unsetting h2w flag");
+ h2wStateChange = false;
+ }
+ // - c: 0 usb headset to 1 usb headset
+ // - d: 1 usb headset to 0 usb headset
+ if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) {
+ Log.e(TAG, "unsetting usb flag");
+ usbStateChange = false;
+ }
+ if (!h2wStateChange && !usbStateChange) {
+ Log.e(TAG, "invalid transition, returning ...");
+ return;
+ }
+
+ mHeadsetName = newName;
+ mPrevHeadsetState = mHeadsetState;
+ mHeadsetState = headsetState;
+
+ if (headsetState == 0) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ // It can take hundreds of ms flush the audio pipeline after
+ // apps pause audio playback, but audio route changes are
+ // immediate, so delay the route change by 1000ms.
+ // This could be improved once the audio sub-system provides an
+ // interface to clear the audio pipeline.
+ delay = 1000;
+ } else {
+ // Insert the same delay for headset connection so that the connection event is not
+ // broadcast before the disconnection event in case of fast removal/insertion
+ if (mHandler.hasMessages(0)) {
+ delay = 1000;
+ }
+ }
+ mWakeLock.acquire();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
+ mHeadsetState,
+ mPrevHeadsetState,
+ mHeadsetName),
+ delay);
+ }
+
+ private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
+ int allHeadsets = SUPPORTED_HEADSETS;
+ for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
+ if ((curHeadset & allHeadsets) != 0) {
+ sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
+ allHeadsets &= ~curHeadset;
+ }
+ }
+ }
+
+ private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
+ if ((headsetState & headset) != (prevHeadsetState & headset)) {
+
+ int state = 0;
+ if ((headsetState & headset) != 0) {
+ state = 1;
+ }
+ if((headset == BIT_USB_HEADSET_ANLG) || (headset == BIT_USB_HEADSET_DGTL)) {
+ Intent intent;
+
+ // Pack up the values and broadcast them to everyone
+ if (headset == BIT_USB_HEADSET_ANLG) {
+ intent = new Intent(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra("state", state);
+ intent.putExtra("name", headsetName);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ } else if (headset == BIT_USB_HEADSET_DGTL) {
+ intent = new Intent(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra("state", state);
+ intent.putExtra("name", headsetName);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ }
+
+ if (LOG) Slog.v(TAG, "Intent.ACTION_USB_HEADSET_PLUG: state: "+state+" name: "+headsetName);
+ // TODO: Should we require a permission?
+ }
+ if((headset == BIT_HEADSET) || (headset == BIT_HEADSET_NO_MIC)) {
+
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ //int state = 0;
+ int microphone = 0;
+
+ if ((headset & HEADSETS_WITH_MIC) != 0) {
+ microphone = 1;
+ }
+
+ intent.putExtra("state", state);
+ intent.putExtra("name", headsetName);
+ intent.putExtra("microphone", microphone);
+
+ if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
+ // TODO: Should we require a permission?
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ }
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
+ mWakeLock.release();
+ }
+ };
+}
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 599163b..d4c4ba4 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -857,7 +857,7 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mCallbacksObj,
gCallbacksClassInfo.interceptKeyBeforeQueueing,
- when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn);
+ when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
@@ -926,7 +926,7 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i
jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
gCallbacksClassInfo.interceptKeyBeforeDispatching,
inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getMetaState(),
+ keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), policyFlags);
bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
@@ -1358,10 +1358,10 @@ int register_android_server_InputManager(JNIEnv* env) {
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
- "interceptKeyBeforeQueueing", "(JIZIZ)I");
+ "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
- "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z");
+ "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIIII)Z");
GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
"checkInjectEventsPermission", "(II)Z");
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 38f44d8..eda9b71 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -148,6 +148,14 @@ public class PhoneStateListener {
*/
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
+ /**
+ * Listen for changes to OTASP mode.
+ *
+ * @see #onOtaspChanged
+ * @hide
+ */
+ public static final int LISTEN_OTASP_CHANGED = 0x00000200;
+
public PhoneStateListener() {
}
@@ -252,6 +260,21 @@ public class PhoneStateListener {
// default implementation empty
}
+
+ /**
+ * The Over The Air Service Provisioning (OTASP) has changed. Requires
+ * the READ_PHONE_STATE permission.
+ * @param otaspMode is integer <code>OTASP_UNKNOWN=1<code>
+ * means the value is currently unknown and the system should wait until
+ * <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before
+ * making the decisision to perform OTASP or not.
+ *
+ * @hide
+ */
+ public void onOtaspChanged(int otaspMode) {
+ // default implementation empty
+ }
+
/**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
@@ -292,9 +315,14 @@ public class PhoneStateListener {
public void onDataActivity(int direction) {
Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget();
}
+
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget();
}
+
+ public void onOtaspChanged(int otaspMode) {
+ Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget();
+ }
};
Handler mHandler = new Handler() {
@@ -329,6 +357,9 @@ public class PhoneStateListener {
case LISTEN_SIGNAL_STRENGTHS:
PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
break;
+ case LISTEN_OTASP_CHANGED:
+ PhoneStateListener.this.onOtaspChanged(msg.arg1);
+ break;
}
}
};
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 6a163dd..14808b6 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -148,6 +148,14 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
}
}
+ public void notifyOtaspChanged(Phone sender, int otaspMode) {
+ try {
+ mRegistry.notifyOtaspChanged(otaspMode);
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
private void log(String s) {
Log.d(LOG_TAG, "[PhoneNotifier] " + s);
}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 856d663..082c097 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -32,5 +32,6 @@ oneway interface IPhoneStateListener {
void onDataConnectionStateChanged(int state, int networkType);
void onDataActivity(int direction);
void onSignalStrengthsChanged(in SignalStrength signalStrength);
+ void onOtaspChanged(in int otaspMode);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7a1587b..3c4bb12 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -66,7 +66,7 @@ interface ITelephony {
boolean showCallScreenWithDialpad(boolean showDialpad);
/**
- * End call or go to the Home screen
+ * End call if there is a call in progress, otherwise does nothing.
*
* @return whether it hung up
*/
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 6407a4e..3c83e50 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -38,4 +38,5 @@ interface ITelephonyRegistry {
in LinkCapabilities linkCapabilities, int networkType);
void notifyDataConnectionFailed(String reason, String apnType);
void notifyCellLocation(in Bundle cellLocation);
+ void notifyOtaspChanged(in int otaspMode);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 74e8c1b..554a7ba 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -750,6 +750,10 @@ public abstract class PhoneBase extends Handler implements Phone {
mNotifier.notifyDataConnection(this, reason, apnType);
}
+ public void notifyOtaspChanged(int otaspMode) {
+ mNotifier.notifyOtaspChanged(this, otaspMode);
+ }
+
public abstract String getPhoneName();
public abstract int getPhoneType();
diff --git a/telephony/java/com/android/internal/telephony/PhoneNotifier.java b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
index 691271f..b1cf953 100644
--- a/telephony/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
@@ -42,4 +42,5 @@ public interface PhoneNotifier {
public void notifyDataActivity(Phone sender);
+ public void notifyOtaspChanged(Phone sender, int otaspMode);
}
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index e8bbe5e..3f9ffc3 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -53,6 +53,12 @@ public abstract class ServiceStateTracker extends Handler {
public SignalStrength mSignalStrength;
+ /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
+ static public final int OTASP_UNINITIALIZED = 0;
+ static public final int OTASP_UNKNOWN = 1;
+ static public final int OTASP_NEEDED = 2;
+ static public final int OTASP_NOT_NEEDED = 3;
+
/**
* A unique identifier to track requests associated with a poll
* and ignore stale responses. The value is a count-down of
@@ -268,9 +274,11 @@ public abstract class ServiceStateTracker extends Handler {
public abstract void handleMessage(Message msg);
+ protected abstract Phone getPhone();
protected abstract void handlePollStateResult(int what, AsyncResult ar);
protected abstract void updateSpnDisplay();
protected abstract void setPowerStateToDesired();
+ protected abstract void log(String s);
/**
* Clean up existing voice and data connection then turn off radio power.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 6e53ec5..b9d5673 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -61,6 +61,7 @@ import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.PhoneNotifier;
import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.PhoneSubInfo;
+import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.UUSInfo;
@@ -83,10 +84,6 @@ public class CDMAPhone extends PhoneBase {
static final String LOG_TAG = "CDMA";
private static final boolean DBG = true;
- // Min values used to by needsActivation
- private static final String UNACTIVATED_MIN2_VALUE = "000000";
- private static final String UNACTIVATED_MIN_VALUE = "1111110111";
-
// Default Emergency Callback Mode exit timer
private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
@@ -1170,19 +1167,7 @@ public class CDMAPhone extends PhoneBase {
*/
@Override
public boolean needsOtaServiceProvisioning() {
- String cdmaMin = getCdmaMin();
- boolean needsProvisioning;
- if (cdmaMin == null || (cdmaMin.length() < 6)) {
- if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
- + cdmaMin + "' assume provisioning needed.");
- needsProvisioning = true;
- } else {
- needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
- || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
- || SystemProperties.getBoolean("test_cdma_setup", false);
- }
- if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
- return needsProvisioning;
+ return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
}
private static final String IS683A_FEATURE_CODE = "*228";
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 3669e60..325c2e1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -354,6 +354,24 @@ public final class CdmaCallTracker extends CallTracker {
|| (foregroundCall.getState() == CdmaCall.State.ACTIVE)
|| !backgroundCall.getState().isAlive());
+ if (!ret) {
+ log(String.format("canDial is false\n" +
+ "((serviceState=%d) != ServiceState.STATE_POWER_OFF)::=%s\n" +
+ "&& pendingMO == null::=%s\n" +
+ "&& !ringingCall.isRinging()::=%s\n" +
+ "&& !disableCall.equals(\"true\")::=%s\n" +
+ "&& (!foregroundCall.getState().isAlive()::=%s\n" +
+ " || foregroundCall.getState() == CdmaCall.State.ACTIVE::=%s\n" +
+ " ||!backgroundCall.getState().isAlive())::=%s)",
+ serviceState,
+ serviceState != ServiceState.STATE_POWER_OFF,
+ pendingMO == null,
+ !ringingCall.isRinging(),
+ !disableCall.equals("true"),
+ !foregroundCall.getState().isAlive(),
+ foregroundCall.getState() == CdmaCall.State.ACTIVE,
+ !backgroundCall.getState().isAlive()));
+ }
return ret;
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 7d2013b..11e04d4 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -22,6 +22,7 @@ import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
@@ -65,6 +66,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
CdmaCellLocation cellLoc;
CdmaCellLocation newCellLoc;
+ // Min values used to by getOtasp()
+ private static final String UNACTIVATED_MIN2_VALUE = "000000";
+ private static final String UNACTIVATED_MIN_VALUE = "1111110111";
+
+ // Current Otasp value
+ int mCurrentOtaspMode = OTASP_UNINITIALIZED;
+
/** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
@@ -446,6 +454,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
if (!mIsMinInfoReady) {
mIsMinInfoReady = true;
}
+ int otaspMode = getOtasp();
+ if (mCurrentOtaspMode != otaspMode) {
+ Log.d(LOG_TAG, "call phone.notifyOtaspChanged old otaspMode=" +
+ mCurrentOtaspMode + " new otaspMode=" + otaspMode);
+ mCurrentOtaspMode = otaspMode;
+ phone.notifyOtaspChanged(mCurrentOtaspMode);
+ }
phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
null);
} else {
@@ -642,6 +657,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
curPlmn = plmn;
}
+ @Override
+ protected Phone getPhone() {
+ return phone;
+ }
+
/**
* Handle the result of one of the pollState()-related requests
*/
@@ -1641,10 +1661,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
return false;
}
- protected void log(String s) {
- Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
- }
-
public String getMdnNumber() {
return mMdn;
}
@@ -1700,6 +1716,32 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
}
+ /**
+ * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
+ */
+ int getOtasp() {
+ int provisioningState;
+ if (mMin == null || (mMin.length() < 6)) {
+ if (DBG) Log.d(LOG_TAG, "getOtasp: bad mMin='" + mMin + "'");
+ provisioningState = OTASP_UNKNOWN;
+ } else {
+ if ((mMin.equals(UNACTIVATED_MIN_VALUE)
+ || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
+ || SystemProperties.getBoolean("test_cdma_setup", false)) {
+ provisioningState = OTASP_NEEDED;
+ } else {
+ provisioningState = OTASP_NOT_NEEDED;
+ }
+ }
+ if (DBG) Log.d(LOG_TAG, "getOtasp: state=" + provisioningState);
+ return provisioningState;
+ }
+
+ @Override
+ protected void log(String s) {
+ Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
+ }
+
private void hangupAndPowerOff() {
// hang up all active voice calls
phone.mCT.ringingCall.hangupIfAlive();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 6332415..bc41b01 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -22,6 +22,7 @@ import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyIntents;
@@ -226,6 +227,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
phone.getContext().registerReceiver(mIntentReceiver, filter);
+
+ // Gsm doesn't support OTASP so its not needed
+ phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
}
public void dispose() {
@@ -246,6 +250,11 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized");
}
+ @Override
+ public Phone getPhone() {
+ return phone;
+ }
+
/**
* Registration point for transition into GPRS attached.
* @param h handler to notify
@@ -1676,7 +1685,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
}
}
- private void log(String s) {
+ @Override
+ protected void log(String s) {
Log.d(LOG_TAG, "[GsmServiceStateTracker] " + s);
}
}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
index 8cb05cc..7bbe696 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
@@ -56,4 +56,7 @@ public class TestPhoneNotifier implements PhoneNotifier {
public void notifyDataActivity(Phone sender) {
}
+
+ public void notifyOtaspChanged(Phone sender, int otaspMode) {
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 24fba72..e97b1e6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -60,6 +60,20 @@ public class Bitmap_Delegate {
// ---- Public Helper methods ----
/**
+ * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
+ */
+ public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
+ return sManager.getDelegate(bitmap.mNativeBitmap);
+ }
+
+ /**
+ * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
+ */
+ public static Bitmap_Delegate getDelegate(int native_bitmap) {
+ return sManager.getDelegate(native_bitmap);
+ }
+
+ /**
* Creates and returns a {@link Bitmap} initialized with the given file content.
*/
public static Bitmap createBitmap(File input, Density density) throws IOException {
@@ -118,6 +132,13 @@ public class Bitmap_Delegate {
return BufferedImage.TYPE_INT_ARGB;
}
+ /**
+ * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+ */
+ public BufferedImage getImage() {
+ return mImage;
+ }
+
// ---- native methods ----
/*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
@@ -127,8 +148,7 @@ public class Bitmap_Delegate {
// create the image
BufferedImage image = new BufferedImage(width, height, imageType);
- // fill it
- //image.setRGB(x, y, rgb)
+ // FIXME fill the bitmap!
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(image);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
deleted file mode 100644
index 24da812..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ /dev/null
@@ -1,1247 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.api.ILayoutLog;
-
-import android.graphics.Paint.Align;
-import android.graphics.Paint.FontInfo;
-import android.graphics.Paint.Style;
-import android.graphics.Region.Op;
-
-import java.awt.AlphaComposite;
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.util.List;
-import java.util.Stack;
-
-/**
- * Re-implementation of the Canvas, 100% in java on top of a BufferedImage.
- */
-public class Canvas extends _Original_Canvas {
-
- private BufferedImage mBufferedImage;
- private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
- private final ILayoutLog mLogger;
-
- public Canvas() {
- mLogger = null;
- // the mBufferedImage will be taken from a bitmap in #setBitmap()
- }
-
- public Canvas(Bitmap bitmap) {
- mLogger = null;
- mBufferedImage = Bitmap_Delegate.getImage(bitmap);
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
- public Canvas(int nativeCanvas) {
- mLogger = null;
- throw new UnsupportedOperationException("Can't create Canvas(int)");
- }
-
- // custom constructors for our use.
- public Canvas(int width, int height, ILayoutLog logger) {
- mLogger = logger;
- mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
- public Canvas(int width, int height) {
- this(width, height, null /* logger*/);
- }
-
- // custom mehtods
- public BufferedImage getImage() {
- return mBufferedImage;
- }
-
- public Graphics2D getGraphics2d() {
- return mGraphicsStack.peek();
- }
-
- public void dispose() {
- while (mGraphicsStack.size() > 0) {
- mGraphicsStack.pop().dispose();
- }
- }
-
- /**
- * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
- * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
- */
- private Graphics2D getCustomGraphics(Paint paint) {
- // make new one
- Graphics2D g = getGraphics2d();
- g = (Graphics2D)g.create();
-
- // configure it
- g.setColor(new Color(paint.getColor()));
- int alpha = paint.getAlpha();
- float falpha = alpha / 255.f;
-
- Style style = paint.getStyle();
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- PathEffect e = paint.getPathEffect();
- if (e instanceof DashPathEffect) {
- DashPathEffect dpe = (DashPathEffect)e;
- g.setStroke(new BasicStroke(
- paint.getStrokeWidth(),
- paint.getStrokeCap().getJavaCap(),
- paint.getStrokeJoin().getJavaJoin(),
- paint.getStrokeMiter(),
- dpe.getIntervals(),
- dpe.getPhase()));
- } else {
- g.setStroke(new BasicStroke(
- paint.getStrokeWidth(),
- paint.getStrokeCap().getJavaCap(),
- paint.getStrokeJoin().getJavaJoin(),
- paint.getStrokeMiter()));
- }
- }
-
- Xfermode xfermode = paint.getXfermode();
- if (xfermode instanceof PorterDuffXfermode) {
- PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
-
- setModeInGraphics(mode, g, falpha);
- } else {
- if (mLogger != null && xfermode != null) {
- mLogger.warning(String.format(
- "Xfermode '%1$s' is not supported in the Layout Editor.",
- xfermode.getClass().getCanonicalName()));
- }
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
- }
-
- Shader shader = paint.getShader();
- if (shader != null) {
- java.awt.Paint shaderPaint = shader.getJavaPaint();
- if (shaderPaint != null) {
- g.setPaint(shaderPaint);
- } else {
- if (mLogger != null) {
- mLogger.warning(String.format(
- "Shader '%1$s' is not supported in the Layout Editor.",
- shader.getClass().getCanonicalName()));
- }
- }
- }
-
- return g;
- }
-
- private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) {
- switch (mode) {
- case CLEAR:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha));
- break;
- case DARKEN:
- break;
- case DST:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha));
- break;
- case DST_ATOP:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha));
- break;
- case DST_IN:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha));
- break;
- case DST_OUT:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha));
- break;
- case DST_OVER:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha));
- break;
- case LIGHTEN:
- break;
- case MULTIPLY:
- break;
- case SCREEN:
- break;
- case SRC:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha));
- break;
- case SRC_ATOP:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha));
- break;
- case SRC_IN:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha));
- break;
- case SRC_OUT:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha));
- break;
- case SRC_OVER:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
- break;
- case XOR:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha));
- break;
- }
- }
-
-
- // --------------------
- // OVERRIDEN ENUMS
- // This is needed since we rename Canvas into _Original_Canvas
- // --------------------
-
- public enum EdgeType {
- BW(0), //!< treat edges by just rounding to nearest pixel boundary
- AA(1); //!< treat edges by rounding-out, since they may be antialiased
-
- EdgeType(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
-
- // --------------------
- // OVERRIDEN METHODS
- // --------------------
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
- */
- @Override
- public void setBitmap(Bitmap bitmap) {
- mBufferedImage = Bitmap_Delegate.getImage(bitmap);
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#translate(float, float)
- */
- @Override
- public void translate(float dx, float dy) {
- getGraphics2d().translate(dx, dy);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#save()
- */
- @Override
- public int save() {
- // get the current save count
- int count = mGraphicsStack.size();
-
- // create a new graphics and add it to the stack
- Graphics2D g = (Graphics2D)getGraphics2d().create();
- mGraphicsStack.push(g);
-
- // return the old save count
- return count;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#save(int)
- */
- @Override
- public int save(int saveFlags) {
- // For now we ignore saveFlags
- return save();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#restore()
- */
- @Override
- public void restore() {
- mGraphicsStack.pop();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#restoreToCount(int)
- */
- @Override
- public void restoreToCount(int saveCount) {
- while (mGraphicsStack.size() > saveCount) {
- mGraphicsStack.pop();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getSaveCount()
- */
- @Override
- public int getSaveCount() {
- return mGraphicsStack.size();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(float left, float top, float right, float bottom, Op op) {
- return clipRect(left, top, right, bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(float, float, float, float)
- */
- @Override
- public boolean clipRect(float left, float top, float right, float bottom) {
- getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(int, int, int, int)
- */
- @Override
- public boolean clipRect(int left, int top, int right, int bottom) {
- getGraphics2d().clipRect(left, top, right-left, bottom-top);
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(Rect rect, Op op) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.Rect)
- */
- @Override
- public boolean clipRect(Rect rect) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(RectF rect, Op op) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.RectF)
- */
- @Override
- public boolean clipRect(RectF rect) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- public boolean quickReject(RectF rect, EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public boolean quickReject(Path path, EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(Path path, _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public boolean quickReject(float left, float top, float right, float bottom,
- EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(float left, float top, float right, float bottom,
- _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Retrieve the clip bounds, returning true if they are non-empty.
- *
- * @param bounds Return the clip bounds here. If it is null, ignore it but
- * still return true if the current clip is non-empty.
- * @return true if the current clip is non-empty.
- */
- @Override
- public boolean getClipBounds(Rect bounds) {
- Rectangle rect = getGraphics2d().getClipBounds();
- if (rect != null) {
- bounds.left = rect.x;
- bounds.top = rect.y;
- bounds.right = rect.x + rect.width;
- bounds.bottom = rect.y + rect.height;
- return true;
- }
- return false;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode)
- */
- @Override
- public void drawColor(int color, PorterDuff.Mode mode) {
- Graphics2D g = getGraphics2d();
-
- // save old color
- Color c = g.getColor();
-
- Composite composite = g.getComposite();
-
- // get the alpha from the color
- int alpha = color >>> 24;
- float falpha = alpha / 255.f;
-
- setModeInGraphics(mode, g, falpha);
-
- g.setColor(new Color(color));
-
- g.fillRect(0, 0, getWidth(), getHeight());
-
- g.setComposite(composite);
-
- // restore color
- g.setColor(c);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawColor(int)
- */
- @Override
- public void drawColor(int color) {
- drawColor(color, PorterDuff.Mode.SRC_OVER);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawARGB(int, int, int, int)
- */
- @Override
- public void drawARGB(int a, int r, int g, int b) {
- drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRGB(int, int, int)
- */
- @Override
- public void drawRGB(int r, int g, int b) {
- drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getWidth()
- */
- @Override
- public int getWidth() {
- return mBufferedImage.getWidth();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getHeight()
- */
- @Override
- public int getHeight() {
- return mBufferedImage.getHeight();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPaint(android.graphics.Paint)
- */
- @Override
- public void drawPaint(Paint paint) {
- drawColor(paint.getColor());
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- (int)left, (int)top,
- (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
- boolean needsRestore = false;
- if (matrix.isIdentity() == false) {
- // create a new graphics and apply the matrix to it
- save(); // this creates a new Graphics2D, and stores it for children call to use
- needsRestore = true;
- Graphics2D g = getGraphics2d(); // get the newly create Graphics2D
-
- // get the Graphics2D current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform from the matrix
- AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix);
-
- // combine them so that the matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
- // draw the bitmap
- drawBitmap(bitmap, 0, 0, paint);
-
- if (needsRestore) {
- // remove the new graphics
- restore();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
- if (src == null) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- dst.left, dst.top, dst.right, dst.bottom, paint);
- } else {
- drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
- dst.left, dst.top, dst.right, dst.bottom, paint);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
- if (src == null) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
- } else {
- drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
- (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
- int height, boolean hasAlpha, Paint paint) {
- throw new UnsupportedOperationException();
- }
-
- private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
- int dtop, int dright, int dbottom, Paint paint) {
- BufferedImage image = Bitmap_Delegate.getImage(bitmap);
-
- Graphics2D g = getGraphics2d();
-
- Composite c = null;
-
- if (paint != null) {
- if (paint.isFilterBitmap()) {
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- }
-
- if (paint.getAlpha() != 0xFF) {
- c = g.getComposite();
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- paint.getAlpha()/255.f));
- }
- }
-
- g.drawImage(image, dleft, dtop, dright, dbottom,
- sleft, stop, sright, sbottom, null);
-
- if (paint != null) {
- if (paint.isFilterBitmap()) {
- g.dispose();
- }
- if (c != null) {
- g.setComposite(c);
- }
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#rotate(float, float, float)
- */
- @Override
- public void rotate(float degrees, float px, float py) {
- if (degrees != 0) {
- Graphics2D g = getGraphics2d();
- g.translate(px, py);
- g.rotate(Math.toRadians(degrees));
- g.translate(-px, -py);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#rotate(float)
- */
- @Override
- public void rotate(float degrees) {
- getGraphics2d().rotate(Math.toRadians(degrees));
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#scale(float, float, float, float)
- */
- @Override
- public void scale(float sx, float sy, float px, float py) {
- Graphics2D g = getGraphics2d();
- g.translate(px, py);
- g.scale(sx, sy);
- g.translate(-px, -py);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#scale(float, float)
- */
- @Override
- public void scale(float sx, float sy) {
- getGraphics2d().scale(sx, sy);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
- // WARNING: the logic in this method is similar to Paint.measureText.
- // Any change to this method should be reflected in Paint.measureText
- Graphics2D g = getGraphics2d();
-
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
- // set the color. because this only handles RGB, the alpha channel is handled
- // as a composite.
- g.setColor(new Color(paint.getColor()));
- int alpha = paint.getAlpha();
- float falpha = alpha / 255.f;
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
-
-
- // Paint.TextAlign indicates how the text is positioned relative to X.
- // LEFT is the default and there's nothing to do.
- if (paint.getTextAlign() != Align.LEFT) {
- float m = paint.measureText(text, index, count);
- if (paint.getTextAlign() == Align.CENTER) {
- x -= m / 2;
- } else if (paint.getTextAlign() == Align.RIGHT) {
- x -= m;
- }
- }
-
- List<FontInfo> fonts = paint.getFonts();
- try {
- if (fonts.size() > 0) {
- FontInfo mainFont = fonts.get(0);
- int i = index;
- int lastIndex = index + count;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // draw all the rest and exit.
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
- return;
- } else if (upTo > 0) {
- // draw what's possible
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, upTo - i, (int)x, (int)y);
-
- // compute the width that was drawn to increase x
- x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-
- // move index to the first non displayed char.
- i = upTo;
-
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < fonts.size() ; f++) {
- FontInfo fontInfo = fonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- // draw that char
- g.setFont(fontInfo.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
-
- // update x
- x += fontInfo.mMetrics.charsWidth(text, i, charCount);
-
- // update the index in the text, and move on
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, display it with the main font.
- // (it'll put a square probably)
- if (foundFont == false) {
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
-
- // measure it to advance x
- x += mainFont.mMetrics.charsWidth(text, i, charCount);
-
- // and move to the next chars.
- i += charCount;
- }
- }
- }
- } finally {
- g.dispose();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
- drawText(text.toString().toCharArray(), start, end - start, x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(String text, float x, float y, Paint paint) {
- drawText(text.toCharArray(), 0, text.length(), x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(String text, int start, int end, float x, float y, Paint paint) {
- drawText(text.toCharArray(), start, end - start, x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawRect(RectF rect, Paint paint) {
- doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawRect(float left, float top, float right, float bottom, Paint paint) {
- doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint)
- */
- @Override
- public void drawRect(Rect r, Paint paint) {
- doDrawRect(r.left, r.top, r.width(), r.height(), paint);
- }
-
- private final void doDrawRect(int left, int top, int width, int height, Paint paint) {
- if (width > 0 && height > 0) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillRect(left, top, width, height);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawRect(left, top, width, height);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint)
- */
- @Override
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
- if (rect.width() > 0 && rect.height() > 0) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
-
- int arcWidth = (int)(rx * 2);
- int arcHeight = (int)(ry * 2);
-
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- arcWidth, arcHeight);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- arcWidth, arcHeight);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawLines(float[] pts, int offset, int count, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- for (int i = 0 ; i < count ; i += 4) {
- g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
- (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint)
- */
- @Override
- public void drawLines(float[] pts, Paint paint) {
- drawLines(pts, 0, pts.length, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawCircle(float cx, float cy, float radius, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- int size = (int)(radius * 2);
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillOval((int)(cx - radius), (int)(cy - radius), size, size);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawOval((int)(cx - radius), (int)(cy - radius), size, size);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawOval(RectF oval, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint)
- */
- @Override
- public void drawPath(Path path, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fill(path.getAwtShape());
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.draw(path.getAwtShape());
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix)
- */
- @Override
- public void setMatrix(Matrix matrix) {
- // get the new current graphics
- Graphics2D g = getGraphics2d();
-
- // and apply the matrix
- g.setTransform(Matrix_Delegate.getAffineTransform(matrix));
-
- if (mLogger != null && Matrix_Delegate.hasPerspective(matrix)) {
- mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#concat(android.graphics.Matrix)
- */
- @Override
- public void concat(Matrix matrix) {
- // get the current top graphics2D object.
- Graphics2D g = getGraphics2d();
-
- // get its current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform of the given matrix
- AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix);
-
- // combine them so that the given matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics2D as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
-
- // --------------------
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op)
- */
- @Override
- public boolean clipPath(Path path, Op op) {
- // TODO Auto-generated method stub
- return super.clipPath(path, op);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipPath(android.graphics.Path)
- */
- @Override
- public boolean clipPath(Path path) {
- // TODO Auto-generated method stub
- return super.clipPath(path);
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRegion(Region region, Op op) {
- // TODO Auto-generated method stub
- return super.clipRegion(region, op);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRegion(android.graphics.Region)
- */
- @Override
- public boolean clipRegion(Region region) {
- // TODO Auto-generated method stub
- return super.clipRegion(region);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint)
- */
- @Override
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- // TODO Auto-generated method stub
- super.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint)
- */
- @Override
- public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
- int vertOffset, int[] colors, int colorOffset, Paint paint) {
- // TODO Auto-generated method stub
- super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect)
- */
- @Override
- public void drawPicture(Picture picture, Rect dst) {
- // TODO Auto-generated method stub
- super.drawPicture(picture, dst);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF)
- */
- @Override
- public void drawPicture(Picture picture, RectF dst) {
- // TODO Auto-generated method stub
- super.drawPicture(picture, dst);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture)
- */
- @Override
- public void drawPicture(Picture picture) {
- // TODO Auto-generated method stub
- super.drawPicture(picture);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint)
- */
- @Override
- public void drawPoint(float x, float y, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoint(x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawPoints(float[] pts, int offset, int count, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoints(pts, offset, count, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint)
- */
- @Override
- public void drawPoints(float[] pts, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoints(pts, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint)
- */
- @Override
- public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPosText(text, index, count, pos, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint)
- */
- @Override
- public void drawPosText(String text, float[] pos, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPosText(text, pos, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint)
- */
- @Override
- public void drawTextOnPath(char[] text, int index, int count, Path path, float offset,
- float offset2, Paint paint) {
- // TODO Auto-generated method stub
- super.drawTextOnPath(text, index, count, path, offset, offset2, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint)
- */
- @Override
- public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) {
- // TODO Auto-generated method stub
- super.drawTextOnPath(text, path, offset, offset2, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
- float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
- int indexOffset, int indexCount, Paint paint) {
- // TODO Auto-generated method stub
- super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset,
- indices, indexOffset, indexCount, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getDrawFilter()
- */
- @Override
- public DrawFilter getDrawFilter() {
- // TODO Auto-generated method stub
- return super.getDrawFilter();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getMatrix()
- */
- @Override
- public Matrix getMatrix() {
- // TODO Auto-generated method stub
- return super.getMatrix();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix)
- */
- @Override
- public void getMatrix(Matrix ctm) {
- // TODO Auto-generated method stub
- super.getMatrix(ctm);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#isOpaque()
- */
- @Override
- public boolean isOpaque() {
- // TODO Auto-generated method stub
- return super.isOpaque();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int)
- */
- @Override
- public int saveLayer(float left, float top, float right, float bottom, Paint paint,
- int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayer(left, top, right, bottom, paint, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int)
- */
- @Override
- public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayer(bounds, paint, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int)
- */
- @Override
- public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
- int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int)
- */
- @Override
- public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayerAlpha(bounds, alpha, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter)
- */
- @Override
- public void setDrawFilter(DrawFilter filter) {
- // TODO Auto-generated method stub
- super.setDrawFilter(filter);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#skew(float, float)
- */
- @Override
- public void skew(float sx, float sy) {
- // TODO Auto-generated method stub
- super.skew(sx, sy);
- }
-
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
new file mode 100644
index 0000000..6627d37
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.api.ILayoutLog;
+import com.android.layoutlib.bridge.DelegateManager;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.util.Stack;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Canvas
+ *
+ * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Canvas class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Canvas_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Canvas_Delegate> sManager =
+ new DelegateManager<Canvas_Delegate>();
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+ private BufferedImage mBufferedImage;
+ private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
+ private ILayoutLog mLogger;
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns the native delegate associated to a given {@link Canvas} object.
+ */
+ public static Canvas_Delegate getDelegate(Canvas canvas) {
+ return sManager.getDelegate(canvas.mNativeCanvas);
+ }
+
+ /**
+ * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
+ */
+ public static Canvas_Delegate getDelegate(int native_canvas) {
+ return sManager.getDelegate(native_canvas);
+ }
+
+ /**
+ * Sets the layoutlib logger into the canvas.
+ * @param logger
+ */
+ public void setLogger(ILayoutLog logger) {
+ mLogger = logger;
+ }
+
+ /**
+ * Returns the current {@link Graphics2D} used to draw.
+ */
+ public Graphics2D getGraphics2d() {
+ return mGraphicsStack.peek();
+ }
+
+ /**
+ * Disposes of the {@link Graphics2D} stack.
+ */
+ public void dispose() {
+
+ }
+
+ // ---- native methods ----
+
+ /*package*/ static boolean isOpaque(Canvas thisCanvas) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int getWidth(Canvas thisCanvas) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int getHeight(Canvas thisCanvas) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
+ float bottom) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
+ int bottom) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int save(Canvas thisCanvas) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void restore(Canvas thisCanvas) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int getSaveCount(Canvas thisCanvas) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
+ Paint paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void drawLines(Canvas thisCanvas, float[] pts, int offset, int count,
+ Paint paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void freeCaches() {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int initRaster(int nativeBitmapOrZero) {
+ if (nativeBitmapOrZero > 0) {
+ // get the Bitmap from the int
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
+
+ // create a new Canvas_Delegate with the given bitmap and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate.getImage());
+
+ return sManager.addDelegate(newDelegate);
+ } else {
+ // create a new Canvas_Delegate and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate();
+
+ return sManager.addDelegate(newDelegate);
+ }
+ }
+
+ /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ assert false;
+ return;
+ }
+
+ canvasDelegate.setBitmap(bitmapDelegate.getImage());
+ }
+
+ /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
+ int paint, int layerFlags) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_saveLayer(int nativeCanvas, float l,
+ float t, float r, float b,
+ int paint, int layerFlags) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_saveLayerAlpha(int nativeCanvas,
+ RectF bounds, int alpha,
+ int layerFlags) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
+ float t, float r, float b,
+ int alpha, int layerFlags) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static void native_concat(int nCanvas, int nMatrix) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_clipRect(int nCanvas,
+ float left, float top,
+ float right, float bottom,
+ int regionOp) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_clipPath(int nativeCanvas,
+ int nativePath,
+ int regionOp) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_clipRegion(int nativeCanvas,
+ int nativeRegion,
+ int regionOp) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
+ int nativeFilter) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_getClipBounds(int nativeCanvas,
+ Rect bounds) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_getCTM(int canvas, int matrix) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ RectF rect,
+ int native_edgeType) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ int path,
+ int native_edgeType) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ float left, float top,
+ float right, float bottom,
+ int native_edgeType) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g,
+ int b) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r,
+ int g, int b) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawColor(int nativeCanvas, int color) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawColor(int nativeCanvas, int color,
+ int mode) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawLine(int nativeCanvas, float startX,
+ float startY, float stopX,
+ float stopY, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawRect(int nativeCanvas, float left,
+ float top, float right,
+ float bottom, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawOval(int nativeCanvas, RectF oval,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawCircle(int nativeCanvas, float cx,
+ float cy, float radius,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawArc(int nativeCanvas, RectF oval,
+ float startAngle, float sweep,
+ boolean useCenter, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawRoundRect(int nativeCanvas,
+ RectF rect, float rx,
+ float ry, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawPath(int nativeCanvas, int path,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+ float left, float top,
+ int nativePaintOrZero,
+ int canvasDensity,
+ int screenDensity,
+ int bitmapDensity) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+ Rect src, RectF dst,
+ int nativePaintOrZero,
+ int screenDensity,
+ int bitmapDensity) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
+ Rect src, Rect dst,
+ int nativePaintOrZero,
+ int screenDensity,
+ int bitmapDensity) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
+ int offset, int stride, float x,
+ float y, int width, int height,
+ boolean hasAlpha,
+ int nativePaintOrZero) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
+ int nMatrix, int nPaint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
+ int meshWidth, int meshHeight,
+ float[] verts, int vertOffset,
+ int[] colors, int colorOffset, int nPaint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n,
+ float[] verts, int vertOffset, float[] texs, int texOffset,
+ int[] colors, int colorOffset, short[] indices,
+ int indexOffset, int indexCount, int nPaint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static void native_drawText(int nativeCanvas, char[] text,
+ int index, int count, float x,
+ float y, int flags, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawText(int nativeCanvas, String text,
+ int start, int end, float x,
+ float y, int flags, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static void native_drawTextRun(int nativeCanvas, String text,
+ int start, int end, int contextStart, int contextEnd,
+ float x, float y, int flags, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text,
+ int start, int count, int contextStart, int contextCount,
+ float x, float y, int flags, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static void native_drawPosText(int nativeCanvas,
+ char[] text, int index,
+ int count, float[] pos,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawPosText(int nativeCanvas,
+ String text, float[] pos,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+ char[] text, int index,
+ int count, int path,
+ float hOffset,
+ float vOffset, int bidiFlags,
+ int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+ String text, int path,
+ float hOffset,
+ float vOffset,
+ int flags, int paint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_drawPicture(int nativeCanvas,
+ int nativePicture) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void finalizer(int nativeCanvas) {
+ sManager.removeDelegate(nativeCanvas);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private Canvas_Delegate(BufferedImage image) {
+ setBitmap(image);
+ }
+
+ private Canvas_Delegate() {
+ }
+
+ private void setBitmap(BufferedImage image) {
+ mBufferedImage = image;
+ mGraphicsStack.push(mBufferedImage.createGraphics());
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
deleted file mode 100644
index 2de21c1..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ /dev/null
@@ -1,1211 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.SpannedString;
-import android.text.TextUtils;
-
-import java.awt.BasicStroke;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A paint implementation overridden by the LayoutLib bridge.
- */
-public class Paint extends _Original_Paint {
-
- private int mColor = 0xFFFFFFFF;
- private float mStrokeWidth = 1.f;
- private float mTextSize = 20;
- private float mScaleX = 1;
- private float mSkewX = 0;
- private Align mAlign = Align.LEFT;
- private Style mStyle = Style.FILL;
- private float mStrokeMiter = 4.0f;
- private Cap mCap = Cap.BUTT;
- private Join mJoin = Join.MITER;
- private int mFlags = 0;
-
- /**
- * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
- */
- public static final class FontInfo {
- Font mFont;
- java.awt.FontMetrics mMetrics;
- }
-
- private List<FontInfo> mFonts;
- private final FontRenderContext mFontContext = new FontRenderContext(
- new AffineTransform(), true, true);
-
- public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
- public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG;
- public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG;
- public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG;
- public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG;
- public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG;
- public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG;
- public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG;
- public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
-
- public static class FontMetrics extends _Original_Paint.FontMetrics {
- }
-
- public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
- }
-
- /**
- * The Style specifies if the primitive being drawn is filled,
- * stroked, or both (in the same color). The default is FILL.
- */
- public enum Style {
- /**
- * Geometry and text drawn with this style will be filled, ignoring all
- * stroke-related settings in the paint.
- */
- FILL (0),
- /**
- * Geometry and text drawn with this style will be stroked, respecting
- * the stroke-related fields on the paint.
- */
- STROKE (1),
- /**
- * Geometry and text drawn with this style will be both filled and
- * stroked at the same time, respecting the stroke-related fields on
- * the paint.
- */
- FILL_AND_STROKE (2);
-
- Style(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * The Cap specifies the treatment for the beginning and ending of
- * stroked lines and paths. The default is BUTT.
- */
- public enum Cap {
- /**
- * The stroke ends with the path, and does not project beyond it.
- */
- BUTT (0),
- /**
- * The stroke projects out as a square, with the center at the end
- * of the path.
- */
- ROUND (1),
- /**
- * The stroke projects out as a semicircle, with the center at the
- * end of the path.
- */
- SQUARE (2);
-
- private Cap(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
-
- /** custom for layoutlib */
- public int getJavaCap() {
- switch (this) {
- case BUTT:
- return BasicStroke.CAP_BUTT;
- case ROUND:
- return BasicStroke.CAP_ROUND;
- default:
- case SQUARE:
- return BasicStroke.CAP_SQUARE;
- }
- }
- }
-
- /**
- * The Join specifies the treatment where lines and curve segments
- * join on a stroked path. The default is MITER.
- */
- public enum Join {
- /**
- * The outer edges of a join meet at a sharp angle
- */
- MITER (0),
- /**
- * The outer edges of a join meet in a circular arc.
- */
- ROUND (1),
- /**
- * The outer edges of a join meet with a straight line
- */
- BEVEL (2);
-
- private Join(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
-
- /** custom for layoutlib */
- public int getJavaJoin() {
- switch (this) {
- default:
- case MITER:
- return BasicStroke.JOIN_MITER;
- case ROUND:
- return BasicStroke.JOIN_ROUND;
- case BEVEL:
- return BasicStroke.JOIN_BEVEL;
- }
- }
- }
-
- /**
- * Align specifies how drawText aligns its text relative to the
- * [x,y] coordinates. The default is LEFT.
- */
- public enum Align {
- /**
- * The text is drawn to the right of the x,y origin
- */
- LEFT (0),
- /**
- * The text is drawn centered horizontally on the x,y origin
- */
- CENTER (1),
- /**
- * The text is drawn to the left of the x,y origin
- */
- RIGHT (2);
-
- private Align(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- public Paint() {
- this(0);
- }
-
- /*
- * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails.
- */
- @Override
- public void finalize() { }
-
- public Paint(int flags) {
- setFlags(flags | DEFAULT_PAINT_FLAGS);
- initFont();
- }
-
- public Paint(Paint paint) {
- set(paint);
- initFont();
- }
-
- @Override
- public void reset() {
- super.reset();
- }
-
- /**
- * Returns the list of {@link Font} objects. The first item is the main font, the rest
- * are fall backs for characters not present in the main font.
- */
- public List<FontInfo> getFonts() {
- return mFonts;
- }
-
- private void initFont() {
- mTypeface = Typeface.DEFAULT;
- updateFontObject();
- }
-
- /**
- * Update the {@link Font} object from the typeface, text size and scaling
- */
- @SuppressWarnings("deprecation")
- private void updateFontObject() {
- if (mTypeface != null) {
- // Get the fonts from the TypeFace object.
- List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
-
- // create new font objects as well as FontMetrics, based on the current text size
- // and skew info.
- ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
- for (Font font : fonts) {
- FontInfo info = new FontInfo();
- info.mFont = font.deriveFont(mTextSize);
- if (mScaleX != 1.0 || mSkewX != 0) {
- // TODO: support skew
- info.mFont = info.mFont.deriveFont(new AffineTransform(
- mScaleX, mSkewX, 0, 0, 1, 0));
- }
- info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
-
- infoList.add(info);
- }
-
- mFonts = Collections.unmodifiableList(infoList);
- }
- }
-
- //----------------------------------------
-
- public void set(Paint src) {
- if (this != src) {
- mColor = src.mColor;
- mTextSize = src.mTextSize;
- mScaleX = src.mScaleX;
- mSkewX = src.mSkewX;
- mAlign = src.mAlign;
- mStyle = src.mStyle;
- mFlags = src.mFlags;
-
- updateFontObject();
-
- super.set(src);
- }
- }
-
- @Override
- public void setCompatibilityScaling(float factor) {
- super.setCompatibilityScaling(factor);
- }
-
- @Override
- public int getFlags() {
- return mFlags;
- }
-
- @Override
- public void setFlags(int flags) {
- mFlags = flags;
- }
-
- @Override
- public boolean isAntiAlias() {
- return super.isAntiAlias();
- }
-
- @Override
- public boolean isDither() {
- return super.isDither();
- }
-
- @Override
- public boolean isLinearText() {
- return super.isLinearText();
- }
-
- @Override
- public boolean isStrikeThruText() {
- return super.isStrikeThruText();
- }
-
- @Override
- public boolean isUnderlineText() {
- return super.isUnderlineText();
- }
-
- @Override
- public boolean isFakeBoldText() {
- return super.isFakeBoldText();
- }
-
- @Override
- public boolean isSubpixelText() {
- return super.isSubpixelText();
- }
-
- @Override
- public boolean isFilterBitmap() {
- return super.isFilterBitmap();
- }
-
- /**
- * Return the font's recommended interline spacing, given the Paint's
- * settings for typeface, textSize, etc. If metrics is not null, return the
- * fontmetric values in it.
- *
- * @param metrics If this object is not null, its fields are filled with
- * the appropriate values given the paint's text attributes.
- * @return the font's recommended interline spacing.
- */
- public float getFontMetrics(FontMetrics metrics) {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- if (metrics != null) {
- // Android expects negative ascent so we invert the value from Java.
- metrics.top = - javaMetrics.getMaxAscent();
- metrics.ascent = - javaMetrics.getAscent();
- metrics.descent = javaMetrics.getDescent();
- metrics.bottom = javaMetrics.getMaxDescent();
- metrics.leading = javaMetrics.getLeading();
- }
-
- return javaMetrics.getHeight();
- }
-
- return 0;
- }
-
- public int getFontMetricsInt(FontMetricsInt metrics) {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- if (metrics != null) {
- // Android expects negative ascent so we invert the value from Java.
- metrics.top = - javaMetrics.getMaxAscent();
- metrics.ascent = - javaMetrics.getAscent();
- metrics.descent = javaMetrics.getDescent();
- metrics.bottom = javaMetrics.getMaxDescent();
- metrics.leading = javaMetrics.getLeading();
- }
-
- return javaMetrics.getHeight();
- }
-
- return 0;
- }
-
- /**
- * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
- */
- public FontMetrics getFontMetrics() {
- FontMetrics fm = new FontMetrics();
- getFontMetrics(fm);
- return fm;
- }
-
- /**
- * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
- */
- public FontMetricsInt getFontMetricsInt() {
- FontMetricsInt fm = new FontMetricsInt();
- getFontMetricsInt(fm);
- return fm;
- }
-
-
-
- @Override
- public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- @Override
- public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- @Override
- public Typeface setTypeface(Typeface typeface) {
- if (typeface != null) {
- mTypeface = typeface;
- } else {
- mTypeface = Typeface.DEFAULT;
- }
-
- updateFontObject();
-
- return typeface;
- }
-
- @Override
- public Typeface getTypeface() {
- return super.getTypeface();
- }
-
- @Override
- public int getColor() {
- return mColor;
- }
-
- @Override
- public void setColor(int color) {
- mColor = color;
- }
-
- @Override
- public void setARGB(int a, int r, int g, int b) {
- super.setARGB(a, r, g, b);
- }
-
- @Override
- public void setAlpha(int alpha) {
- mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
- }
-
- @Override
- public int getAlpha() {
- return mColor >>> 24;
- }
-
- /**
- * Set or clear the shader object.
- * <p />
- * Pass null to clear any previous shader.
- * As a convenience, the parameter passed is also returned.
- *
- * @param shader May be null. the new shader to be installed in the paint
- * @return shader
- */
- @Override
- public Shader setShader(Shader shader) {
- return mShader = shader;
- }
-
- @Override
- public Shader getShader() {
- return super.getShader();
- }
-
- /**
- * Set or clear the paint's colorfilter, returning the parameter.
- *
- * @param filter May be null. The new filter to be installed in the paint
- * @return filter
- */
- @Override
- public ColorFilter setColorFilter(ColorFilter filter) {
- mColorFilter = filter;
- return filter;
- }
-
- @Override
- public ColorFilter getColorFilter() {
- return super.getColorFilter();
- }
-
- /**
- * Set or clear the xfermode object.
- * <p />
- * Pass null to clear any previous xfermode.
- * As a convenience, the parameter passed is also returned.
- *
- * @param xfermode May be null. The xfermode to be installed in the paint
- * @return xfermode
- */
- @Override
- public Xfermode setXfermode(Xfermode xfermode) {
- return mXfermode = xfermode;
- }
-
- @Override
- public Xfermode getXfermode() {
- return super.getXfermode();
- }
-
- @Override
- public Rasterizer setRasterizer(Rasterizer rasterizer) {
- mRasterizer = rasterizer;
- return rasterizer;
- }
-
- @Override
- public Rasterizer getRasterizer() {
- return super.getRasterizer();
- }
-
- @Override
- public void setShadowLayer(float radius, float dx, float dy, int color) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void clearShadowLayer() {
- super.clearShadowLayer();
- }
-
- public void setTextAlign(Align align) {
- mAlign = align;
- }
-
- @Override
- public void setTextAlign(android.graphics._Original_Paint.Align align) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public Align getTextAlign() {
- return mAlign;
- }
-
- public void setStyle(Style style) {
- mStyle = style;
- }
-
- @Override
- public void setStyle(android.graphics._Original_Paint.Style style) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public Style getStyle() {
- return mStyle;
- }
-
- @Override
- public void setDither(boolean dither) {
- mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
- }
-
- @Override
- public void setAntiAlias(boolean aa) {
- mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
- }
-
- @Override
- public void setFakeBoldText(boolean flag) {
- mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
- }
-
- @Override
- public void setLinearText(boolean flag) {
- mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
- }
-
- @Override
- public void setSubpixelText(boolean flag) {
- mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
- }
-
- @Override
- public void setUnderlineText(boolean flag) {
- mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
- }
-
- @Override
- public void setStrikeThruText(boolean flag) {
- mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
- }
-
- @Override
- public void setFilterBitmap(boolean flag) {
- mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
- }
-
- @Override
- public float getStrokeWidth() {
- return mStrokeWidth;
- }
-
- @Override
- public void setStrokeWidth(float width) {
- mStrokeWidth = width;
- }
-
- @Override
- public float getStrokeMiter() {
- return mStrokeMiter;
- }
-
- @Override
- public void setStrokeMiter(float miter) {
- mStrokeMiter = miter;
- }
-
- @Override
- public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public void setStrokeCap(Cap cap) {
- mCap = cap;
- }
-
- public Cap getStrokeCap() {
- return mCap;
- }
-
- @Override
- public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public void setStrokeJoin(Join join) {
- mJoin = join;
- }
-
- public Join getStrokeJoin() {
- return mJoin;
- }
-
- @Override
- public boolean getFillPath(Path src, Path dst) {
- return super.getFillPath(src, dst);
- }
-
- @Override
- public PathEffect setPathEffect(PathEffect effect) {
- mPathEffect = effect;
- return effect;
- }
-
- @Override
- public PathEffect getPathEffect() {
- return super.getPathEffect();
- }
-
- @Override
- public MaskFilter setMaskFilter(MaskFilter maskfilter) {
- mMaskFilter = maskfilter;
- return maskfilter;
- }
-
- @Override
- public MaskFilter getMaskFilter() {
- return super.getMaskFilter();
- }
-
- /**
- * Return the paint's text size.
- *
- * @return the paint's text size.
- */
- @Override
- public float getTextSize() {
- return mTextSize;
- }
-
- /**
- * Set the paint's text size. This value must be > 0
- *
- * @param textSize set the paint's text size.
- */
- @Override
- public void setTextSize(float textSize) {
- mTextSize = textSize;
-
- updateFontObject();
- }
-
- /**
- * Return the paint's horizontal scale factor for text. The default value
- * is 1.0.
- *
- * @return the paint's scale factor in X for drawing/measuring text
- */
- @Override
- public float getTextScaleX() {
- return mScaleX;
- }
-
- /**
- * Set the paint's horizontal scale factor for text. The default value
- * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
- * stretch the text narrower.
- *
- * @param scaleX set the paint's scale in X for drawing/measuring text.
- */
- @Override
- public void setTextScaleX(float scaleX) {
- mScaleX = scaleX;
-
- updateFontObject();
- }
-
- /**
- * Return the paint's horizontal skew factor for text. The default value
- * is 0.
- *
- * @return the paint's skew factor in X for drawing text.
- */
- @Override
- public float getTextSkewX() {
- return mSkewX;
- }
-
- /**
- * Set the paint's horizontal skew factor for text. The default value
- * is 0. For approximating oblique text, use values around -0.25.
- *
- * @param skewX set the paint's skew factor in X for drawing text.
- */
- @Override
- public void setTextSkewX(float skewX) {
- mSkewX = skewX;
-
- updateFontObject();
- }
-
- @Override
- public float getFontSpacing() {
- return super.getFontSpacing();
- }
-
- /**
- * Return the distance above (negative) the baseline (ascent) based on the
- * current typeface and text size.
- *
- * @return the distance above (negative) the baseline (ascent) based on the
- * current typeface and text size.
- */
- @Override
- public float ascent() {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- // Android expects negative ascent so we invert the value from Java.
- return - javaMetrics.getAscent();
- }
-
- return 0;
- }
-
- /**
- * Return the distance below (positive) the baseline (descent) based on the
- * current typeface and text size.
- *
- * @return the distance below (positive) the baseline (descent) based on
- * the current typeface and text size.
- */
- @Override
- public float descent() {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- return javaMetrics.getDescent();
- }
-
- return 0;
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @param index The index of the first character to start measuring
- * @param count THe number of characters to measure, beginning with start
- * @return The width of the text
- */
- @Override
- public float measureText(char[] text, int index, int count) {
- // WARNING: the logic in this method is similar to Canvas.drawText.
- // Any change to this method should be reflected in Canvas.drawText
- if (mFonts.size() > 0) {
- FontInfo mainFont = mFonts.get(0);
- int i = index;
- int lastIndex = index + count;
- float total = 0f;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // shortcut to exit
- return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
- } else if (upTo > 0) {
- total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
- i = upTo;
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < mFonts.size() ; f++) {
- FontInfo fontInfo = mFonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- total += fontInfo.mMetrics.charsWidth(text, i, charCount);
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, measure it with the main font.
- if (foundFont == false) {
- int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
- total += mainFont.mMetrics.charsWidth(text, i, size);
- i += size;
- }
- }
- }
-
- return 0;
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @param start The index of the first character to start measuring
- * @param end 1 beyond the index of the last character to measure
- * @return The width of the text
- */
- @Override
- public float measureText(String text, int start, int end) {
- return measureText(text.toCharArray(), start, end - start);
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @return The width of the text
- */
- @Override
- public float measureText(String text) {
- return measureText(text.toCharArray(), 0, text.length());
- }
-
- /*
- * re-implement to call SpannableStringBuilder.measureText with a Paint object
- * instead of an _Original_Paint
- */
- @Override
- public float measureText(CharSequence text, int start, int end) {
- if (text instanceof String) {
- return measureText((String)text, start, end);
- }
- if (text instanceof SpannedString ||
- text instanceof SpannableString) {
- return measureText(text.toString(), start, end);
- }
- if (text instanceof SpannableStringBuilder) {
- return ((SpannableStringBuilder)text).measureText(start, end, this);
- }
-
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- float result = measureText(buf, 0, end - start);
- TemporaryBuffer.recycle(buf);
- return result;
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param index The offset into text to begin measuring at
- * @param count The number of maximum number of entries to measure. If count
- * is negative, then the characters before index are measured
- * in reverse order. This allows for measuring the end of
- * string.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(count).
- */
- @Override
- public int breakText(char[] text, int index, int count,
- float maxWidth, float[] measuredWidth) {
- int inc = count > 0 ? 1 : -1;
-
- int measureIndex = 0;
- float measureAcc = 0;
- for (int i = index ; i != index + count ; i += inc, measureIndex++) {
- int start, end;
- if (i < index) {
- start = i;
- end = index;
- } else {
- start = index;
- end = i;
- }
-
- // measure from start to end
- float res = measureText(text, start, end - start + 1);
-
- if (measuredWidth != null) {
- measuredWidth[measureIndex] = res;
- }
-
- measureAcc += res;
- if (res > maxWidth) {
- // we should not return this char index, but since it's 0-based and we need
- // to return a count, we simply return measureIndex;
- return measureIndex;
- }
-
- }
-
- return measureIndex;
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param measureForwards If true, measure forwards, starting at index.
- * Otherwise, measure backwards, starting with the
- * last character in the string.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(count).
- */
- @Override
- public int breakText(String text, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
- return breakText(text,
- 0 /* start */, text.length() /* end */,
- measureForwards, maxWidth, measuredWidth);
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param start The offset into text to begin measuring at
- * @param end The end of the text slice to measure.
- * @param measureForwards If true, measure forwards, starting at start.
- * Otherwise, measure backwards, starting with end.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(end - start).
- */
- @Override
- public int breakText(CharSequence text, int start, int end, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
- char[] buf = new char[end - start];
- int result;
-
- TextUtils.getChars(text, start, end, buf, 0);
-
- if (measureForwards) {
- result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
- } else {
- result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
- }
-
- return result;
- }
-
- /**
- * Return the advance widths for the characters in the string.
- *
- * @param text The text to measure
- * @param index The index of the first char to to measure
- * @param count The number of chars starting with index to measure
- * @param widths array to receive the advance widths of the characters.
- * Must be at least a large as count.
- * @return the actual number of widths returned.
- */
- @Override
- public int getTextWidths(char[] text, int index, int count,
- float[] widths) {
- if (mFonts.size() > 0) {
- if ((index | count) < 0 || index + count > text.length
- || count > widths.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // FIXME: handle multi-char characters.
- // Need to figure out if the lengths of the width array takes into account
- // multi-char characters.
- for (int i = 0; i < count; i++) {
- char c = text[i + index];
- boolean found = false;
- for (FontInfo info : mFonts) {
- if (info.mFont.canDisplay(c)) {
- widths[i] = info.mMetrics.charWidth(c);
- found = true;
- break;
- }
- }
-
- if (found == false) {
- // we stop there.
- return i;
- }
- }
-
- return count;
- }
-
- return 0;
- }
-
- /**
- * Return the advance widths for the characters in the string.
- *
- * @param text The text to measure
- * @param start The index of the first char to to measure
- * @param end The end of the text slice to measure
- * @param widths array to receive the advance widths of the characters.
- * Must be at least a large as the text.
- * @return the number of unichars in the specified text.
- */
- @Override
- public int getTextWidths(String text, int start, int end, float[] widths) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (end - start > widths.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- return getTextWidths(text.toCharArray(), start, end - start, widths);
- }
-
- /*
- * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
- * instead of an _Original_Paint
- */
- @Override
- public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
- if (text instanceof String) {
- return getTextWidths((String)text, start, end, widths);
- }
- if (text instanceof SpannedString || text instanceof SpannableString) {
- return getTextWidths(text.toString(), start, end, widths);
- }
- if (text instanceof SpannableStringBuilder) {
- return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
- }
-
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- int result = getTextWidths(buf, 0, end - start, widths);
- TemporaryBuffer.recycle(buf);
- return result;
- }
-
- @Override
- public int getTextWidths(String text, float[] widths) {
- return super.getTextWidths(text, widths);
- }
-
- /**
- * Return the path (outline) for the specified text.
- * Note: just like Canvas.drawText, this will respect the Align setting in
- * the paint.
- *
- * @param text The text to retrieve the path from
- * @param index The index of the first character in text
- * @param count The number of characterss starting with index
- * @param x The x coordinate of the text's origin
- * @param y The y coordinate of the text's origin
- * @param path The path to receive the data describing the text. Must
- * be allocated by the caller.
- */
- @Override
- public void getTextPath(char[] text, int index, int count,
- float x, float y, Path path) {
-
- // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
-
- if ((index | count) < 0 || index + count > text.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
-
- throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
- }
-
- /**
- * Return the path (outline) for the specified text.
- * Note: just like Canvas.drawText, this will respect the Align setting
- * in the paint.
- *
- * @param text The text to retrieve the path from
- * @param start The first character in the text
- * @param end 1 past the last charcter in the text
- * @param x The x coordinate of the text's origin
- * @param y The y coordinate of the text's origin
- * @param path The path to receive the data describing the text. Must
- * be allocated by the caller.
- */
- @Override
- public void getTextPath(String text, int start, int end,
- float x, float y, Path path) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
-
- getTextPath(text.toCharArray(), start, end - start, x, y, path);
- }
-
- /**
- * Return in bounds (allocated by the caller) the smallest rectangle that
- * encloses all of the characters, with an implied origin at (0,0).
- *
- * @param text String to measure and return its bounds
- * @param start Index of the first char in the string to measure
- * @param end 1 past the last char in the string measure
- * @param bounds Returns the unioned bounds of all the text. Must be
- * allocated by the caller.
- */
- @Override
- public void getTextBounds(String text, int start, int end, Rect bounds) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (bounds == null) {
- throw new NullPointerException("need bounds Rect");
- }
-
- getTextBounds(text.toCharArray(), start, end - start, bounds);
- }
-
- /**
- * Return in bounds (allocated by the caller) the smallest rectangle that
- * encloses all of the characters, with an implied origin at (0,0).
- *
- * @param text Array of chars to measure and return their unioned bounds
- * @param index Index of the first char in the array to measure
- * @param count The number of chars, beginning at index, to measure
- * @param bounds Returns the unioned bounds of all the text. Must be
- * allocated by the caller.
- */
- @Override
- public void getTextBounds(char[] text, int index, int count, Rect bounds) {
- // FIXME
- if (mFonts.size() > 0) {
- if ((index | count) < 0 || index + count > text.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- if (bounds == null) {
- throw new NullPointerException("need bounds Rect");
- }
-
- FontInfo mainInfo = mFonts.get(0);
-
- Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
- bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
- }
- }
-
- public static void finalizer(int foo) {
- // pass
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
new file mode 100644
index 0000000..e8079ed
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.DelegateManager;
+
+import android.graphics.Paint.FontMetrics;
+import android.graphics.Paint.FontMetricsInt;
+
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Paint
+ *
+ * Through the layoutlib_create tool, the original native methods of Paint have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Paint class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Paint_Delegate {
+
+ /**
+ * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+ */
+ public static final class FontInfo {
+ Font mFont;
+ java.awt.FontMetrics mMetrics;
+ }
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Paint_Delegate> sManager =
+ new DelegateManager<Paint_Delegate>();
+
+ // ---- delegate helper data ----
+ private List<FontInfo> mFonts;
+ private final FontRenderContext mFontContext = new FontRenderContext(
+ new AffineTransform(), true, true);
+
+ // ---- delegate data ----
+ private int mFlags;
+ private int mColor;
+ private int mStyle;
+ private int mCap;
+ private int mJoin;
+ private int mAlign;
+ private int mTypeface;
+ private float mStrokeWidth;
+ private float mStrokeMiter;
+ private float mTextSize;
+ private float mTextScaleX;
+ private float mTextSkewX;
+
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns the list of {@link Font} objects. The first item is the main font, the rest
+ * are fall backs for characters not present in the main font.
+ */
+ public List<FontInfo> getFonts() {
+ return mFonts;
+ }
+
+
+ // ---- native methods ----
+
+ /*package*/ static int getFlags(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mFlags;
+ }
+
+ /*package*/ static void setFlags(Paint thisPaint, int flags) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mFlags = flags;
+ }
+
+ /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
+ setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
+ }
+
+ /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
+ setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
+ }
+
+ /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
+ setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
+ }
+
+ /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
+ setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
+ }
+
+ /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
+ setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
+ }
+
+ /*package*/ static void setDither(Paint thisPaint, boolean dither) {
+ setFlag(thisPaint, Paint.DITHER_FLAG, dither);
+ }
+
+ /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
+ setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
+ }
+
+ /*package*/ static int getColor(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mColor;
+ }
+
+ /*package*/ static void setColor(Paint thisPaint, int color) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mColor = color;
+ }
+
+ /*package*/ static int getAlpha(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mColor >>> 24;
+ }
+
+ /*package*/ static void setAlpha(Paint thisPaint, int a) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF);
+ }
+
+ /*package*/ static float getStrokeWidth(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 1.f;
+ }
+
+ return delegate.mStrokeWidth;
+ }
+
+ /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mStrokeWidth = width;
+ }
+
+ /*package*/ static float getStrokeMiter(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 1.f;
+ }
+
+ return delegate.mStrokeMiter;
+ }
+
+ /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mStrokeMiter = miter;
+ }
+
+ /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+ int color) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static float getTextSize(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 1.f;
+ }
+
+ return delegate.mTextSize;
+ }
+
+ /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mTextSize = textSize;
+ }
+
+ /*package*/ static float getTextScaleX(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 1.f;
+ }
+
+ return delegate.mTextScaleX;
+ }
+
+ /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mTextScaleX = scaleX;
+ }
+
+ /*package*/ static float getTextSkewX(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 1.f;
+ }
+
+ return delegate.mTextSkewX;
+ }
+
+ /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mTextSkewX = skewX;
+ }
+
+ /*package*/ static float ascent(Paint thisPaint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static float descent(Paint thisPaint) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
+ int count) {
+ // WARNING: the logic in this method is similar to Canvas.drawText.
+ // Any change to this method should be reflected in Canvas.drawText
+
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ FontInfo mainFont = delegate.mFonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ float total = 0f;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // shortcut to exit
+ return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
+ } else if (upTo > 0) {
+ total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+ i = upTo;
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < delegate.mFonts.size() ; f++) {
+ FontInfo fontInfo = delegate.mFonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ total += fontInfo.mMetrics.charsWidth(text, i, charCount);
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, measure it with the main font.
+ if (foundFont == false) {
+ int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ total += mainFont.mMetrics.charsWidth(text, i, size);
+ i += size;
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
+ return native_measureText(thisPaint, text.toCharArray(), start, end - start);
+ }
+
+ /*package*/ static float native_measureText(Paint thisPaint, String text) {
+ return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
+ }
+
+ /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
+ float maxWidth, float[] measuredWidth) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
+ float maxWidth, float[] measuredWidth) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static int native_init() {
+ Paint_Delegate newDelegate = new Paint_Delegate();
+ return sManager.addDelegate(newDelegate);
+ }
+
+ /*package*/ static int native_initWithPaint(int paint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(paint);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ Paint_Delegate newDelegate = new Paint_Delegate(delegate);
+ return sManager.addDelegate(newDelegate);
+ }
+
+ /*package*/ static void native_reset(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.reset();
+ }
+
+ /*package*/ static void native_set(int native_dst, int native_src) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
+ if (delegate_dst == null) {
+ assert false;
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate delegate_src = sManager.getDelegate(native_src);
+ if (delegate_src == null) {
+ assert false;
+ return;
+ }
+
+ delegate_dst.set(delegate_src);
+ }
+
+ /*package*/ static int native_getStyle(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mStyle;
+ }
+
+ /*package*/ static void native_setStyle(int native_object, int style) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mStyle = style;
+ }
+
+ /*package*/ static int native_getStrokeCap(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mCap;
+ }
+
+ /*package*/ static void native_setStrokeCap(int native_object, int cap) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mCap = cap;
+ }
+
+ /*package*/ static int native_getStrokeJoin(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mJoin;
+ }
+
+ /*package*/ static void native_setStrokeJoin(int native_object, int join) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mJoin = join;
+ }
+
+ /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_setShader(int native_object, int shader) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_setColorFilter(int native_object, int filter) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_setXfermode(int native_object, int xfermode) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_setPathEffect(int native_object, int effect) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_setTypeface(int native_object, int typeface) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mTypeface = typeface;
+ }
+
+ /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+
+ /*package*/ static int native_getTextAlign(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mAlign;
+ }
+
+ /*package*/ static void native_setTextAlign(int native_object, int align) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.mAlign = align;
+ }
+
+ /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
+ int count, float[] widths) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_getTextWidths(int native_object, String text, int start,
+ int end, float[] widths) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static float native_getTextRunAdvances(int native_object,
+ char[] text, int index, int count, int contextIndex, int contextCount,
+ int flags, float[] advances, int advancesIndex) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static float native_getTextRunAdvances(int native_object,
+ String text, int start, int end, int contextStart, int contextEnd,
+ int flags, float[] advances, int advancesIndex) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
+ int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
+ int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
+ char[] text, int index, int count, float x, float y, int path) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
+ String text, int start, int end, float x, float y, int path) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
+ int end, Rect bounds) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
+ int count, Rect bounds) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ /*package*/ static void finalizer(int nativePaint) {
+ sManager.removeDelegate(nativePaint);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private Paint_Delegate() {
+ reset();
+
+ mTypeface = Typeface.sDefaults[0].native_instance;
+ updateFontObject();
+ }
+
+ private Paint_Delegate(Paint_Delegate paint) {
+ set(paint);
+ updateFontObject();
+ }
+
+ private void set(Paint_Delegate paint) {
+ mFlags = paint.mFlags;
+ mColor = paint.mColor;
+ mStyle = paint.mStyle;
+ mCap = paint.mCap;
+ mJoin = paint.mJoin;
+ mAlign = paint.mAlign;
+ mTypeface = paint.mTypeface;
+ mStrokeWidth = paint.mStrokeWidth;
+ mStrokeMiter = paint.mStrokeMiter;
+ mTextSize = paint.mTextSize;
+ mTextScaleX = paint.mTextScaleX;
+ mTextSkewX = paint.mTextSkewX;
+ }
+
+ private void reset() {
+ mFlags = Paint.DEFAULT_PAINT_FLAGS;
+ mColor = 0;
+ mStyle = 0;
+ mCap = 0;
+ mJoin = 0;
+ mAlign = 0;
+ mTypeface = 0;
+ mStrokeWidth = 1.f;
+ mStrokeMiter = 2.f;
+ mTextSize = 20.f;
+ mTextScaleX = 1.f;
+ mTextSkewX = 0.f;
+ }
+
+ /**
+ * Update the {@link Font} object from the typeface, text size and scaling
+ */
+ private void updateFontObject() {
+ if (mTypeface != 0) {
+ // Get the fonts from the TypeFace object.
+ List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
+
+ // create new font objects as well as FontMetrics, based on the current text size
+ // and skew info.
+ ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
+ for (Font font : fonts) {
+ FontInfo info = new FontInfo();
+ info.mFont = font.deriveFont(mTextSize);
+ if (mTextScaleX != 1.0 || mTextSkewX != 0) {
+ // TODO: support skew
+ info.mFont = info.mFont.deriveFont(new AffineTransform(
+ mTextScaleX, mTextSkewX, 0, 0, 1, 0));
+ }
+ info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
+
+ infoList.add(info);
+ }
+
+ mFonts = Collections.unmodifiableList(infoList);
+ }
+ }
+
+ private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ if (flagValue) {
+ delegate.mFlags |= flagMask;
+ } else {
+ delegate.mFlags &= ~flagMask;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 248bdab..7e90e7d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -72,7 +72,11 @@ public final class Typeface_Delegate {
}
public static List<Font> getFonts(Typeface typeface) {
- Typeface_Delegate delegate = sManager.getDelegate(typeface.native_instance);
+ return getFonts(typeface.native_instance);
+ }
+
+ public static List<Font> getFonts(int native_int) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_int);
if (delegate == null) {
assert false;
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 9eb83c8..cdb4148 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -24,6 +24,7 @@ import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
import com.android.layoutlib.api.IXmlPullParser;
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo;
import com.android.ninepatch.NinePatch;
@@ -33,7 +34,9 @@ import com.android.tools.layoutlib.create.OverrideMethod;
import android.content.ClipData;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
+import android.graphics.Canvas_Delegate;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Typeface_Delegate;
@@ -64,6 +67,7 @@ import android.widget.FrameLayout;
import android.widget.TabHost;
import android.widget.TabWidget;
+import java.awt.image.BufferedImage;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -450,13 +454,28 @@ public final class Bridge implements ILayoutBridge {
view.layout(0, screenOffset, screenWidth, screenHeight);
// draw the views
- Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger);
+ // create the BufferedImage into which the layout will be rendered.
+ BufferedImage image = new BufferedImage(screenWidth, screenHeight - screenOffset,
+ BufferedImage.TYPE_INT_ARGB);
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(image, Density.getEnum(density));
+
+ // create a Canvas around the Android bitmap
+ Canvas canvas = new Canvas(bitmap);
+
+ // to set the logger, get the native delegate
+ Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
+ canvasDelegate.setLogger(logger);
+
root.draw(canvas);
- canvas.dispose();
+ canvasDelegate.dispose();
+
+ return new LayoutResult(
+ visit(((ViewGroup)view).getChildAt(0), context),
+ image);
- return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
- canvas.getImage());
} catch (PostInflateException e) {
return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
+ e.getMessage());
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
index abbf2f0..2c92567 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
@@ -19,6 +19,7 @@ package com.android.layoutlib.bridge;
import com.android.ninepatch.NinePatch;
import android.graphics.Canvas;
+import android.graphics.Canvas_Delegate;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -80,7 +81,8 @@ public class NinePatchDrawable extends Drawable {
@Override
public void draw(Canvas canvas) {
Rect r = getBounds();
- m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height());
+ Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
+ m9Patch.draw(canvasDelegate.getGraphics2d(), r.left, r.top, r.width(), r.height());
return;
}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
index 6e14e82..ba3c51a 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
@@ -17,8 +17,6 @@
package com.android.layoutlib.bridge;
import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics._Original_Paint;
import android.text.TextPaint;
import junit.framework.TestCase;
@@ -58,14 +56,6 @@ public class AndroidGraphicsTests extends TestCase {
}
}
- public void testPaint() {
- _Original_Paint o = new _Original_Paint();
- assertNotNull(o);
-
- Paint p = new Paint();
- assertNotNull(p);
- }
-
public void textTextPaint() {
TextPaint p = new TextPaint();
assertNotNull(p);
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
index 7c1eecd..a86b5c9 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
@@ -87,7 +87,11 @@ public class TestNativeDelegate extends TestCase {
try {
// try to load the method with the given parameter types.
- delegateClass.getDeclaredMethod(originalMethod.getName(), parameters);
+ Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(),
+ parameters);
+
+ // check that the method is static
+ assertTrue((delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
} catch (NoSuchMethodException e) {
// compute a full class name that's long but not too long.
StringBuilder sb = new StringBuilder(originalMethod.getName() + "(");
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 0ecb474..c845cc4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -104,7 +104,9 @@ public final class CreateInfo implements ICreateInfo {
*/
private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
"android.graphics.Bitmap",
+ "android.graphics.Canvas",
"android.graphics.Matrix",
+ "android.graphics.Paint",
"android.graphics.Typeface",
};
@@ -126,11 +128,9 @@ public final class CreateInfo implements ICreateInfo {
new String[] {
"android.graphics.BitmapFactory", "android.graphics._Original_BitmapFactory",
"android.graphics.BitmapShader", "android.graphics._Original_BitmapShader",
- "android.graphics.Canvas", "android.graphics._Original_Canvas",
"android.graphics.ComposeShader", "android.graphics._Original_ComposeShader",
"android.graphics.DashPathEffect", "android.graphics._Original_DashPathEffect",
"android.graphics.LinearGradient", "android.graphics._Original_LinearGradient",
- "android.graphics.Paint", "android.graphics._Original_Paint",
"android.graphics.Path", "android.graphics._Original_Path",
"android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode",
"android.graphics.RadialGradient", "android.graphics._Original_RadialGradient",
@@ -150,13 +150,6 @@ public final class CreateInfo implements ICreateInfo {
*/
private final static String[] DELETE_RETURNS =
new String[] {
- "android.graphics.Paint", // class to delete methods from
- "android.graphics.Paint$Align", // list of type identifying methods to delete
- "android.graphics.Paint$Style",
- "android.graphics.Paint$Join",
- "android.graphics.Paint$Cap",
- "android.graphics.Paint$FontMetrics",
- "android.graphics.Paint$FontMetricsInt",
null }; // separator, for next class/methods list.
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
index 21d6682..c7968a4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -169,7 +169,7 @@ class DelegateMethodAdapter implements MethodVisitor {
// Construct the descriptor of the delegate. For a static method, it's the same
// however for an instance method we need to pass the 'this' reference first
String desc = mDesc;
- if (!mIsStatic && argTypes.length > 0) {
+ if (!mIsStatic) {
Type[] argTypes2 = new Type[argTypes.length + 1];
argTypes2[0] = Type.getObjectType(mClassName);