summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/13.txt80
-rw-r--r--api/current.txt91
-rw-r--r--core/java/android/animation/AnimatorInflater.java6
-rw-r--r--core/java/android/hardware/Camera.java19
-rw-r--r--core/java/android/net/ConnectivityManager.java11
-rw-r--r--core/java/android/preference/MultiSelectListPreference.java6
-rw-r--r--core/java/android/provider/Settings.java16
-rw-r--r--core/java/android/text/GraphicsOperations.java4
-rw-r--r--core/java/android/text/SpannableStringBuilder.java16
-rw-r--r--core/java/android/view/Display.java23
-rw-r--r--core/java/android/view/InputEventConsistencyVerifier.java19
-rw-r--r--core/java/android/view/View.java44
-rw-r--r--core/java/android/view/ViewConfiguration.java22
-rw-r--r--core/java/android/view/ViewGroup.java54
-rw-r--r--core/java/android/view/ViewParent.java19
-rw-r--r--core/java/android/view/ViewRoot.java8
-rw-r--r--core/java/android/view/WindowManagerPolicy.java9
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java470
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java36
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java415
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl2
-rw-r--r--core/java/android/widget/AbsListView.java12
-rw-r--r--core/java/android/widget/AdapterView.java28
-rw-r--r--core/java/android/widget/CheckedTextView.java9
-rw-r--r--core/java/android/widget/CompoundButton.java26
-rw-r--r--core/java/android/widget/DatePicker.java7
-rw-r--r--core/java/android/widget/ListView.java40
-rw-r--r--core/java/android/widget/ProgressBar.java10
-rw-r--r--core/java/android/widget/TabWidget.java15
-rw-r--r--core/java/android/widget/TextView.java190
-rw-r--r--core/java/android/widget/TimePicker.java5
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java4
-rw-r--r--core/java/com/android/internal/view/menu/BaseMenuPresenter.java4
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java4
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java32
-rw-r--r--core/jni/android/graphics/Paint.cpp58
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/layout-large/action_bar_home.xml39
-rw-r--r--core/res/res/layout-large/action_mode_close_item.xml38
-rw-r--r--core/res/res/layout/action_bar_home.xml13
-rw-r--r--core/res/res/layout/action_menu_item_layout.xml10
-rw-r--r--core/res/res/layout/action_mode_close_item.xml14
-rw-r--r--core/res/res/values-land/dimens.xml4
-rw-r--r--core/res/res/values-large/dimens.xml6
-rw-r--r--core/res/res/values-port/dimens.xml24
-rw-r--r--core/res/res/values-w480dp/bools.xml21
-rw-r--r--core/res/res/values-zh-rTW/strings.xml20
-rw-r--r--core/res/res/values/bools.xml21
-rw-r--r--core/res/res/values/dimens.xml7
-rw-r--r--core/res/res/values/themes.xml6
-rw-r--r--data/etc/platform.xml4
-rw-r--r--docs/html/guide/topics/ui/actionbar.jd5
-rw-r--r--graphics/java/android/graphics/Paint.java181
-rw-r--r--graphics/jni/android_renderscript_RenderScript.cpp36
-rw-r--r--include/camera/CameraParameters.h21
-rw-r--r--include/media/mediascanner.h5
-rw-r--r--keystore/java/android/security/Credentials.java4
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl31
-rw-r--r--keystore/java/android/security/KeyChain.java372
-rw-r--r--libs/hwui/OpenGLRenderer.cpp5
-rw-r--r--libs/hwui/ProgramCache.h5
-rw-r--r--libs/rs/driver/rsdRuntimeMath.cpp6
-rw-r--r--libs/rs/rs.spec31
-rw-r--r--libs/rs/rsAllocation.cpp2
-rw-r--r--libs/rs/rsContext.cpp6
-rw-r--r--libs/rs/rsElement.cpp9
-rw-r--r--libs/rs/rsFont.cpp11
-rw-r--r--libs/rs/rsHandcode.h16
-rw-r--r--libs/rs/rsMatrix4x4.cpp7
-rw-r--r--libs/rs/rsMatrix4x4.h1
-rw-r--r--libs/rs/rsScriptC.cpp7
-rw-r--r--libs/rs/spec.l14
-rw-r--r--media/java/android/media/MediaScanner.java192
-rw-r--r--media/java/android/media/MediaScannerClient.java5
-rw-r--r--media/jni/android_media_MediaScanner.cpp29
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp42
-rwxr-xr-xmedia/jni/mediaeditor/VideoBrowserInternal.h2
-rwxr-xr-xmedia/jni/mediaeditor/VideoBrowserMain.c4
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorClasses.cpp3
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorMain.cpp151
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorOsal.cpp15
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorPropertiesMain.cpp2
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorThumbnailMain.cpp6
-rw-r--r--media/libmedia/IMediaPlayer.cpp9
-rw-r--r--media/libmedia/MediaScanner.cpp24
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp14
-rw-r--r--media/libstagefright/XINGSeeker.cpp2
-rw-r--r--media/mtp/MtpDatabase.h3
-rw-r--r--media/mtp/MtpDebug.cpp6
-rw-r--r--media/mtp/MtpServer.cpp226
-rw-r--r--media/mtp/MtpServer.h33
-rw-r--r--media/mtp/mtp.h13
-rwxr-xr-xopengl/libs/GLES2_dbg/generate_api_cpp.py8
-rwxr-xr-xopengl/libs/GLES2_dbg/generate_debugger_message_proto.py4
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java12
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java20
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityInputFilter.java65
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java74
-rw-r--r--services/java/com/android/server/accessibility/TouchExplorer.java1540
-rw-r--r--services/java/com/android/server/wm/InputFilter.java6
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java190
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestView.java3
-rw-r--r--tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml4
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpgbin76367 -> 0 bytes
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/drawable/city.pngbin0 -> 611708 bytes
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpgbin76367 -> 0 bytes
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/layout/main.xml43
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java182
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs2
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs2
111 files changed, 4285 insertions, 1476 deletions
diff --git a/Android.mk b/Android.mk
index cd9ae7d..898d7e2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -158,6 +158,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/view/IInputMethodSession.aidl \
core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
+ keystore/java/android/security/IKeyChainService.aidl \
location/java/android/location/ICountryDetector.aidl \
location/java/android/location/ICountryListener.aidl \
location/java/android/location/IGeocodeProvider.aidl \
diff --git a/api/13.txt b/api/13.txt
index cbc2c40..a17b80c 100644
--- a/api/13.txt
+++ b/api/13.txt
@@ -21945,49 +21945,24 @@ package android.view {
package android.view.accessibility {
- public final class AccessibilityEvent implements android.os.Parcelable {
+ public final class AccessibilityEvent extends android.view.accessibility.AccessibilityRecord implements android.os.Parcelable {
+ method public void appendRecord(android.view.accessibility.AccessibilityRecord);
method public int describeContents();
- method public int getAddedCount();
- method public java.lang.CharSequence getBeforeText();
- method public java.lang.CharSequence getClassName();
- method public java.lang.CharSequence getContentDescription();
- method public int getCurrentItemIndex();
method public long getEventTime();
method public int getEventType();
- method public int getFromIndex();
- method public int getItemCount();
method public java.lang.CharSequence getPackageName();
- method public android.os.Parcelable getParcelableData();
- method public int getRemovedCount();
- method public java.util.List<java.lang.CharSequence> getText();
+ method public android.view.accessibility.AccessibilityRecord getRecord(int);
+ method public int getRecordCount();
method public void initFromParcel(android.os.Parcel);
- method public boolean isChecked();
- method public boolean isEnabled();
- method public boolean isFullScreen();
- method public boolean isPassword();
method public static android.view.accessibility.AccessibilityEvent obtain(int);
method public static android.view.accessibility.AccessibilityEvent obtain();
- method public void recycle();
- method public void setAddedCount(int);
- method public void setBeforeText(java.lang.CharSequence);
- method public void setChecked(boolean);
- method public void setClassName(java.lang.CharSequence);
- method public void setContentDescription(java.lang.CharSequence);
- method public void setCurrentItemIndex(int);
- method public void setEnabled(boolean);
method public void setEventTime(long);
method public void setEventType(int);
- method public void setFromIndex(int);
- method public void setFullScreen(boolean);
- method public void setItemCount(int);
method public void setPackageName(java.lang.CharSequence);
- method public void setParcelableData(android.os.Parcelable);
- method public void setPassword(boolean);
- method public void setRemovedCount(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int INVALID_POSITION = -1; // 0xffffffff
- field public static final int MAX_TEXT_LENGTH = 500; // 0x1f4
+ field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4
field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40
field public static final int TYPE_VIEW_CLICKED = 1; // 0x1
@@ -22010,6 +21985,51 @@ package android.view.accessibility {
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
+ public class AccessibilityRecord {
+ ctor protected AccessibilityRecord();
+ method protected void clear();
+ method public int getAddedCount();
+ method public java.lang.CharSequence getBeforeText();
+ method public boolean getBooleanProperty(int);
+ method public java.lang.CharSequence getClassName();
+ method public java.lang.CharSequence getContentDescription();
+ method public int getCurrentItemIndex();
+ method public int getFromIndex();
+ method public int getItemCount();
+ method public android.os.Parcelable getParcelableData();
+ method public int getRemovedCount();
+ method public java.util.List<java.lang.CharSequence> getText();
+ method public boolean isChecked();
+ method public boolean isEnabled();
+ method public boolean isFullScreen();
+ method public boolean isPassword();
+ method protected static android.view.accessibility.AccessibilityRecord obtain();
+ method public void recycle();
+ method public void setAddedCount(int);
+ method public void setBeforeText(java.lang.CharSequence);
+ method public void setChecked(boolean);
+ method public void setClassName(java.lang.CharSequence);
+ method public void setContentDescription(java.lang.CharSequence);
+ method public void setCurrentItemIndex(int);
+ method public void setEnabled(boolean);
+ method public void setFromIndex(int);
+ method public void setFullScreen(boolean);
+ method public void setItemCount(int);
+ method public void setParcelableData(android.os.Parcelable);
+ method public void setPassword(boolean);
+ method public void setRemovedCount(int);
+ field protected int mAddedCount;
+ field protected java.lang.CharSequence mBeforeText;
+ field protected int mBooleanProperties;
+ field protected java.lang.CharSequence mClassName;
+ field protected java.lang.CharSequence mContentDescription;
+ field protected int mCurrentItemIndex;
+ field protected int mFromIndex;
+ field protected int mItemCount;
+ field protected android.os.Parcelable mParcelableData;
+ field protected int mRemovedCount;
+ field protected final java.util.List mText;
+ }
}
package android.view.animation {
diff --git a/api/current.txt b/api/current.txt
index c7e6ee6..8ec7732 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10778,6 +10778,9 @@ package android.net {
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
field public static final java.lang.String EXTRA_REASON = "reason";
+ field public static final int TYPE_BLUETOOTH = 7; // 0x7
+ field public static final int TYPE_DUMMY = 8; // 0x8
+ field public static final int TYPE_ETHERNET = 9; // 0x9
field public static final int TYPE_MOBILE = 0; // 0x0
field public static final int TYPE_MOBILE_DUN = 4; // 0x4
field public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
@@ -21174,6 +21177,7 @@ package android.view {
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
method protected void onOverScrolled(int, int, boolean, boolean);
+ method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method protected void onRestoreInstanceState(android.os.Parcelable);
method protected android.os.Parcelable onSaveInstanceState();
method protected void onScrollChanged(int, int, int, int);
@@ -21585,6 +21589,7 @@ package android.view {
method public boolean onInterceptTouchEvent(android.view.MotionEvent);
method protected abstract void onLayout(boolean, int, int, int, int);
method protected boolean onRequestFocusInDescendants(int, android.graphics.Rect);
+ method public boolean onRequestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void recomputeViewAttributes(android.view.View);
method public void removeAllViews();
method public void removeAllViewsInLayout();
@@ -21597,6 +21602,7 @@ package android.view {
method public void requestChildFocus(android.view.View, android.view.View);
method public boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
method public void requestDisallowInterceptTouchEvent(boolean);
+ method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void requestTransparentRegion(android.view.View);
method public void scheduleLayoutAnimation();
method public void setAddStatesFromChildren(boolean);
@@ -21683,6 +21689,7 @@ package android.view {
method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
method public abstract void requestDisallowInterceptTouchEvent(boolean);
method public abstract void requestLayout();
+ method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public abstract void requestTransparentRegion(android.view.View);
method public abstract boolean showContextMenuForChild(android.view.View);
method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
@@ -22028,53 +22035,32 @@ package android.view {
package android.view.accessibility {
- public final class AccessibilityEvent implements android.os.Parcelable {
+ public final class AccessibilityEvent extends android.view.accessibility.AccessibilityRecord implements android.os.Parcelable {
+ method public void appendRecord(android.view.accessibility.AccessibilityRecord);
method public int describeContents();
- method public int getAddedCount();
- method public java.lang.CharSequence getBeforeText();
- method public java.lang.CharSequence getClassName();
- method public java.lang.CharSequence getContentDescription();
- method public int getCurrentItemIndex();
method public long getEventTime();
method public int getEventType();
- method public int getFromIndex();
- method public int getItemCount();
method public java.lang.CharSequence getPackageName();
- method public android.os.Parcelable getParcelableData();
- method public int getRemovedCount();
- method public java.util.List<java.lang.CharSequence> getText();
+ method public android.view.accessibility.AccessibilityRecord getRecord(int);
+ method public int getRecordCount();
method public void initFromParcel(android.os.Parcel);
- method public boolean isChecked();
- method public boolean isEnabled();
- method public boolean isFullScreen();
- method public boolean isPassword();
method public static android.view.accessibility.AccessibilityEvent obtain(int);
method public static android.view.accessibility.AccessibilityEvent obtain();
- method public void recycle();
- method public void setAddedCount(int);
- method public void setBeforeText(java.lang.CharSequence);
- method public void setChecked(boolean);
- method public void setClassName(java.lang.CharSequence);
- method public void setContentDescription(java.lang.CharSequence);
- method public void setCurrentItemIndex(int);
- method public void setEnabled(boolean);
method public void setEventTime(long);
method public void setEventType(int);
- method public void setFromIndex(int);
- method public void setFullScreen(boolean);
- method public void setItemCount(int);
method public void setPackageName(java.lang.CharSequence);
- method public void setParcelableData(android.os.Parcelable);
- method public void setPassword(boolean);
- method public void setRemovedCount(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int INVALID_POSITION = -1; // 0xffffffff
field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4
field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40
+ field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
field public static final int TYPE_VIEW_CLICKED = 1; // 0x1
field public static final int TYPE_VIEW_FOCUSED = 8; // 0x8
+ field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
field public static final int TYPE_VIEW_LONG_CLICKED = 2; // 0x2
field public static final int TYPE_VIEW_SELECTED = 4; // 0x4
field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10
@@ -22088,11 +22074,58 @@ package android.view.accessibility {
public final class AccessibilityManager {
method public java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
+ method public java.util.List<android.content.pm.ServiceInfo> getEnabledAccessibilityServiceList(int);
method public void interrupt();
method public boolean isEnabled();
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
+ public class AccessibilityRecord {
+ ctor protected AccessibilityRecord();
+ method protected void clear();
+ method public int getAddedCount();
+ method public java.lang.CharSequence getBeforeText();
+ method public boolean getBooleanProperty(int);
+ method public java.lang.CharSequence getClassName();
+ method public java.lang.CharSequence getContentDescription();
+ method public int getCurrentItemIndex();
+ method public int getFromIndex();
+ method public int getItemCount();
+ method public android.os.Parcelable getParcelableData();
+ method public int getRemovedCount();
+ method public java.util.List<java.lang.CharSequence> getText();
+ method public boolean isChecked();
+ method public boolean isEnabled();
+ method public boolean isFullScreen();
+ method public boolean isPassword();
+ method protected static android.view.accessibility.AccessibilityRecord obtain();
+ method public void recycle();
+ method public void setAddedCount(int);
+ method public void setBeforeText(java.lang.CharSequence);
+ method public void setChecked(boolean);
+ method public void setClassName(java.lang.CharSequence);
+ method public void setContentDescription(java.lang.CharSequence);
+ method public void setCurrentItemIndex(int);
+ method public void setEnabled(boolean);
+ method public void setFromIndex(int);
+ method public void setFullScreen(boolean);
+ method public void setItemCount(int);
+ method public void setParcelableData(android.os.Parcelable);
+ method public void setPassword(boolean);
+ method public void setRemovedCount(int);
+ field protected int mAddedCount;
+ field protected java.lang.CharSequence mBeforeText;
+ field protected int mBooleanProperties;
+ field protected java.lang.CharSequence mClassName;
+ field protected java.lang.CharSequence mContentDescription;
+ field protected int mCurrentItemIndex;
+ field protected int mFromIndex;
+ field protected int mItemCount;
+ field protected android.os.Parcelable mParcelableData;
+ field protected int mRemovedCount;
+ field protected final java.util.List mText;
+ }
+
}
package android.view.animation {
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index bcab66e..ed4036d 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -31,11 +31,11 @@ import java.io.IOException;
import java.util.ArrayList;
/**
- * This class is used to instantiate menu XML files into Animator objects.
+ * This class is used to instantiate animator XML files into Animator objects.
* <p>
- * For performance reasons, menu inflation relies heavily on pre-processing of
+ * For performance reasons, inflation relies heavily on pre-processing of
* XML files that is done at build time. Therefore, it is not currently possible
- * to use MenuInflater with an XmlPullParser over a plain XML file at runtime;
+ * to use this inflater with an XmlPullParser over a plain XML file at runtime;
* it only works with an XmlPullParser returned from a compiled resource (R.
* <em>something</em> file.)
*/
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 328a55b..77c2d1b 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -2600,10 +2600,12 @@ public class Camera {
* (1000, 1000) is the lower right point. The length and width of focus
* areas cannot be 0 or negative.
*
- * The weight ranges from 1 to 1000. The sum of the weights of all focus
- * areas must be 1000. Focus areas can partially overlap and the driver
- * will add the weights in the overlap region. But apps should not set
- * two focus areas that have identical coordinates.
+ * The weight must range from 1 to 1000. The weight should be
+ * interpreted as a per-pixel weight - all pixels in the area have the
+ * specified weight. This means a small area with the same weight as a
+ * larger area will have less influence on the focusing than the larger
+ * area. Focus areas can partially overlap and the driver will add the
+ * weights in the overlap region.
*
* A special case of all-zero single focus area means driver to decide
* the focus area. For example, the driver may use more signals to
@@ -2668,10 +2670,11 @@ public class Camera {
* point. (1000, 1000) is the lower right point. The length and width of
* metering areas cannot be 0 or negative.
*
- * The weight ranges from 1 to 1000. The sum of the weights of all
- * metering areas must be 1000. Metering areas can partially overlap and
- * the driver will add the weights in the overlap region. But apps
- * should not set two metering areas that have identical coordinates.
+ * The weight must range from 1 to 1000, and represents a weight for
+ * every pixel in the area. This means that a large metering area with
+ * the same weight as a smaller area will have more effect in the
+ * metering result. Metering areas can partially overlap and the driver
+ * will add the weights in the overlap region.
*
* A special case of all-zero single metering area means driver to
* decide the metering area. For example, the driver may use more
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index b541ec3..419288b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -215,15 +215,20 @@ public class ConnectivityManager
/**
* Bluetooth data connection. This is used for Bluetooth reverse tethering.
- * @hide
*/
public static final int TYPE_BLUETOOTH = 7;
- /** {@hide} */
+ /**
+ * Dummy data connection. This should not be used on shipping devices.
+ */
public static final int TYPE_DUMMY = 8;
- /** {@hide} */
+ /**
+ * Ethernet data connection. This may be via USB dongle or more
+ * traditional means.
+ */
public static final int TYPE_ETHERNET = 9;
+
/**
* Over the air Adminstration.
* {@hide}
diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java
index 42d555c..2e8d551 100644
--- a/core/java/android/preference/MultiSelectListPreference.java
+++ b/core/java/android/preference/MultiSelectListPreference.java
@@ -169,9 +169,9 @@ public class MultiSelectListPreference extends DialogPreference {
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked) {
- mPreferenceChanged |= mNewValues.add(mEntries[which].toString());
+ mPreferenceChanged |= mNewValues.add(mEntryValues[which].toString());
} else {
- mPreferenceChanged |= mNewValues.remove(mEntries[which].toString());
+ mPreferenceChanged |= mNewValues.remove(mEntryValues[which].toString());
}
}
});
@@ -180,7 +180,7 @@ public class MultiSelectListPreference extends DialogPreference {
}
private boolean[] getSelectedItems() {
- final CharSequence[] entries = mEntries;
+ final CharSequence[] entries = mEntryValues;
final int entryCount = entries.length;
final Set<String> values = mValues;
boolean[] result = new boolean[entryCount];
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2f4a4bb..570b801 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3721,6 +3721,22 @@ public final class Settings {
"setup_prepaid_data_service_url";
/**
+ * URL to attempt a GET on to see if this is a prepay device
+ * @hide
+ */
+ public static final String SETUP_PREPAID_DETECTION_TARGET_URL =
+ "setup_prepaid_detection_target_url";
+
+ /**
+ * Host to check for a redirect to after an attempt to GET
+ * SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there,
+ * this is a prepaid device with zero balance.)
+ * @hide
+ */
+ public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
+ "setup_prepaid_detection_redir_host";
+
+ /**
* @hide
*/
public static final String[] SETTINGS_TO_BACKUP = {
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 6e2168b..831ccc5 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -61,8 +61,8 @@ extends CharSequence
* Just like {@link Paint#getTextRunAdvances}.
* @hide
*/
- float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex, Paint paint);
+ float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
+ int flags, float[] advances, int advancesIndex, Paint paint, int reserved);
/**
* Just like {@link Paint#getTextRunCursor}.
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index ff6a4cd..6b2d8e4 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1173,8 +1173,8 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
* Don't call this yourself -- exists for Paint to use internally.
* {@hide}
*/
- public float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd, int flags,
- float[] advances, int advancesPos, Paint p) {
+ public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
+ float[] advances, int advancesPos, Paint p, int reserved) {
float ret;
@@ -1182,16 +1182,16 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
int len = end - start;
if (end <= mGapStart) {
- ret = p.getTextRunAdvancesICU(mText, start, len, contextStart, contextLen,
- flags, advances, advancesPos);
+ ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
+ flags, advances, advancesPos, reserved);
} else if (start >= mGapStart) {
- ret = p.getTextRunAdvancesICU(mText, start + mGapLength, len,
- contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+ ret = p.getTextRunAdvances(mText, start + mGapLength, len,
+ contextStart + mGapLength, contextLen, flags, advances, advancesPos, reserved);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
- ret = p.getTextRunAdvancesICU(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesPos);
+ ret = p.getTextRunAdvances(buf, start - contextStart, len,
+ 0, contextLen, flags, advances, advancesPos, reserved);
TextUtils.recycle(buf);
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 980239b..8e839c0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -200,8 +200,27 @@ public class Display {
* @param outMetrics
*/
public void getMetrics(DisplayMetrics outMetrics) {
- outMetrics.widthPixels = getWidth();
- outMetrics.heightPixels = getHeight();
+ synchronized (mTmpPoint) {
+ getSize(mTmpPoint);
+ outMetrics.widthPixels = mTmpPoint.x;
+ outMetrics.heightPixels = mTmpPoint.y;
+ }
+ getNonSizeMetrics(outMetrics);
+ }
+
+ /**
+ * Initialize a DisplayMetrics object from this display's data.
+ *
+ * @param outMetrics
+ * @hide
+ */
+ public void getRealMetrics(DisplayMetrics outMetrics) {
+ outMetrics.widthPixels = getRealWidth();
+ outMetrics.heightPixels = getRealHeight();
+ getNonSizeMetrics(outMetrics);
+ }
+
+ private void getNonSizeMetrics(DisplayMetrics outMetrics) {
outMetrics.density = mDensity;
outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f);
outMetrics.scaledDensity= outMetrics.density;
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index b5ca2c2..e14b975 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -30,7 +30,6 @@ import android.util.Log;
* @hide
*/
public final class InputEventConsistencyVerifier {
- private static final String TAG = "InputEventConsistencyVerifier";
private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE);
// The number of recent events to log when a problem is detected.
@@ -44,6 +43,11 @@ public final class InputEventConsistencyVerifier {
// Consistency verifier flags.
private final int mFlags;
+ // Tag for logging which a client can set to help distinguish the output
+ // from different verifiers since several can be active at the same time.
+ // If not provided defaults to the simple class name.
+ private final String mLogTag;
+
// The most recently checked event and the nesting level at which it was checked.
// This is only set when the verifier is called from a nesting level greater than 0
// so that the verifier can detect when it has been asked to verify the same event twice.
@@ -103,8 +107,19 @@ public final class InputEventConsistencyVerifier {
* @param flags Flags to the verifier, or 0 if none.
*/
public InputEventConsistencyVerifier(Object caller, int flags) {
+ this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName());
+ }
+
+ /**
+ * Creates an input consistency verifier.
+ * @param caller The object to which the verifier is attached.
+ * @param flags Flags to the verifier, or 0 if none.
+ * @param logTag Tag for logging. If null defaults to the short class name.
+ */
+ public InputEventConsistencyVerifier(Object caller, int flags, String logTag) {
this.mCaller = caller;
this.mFlags = flags;
+ this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier";
}
/**
@@ -596,7 +611,7 @@ public final class InputEventConsistencyVerifier {
}
}
- Log.d(TAG, mViolationMessage.toString());
+ Log.d(mLogTag, mViolationMessage.toString());
mViolationMessage.setLength(0);
tainted = true;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4a62892..4bc7f39 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3455,6 +3455,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (!isShown()) {
return;
}
+
+ // Populate these here since they are related to the View that
+ // sends the event and should not be modified while dispatching
+ // to descendants.
event.setClassName(getClass().getName());
event.setPackageName(getContext().getPackageName());
event.setEnabled(isEnabled());
@@ -3470,22 +3474,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
dispatchPopulateAccessibilityEvent(event);
- AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event);
+ // In the beginning we called #isShown(), so we know that getParent() is not null.
+ getParent().requestSendAccessibilityEvent(this, event);
}
/**
- * Dispatches an {@link AccessibilityEvent} to the {@link View} children
- * to be populated.
+ * Dispatches an {@link AccessibilityEvent} to the {@link View} children to be populated.
+ * This method first calls {@link #onPopulateAccessibilityEvent(AccessibilityEvent)}
+ * on this view allowing it to populate information about itself and also decide
+ * whether to intercept the population i.e. to prevent its children from populating
+ * the event.
*
* @param event The event.
*
* @return True if the event population was completed.
*/
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ onPopulateAccessibilityEvent(event);
return false;
}
/**
+ * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
+ * giving a chance to this View to populate the accessibility evnet with
+ * information about itself.
+ *
+ * @param event The accessibility event which to populate.
+ */
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+
+ }
+
+ /**
* Gets the {@link View} description. It briefly describes the view and is
* primarily used for accessibility support. Set this property to enable
* better accessibility support for your application. This is especially
@@ -5390,20 +5410,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* to receive the hover event.
*/
public boolean onHoverEvent(MotionEvent event) {
- final int viewFlags = mViewFlags;
-
- if (((viewFlags & CLICKABLE) != CLICKABLE &&
- (viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) {
- // Nothing to do if the view is not clickable.
- return false;
- }
-
- if ((viewFlags & ENABLED_MASK) == DISABLED) {
- // A disabled view that is clickable still consumes the hover events, it just doesn't
- // respond to them.
- return true;
- }
-
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
setHovered(true);
@@ -5414,7 +5420,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
break;
}
- return true;
+ return false;
}
/**
@@ -5436,11 +5442,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if ((mPrivateFlags & HOVERED) == 0) {
mPrivateFlags |= HOVERED;
refreshDrawableState();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
}
} else {
if ((mPrivateFlags & HOVERED) != 0) {
mPrivateFlags &= ~HOVERED;
refreshDrawableState();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
}
}
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 739758c..94eb429 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -19,7 +19,6 @@ package android.view;
import android.app.AppGlobals;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.Bundle;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.SparseArray;
@@ -156,6 +155,13 @@ public class ViewConfiguration {
private static final int MAXIMUM_FLING_VELOCITY = 8000;
/**
+ * Distance between a touch up event denoting the end of a touch exploration
+ * gesture and the touch up event of a subsequent tap for the latter tap to be
+ * considered as a tap i.e. to perform a click.
+ */
+ private static final int TOUCH_EXPLORATION_TAP_SLOP = 80;
+
+ /**
* The maximum size of View's drawing cache, expressed in bytes. This size
* should be at least equal to the size of the screen in ARGB888 format.
*/
@@ -185,6 +191,7 @@ public class ViewConfiguration {
private final int mTouchSlop;
private final int mPagingTouchSlop;
private final int mDoubleTapSlop;
+ private final int mScaledTouchExplorationTapSlop;
private final int mWindowTouchSlop;
private final int mMaximumDrawingCacheSize;
private final int mOverscrollDistance;
@@ -206,6 +213,7 @@ public class ViewConfiguration {
mTouchSlop = TOUCH_SLOP;
mPagingTouchSlop = PAGING_TOUCH_SLOP;
mDoubleTapSlop = DOUBLE_TAP_SLOP;
+ mScaledTouchExplorationTapSlop = TOUCH_EXPLORATION_TAP_SLOP;
mWindowTouchSlop = WINDOW_TOUCH_SLOP;
//noinspection deprecation
mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
@@ -242,6 +250,7 @@ public class ViewConfiguration {
mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f);
mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
+ mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
// Size of the screen in bytes, in ARGB_8888 format
@@ -444,6 +453,17 @@ public class ViewConfiguration {
}
/**
+ * @return Distance between a touch up event denoting the end of a touch exploration
+ * gesture and the touch up event of a subsequent tap for the latter tap to be
+ * considered as a tap i.e. to perform a click.
+ *
+ * @hide
+ */
+ public int getScaledTouchExplorationTapSlop() {
+ return mScaledTouchExplorationTapSlop;
+ }
+
+ /**
* @return Distance a touch must be outside the bounds of a window for it
* to be counted as outside the window for purposes of dismissing that
* window.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 08daa28..7b404b4 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -586,6 +586,35 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* {@inheritDoc}
*/
+ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ ViewParent parent = getParent();
+ if (parent == null) {
+ return false;
+ }
+ final boolean propagate = onRequestSendAccessibilityEvent(child, event);
+ if (!propagate) {
+ return false;
+ }
+ return parent.requestSendAccessibilityEvent(this, event);
+ }
+
+ /**
+ * Called when a child has requested sending an {@link AccessibilityEvent} and
+ * gives an opportunity to its parent to augment the event.
+ *
+ * @param child The child which requests sending the event.
+ * @param event The event to be sent.
+ * @return True if the event should be sent.
+ *
+ * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
+ */
+ public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
return mFocused != null &&
@@ -1216,9 +1245,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild);
eventNoHistory.setAction(action);
-
mHoveredChild = null;
- } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
+ } else {
// Pointer is still within the child.
handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild);
}
@@ -1278,6 +1306,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return handled;
}
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ // Handle the event only if leaf. This guarantees that
+ // the leafs (or any custom class that returns true from
+ // this method) will get a change to process the hover.
+ if (getChildCount() == 0) {
+ return super.onHoverEvent(event);
+ }
+ return false;
+ }
+
private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
if (event.getHistorySize() == 0) {
return event;
@@ -2091,11 +2130,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = false;
+ // We first get a chance to populate the event.
+ onPopulateAccessibilityEvent(event);
+ // Let our children have a shot in populating the event.
for (int i = 0, count = getChildCount(); i < count; i++) {
- populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
+ boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event);
+ if (handled) {
+ return handled;
+ }
}
- return populated;
+ return false;
}
/**
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index d7d4c3f..655df39 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.Rect;
+import android.view.accessibility.AccessibilityEvent;
/**
* Defines the responsibilities for a class that will be a parent of a View.
@@ -222,4 +223,22 @@ public interface ViewParent {
*/
public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
boolean immediate);
+
+ /**
+ * Called by a child to request from its parent to send an {@link AccessibilityEvent}.
+ * The child has already populated a record for itself in the event and is delegating
+ * to its parent to send the event. The parent can optionally add a record for itself.
+ * <p>
+ * Note: An accessibility event is fired by an individual view which populates the
+ * event with a record for its state and requests from its parent to perform
+ * the sending. The parent can optionally add a record for itself before
+ * dispatching the request to its parent. A parent can also choose not to
+ * respect the request for sending the event. The accessibility event is sent
+ * by the topmost view in the view tree.
+ *
+ * @param child The child which requests sending the event.
+ * @param event The event to be sent.
+ * @return True if the event was sent.
+ */
+ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event);
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 4104b07..f02daba 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -3530,6 +3530,14 @@ public final class ViewRoot extends Handler implements ViewParent,
public void childDrawableStateChanged(View child) {
}
+ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ if (mView == null) {
+ return false;
+ }
+ AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event);
+ return true;
+ }
+
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 8f7bb8c..3d19380 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -400,7 +400,7 @@ public interface WindowManagerPolicy {
* display dimensions.
*/
public void setInitialDisplaySize(int width, int height);
-
+
/**
* Check permissions when adding a window.
*
@@ -816,6 +816,13 @@ public interface WindowManagerPolicy {
boolean displayEnabled);
/**
+ * Return the currently locked screen rotation, if any. Return
+ * Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, or
+ * Surface.ROTATION_270 if locked; return -1 if not locked.
+ */
+ public int getLockedRotationLw();
+
+ /**
* Called when the system is mostly done booting to determine whether
* the system should go into safe mode.
*/
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 9af19b8..11c9392 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -21,13 +21,26 @@ import android.os.Parcelable;
import android.text.TextUtils;
import java.util.ArrayList;
-import java.util.List;
/**
* This class represents accessibility events that are sent by the system when
* something notable happens in the user interface. For example, when a
* {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc.
* <p>
+ * An accessibility event is fired by an individual view which populates the event with
+ * a record for its state and requests from its parent to send the event to interested
+ * parties. The parent can optionally add a record for itself before dispatching a similar
+ * request to its parent. A parent can also choose not to respect the request for sending
+ * an event. The accessibility event is sent by the topmost view in the view tree.
+ * Therefore, an {@link android.accessibilityservice.AccessibilityService} can explore
+ * all records in an accessibility event to obtain more information about the context
+ * in which the event was fired.
+ * <p>
+ * A client can add, remove, and modify records. The getters and setters for individual
+ * properties operate on the current record which can be explicitly set by the client. By
+ * default current is the first record. Thus, querying a record would require setting
+ * it as the current one and interacting with the property getters and setters.
+ * <p>
* This class represents various semantically different accessibility event
* types. Each event type has associated a set of related properties. In other
* words, each event type is characterized via a subset of the properties exposed
@@ -145,7 +158,7 @@ import java.util.List;
* @see android.view.accessibility.AccessibilityManager
* @see android.accessibilityservice.AccessibilityService
*/
-public final class AccessibilityEvent implements Parcelable {
+public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
/**
* Invalid selection/focus position.
@@ -207,6 +220,26 @@ public final class AccessibilityEvent implements Parcelable {
public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
/**
+ * Represents the event of a hover enter over a {@link android.view.View}.
+ */
+ public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080;
+
+ /**
+ * Represents the event of a hover exit over a {@link android.view.View}.
+ */
+ public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100;
+
+ /**
+ * Represents the event of starting a touch exploration gesture.
+ */
+ public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200;
+
+ /**
+ * Represents the event of ending a touch exploration gesture.
+ */
+ public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
+
+ /**
* Mask for {@link AccessibilityEvent} all types.
*
* @see #TYPE_VIEW_CLICKED
@@ -219,116 +252,53 @@ public final class AccessibilityEvent implements Parcelable {
*/
public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
- private static final int MAX_POOL_SIZE = 2;
+ private static final int MAX_POOL_SIZE = 10;
private static final Object mPoolLock = new Object();
private static AccessibilityEvent sPool;
private static int sPoolSize;
- private static final int CHECKED = 0x00000001;
- private static final int ENABLED = 0x00000002;
- private static final int PASSWORD = 0x00000004;
- private static final int FULL_SCREEN = 0x00000080;
-
private AccessibilityEvent mNext;
+ private boolean mIsInPool;
private int mEventType;
- private int mBooleanProperties;
- private int mCurrentItemIndex;
- private int mItemCount;
- private int mFromIndex;
- private int mAddedCount;
- private int mRemovedCount;
-
- private long mEventTime;
-
- private CharSequence mClassName;
private CharSequence mPackageName;
- private CharSequence mContentDescription;
- private CharSequence mBeforeText;
-
- private Parcelable mParcelableData;
-
- private final List<CharSequence> mText = new ArrayList<CharSequence>();
+ private long mEventTime;
- private boolean mIsInPool;
+ private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
/*
* Hide constructor from clients.
*/
private AccessibilityEvent() {
- mCurrentItemIndex = INVALID_POSITION;
- }
-
- /**
- * Gets if the source is checked.
- *
- * @return True if the view is checked, false otherwise.
- */
- public boolean isChecked() {
- return getBooleanProperty(CHECKED);
- }
-
- /**
- * Sets if the source is checked.
- *
- * @param isChecked True if the view is checked, false otherwise.
- */
- public void setChecked(boolean isChecked) {
- setBooleanProperty(CHECKED, isChecked);
- }
- /**
- * Gets if the source is enabled.
- *
- * @return True if the view is enabled, false otherwise.
- */
- public boolean isEnabled() {
- return getBooleanProperty(ENABLED);
- }
-
- /**
- * Sets if the source is enabled.
- *
- * @param isEnabled True if the view is enabled, false otherwise.
- */
- public void setEnabled(boolean isEnabled) {
- setBooleanProperty(ENABLED, isEnabled);
- }
-
- /**
- * Gets if the source is a password field.
- *
- * @return True if the view is a password field, false otherwise.
- */
- public boolean isPassword() {
- return getBooleanProperty(PASSWORD);
}
/**
- * Sets if the source is a password field.
+ * Gets the number of records contained in the event.
*
- * @param isPassword True if the view is a password field, false otherwise.
+ * @return The number of records.
*/
- public void setPassword(boolean isPassword) {
- setBooleanProperty(PASSWORD, isPassword);
+ public int getRecordCount() {
+ return mRecords.size();
}
/**
- * Sets if the source is taking the entire screen.
+ * Appends an {@link AccessibilityRecord} to the end of event records.
*
- * @param isFullScreen True if the source is full screen, false otherwise.
+ * @param record The record to append.
*/
- public void setFullScreen(boolean isFullScreen) {
- setBooleanProperty(FULL_SCREEN, isFullScreen);
+ public void appendRecord(AccessibilityRecord record) {
+ mRecords.add(record);
}
/**
- * Gets if the source is taking the entire screen.
+ * Gets the records at a given index.
*
- * @return True if the source is full screen, false otherwise.
+ * @param index The index.
+ * @return The records at the specified index.
*/
- public boolean isFullScreen() {
- return getBooleanProperty(FULL_SCREEN);
+ public AccessibilityRecord getRecord(int index) {
+ return mRecords.get(index);
}
/**
@@ -350,96 +320,6 @@ public final class AccessibilityEvent implements Parcelable {
}
/**
- * Gets the number of items that can be visited.
- *
- * @return The number of items.
- */
- public int getItemCount() {
- return mItemCount;
- }
-
- /**
- * Sets the number of items that can be visited.
- *
- * @param itemCount The number of items.
- */
- public void setItemCount(int itemCount) {
- mItemCount = itemCount;
- }
-
- /**
- * Gets the index of the source in the list of items the can be visited.
- *
- * @return The current item index.
- */
- public int getCurrentItemIndex() {
- return mCurrentItemIndex;
- }
-
- /**
- * Sets the index of the source in the list of items that can be visited.
- *
- * @param currentItemIndex The current item index.
- */
- public void setCurrentItemIndex(int currentItemIndex) {
- mCurrentItemIndex = currentItemIndex;
- }
-
- /**
- * Gets the index of the first character of the changed sequence.
- *
- * @return The index of the first character.
- */
- public int getFromIndex() {
- return mFromIndex;
- }
-
- /**
- * Sets the index of the first character of the changed sequence.
- *
- * @param fromIndex The index of the first character.
- */
- public void setFromIndex(int fromIndex) {
- mFromIndex = fromIndex;
- }
-
- /**
- * Gets the number of added characters.
- *
- * @return The number of added characters.
- */
- public int getAddedCount() {
- return mAddedCount;
- }
-
- /**
- * Sets the number of added characters.
- *
- * @param addedCount The number of added characters.
- */
- public void setAddedCount(int addedCount) {
- mAddedCount = addedCount;
- }
-
- /**
- * Gets the number of removed characters.
- *
- * @return The number of removed characters.
- */
- public int getRemovedCount() {
- return mRemovedCount;
- }
-
- /**
- * Sets the number of removed characters.
- *
- * @param removedCount The number of removed characters.
- */
- public void setRemovedCount(int removedCount) {
- mRemovedCount = removedCount;
- }
-
- /**
* Gets the time in which this event was sent.
*
* @return The event time.
@@ -458,24 +338,6 @@ public final class AccessibilityEvent implements Parcelable {
}
/**
- * Gets the class name of the source.
- *
- * @return The class name.
- */
- public CharSequence getClassName() {
- return mClassName;
- }
-
- /**
- * Sets the class name of the source.
- *
- * @param className The lass name.
- */
- public void setClassName(CharSequence className) {
- mClassName = className;
- }
-
- /**
* Gets the package name of the source.
*
* @return The package name.
@@ -494,70 +356,6 @@ public final class AccessibilityEvent implements Parcelable {
}
/**
- * Gets the text of the event. The index in the list represents the priority
- * of the text. Specifically, the lower the index the higher the priority.
- *
- * @return The text.
- */
- public List<CharSequence> getText() {
- return mText;
- }
-
- /**
- * Sets the text before a change.
- *
- * @return The text before the change.
- */
- public CharSequence getBeforeText() {
- return mBeforeText;
- }
-
- /**
- * Sets the text before a change.
- *
- * @param beforeText The text before the change.
- */
- public void setBeforeText(CharSequence beforeText) {
- mBeforeText = beforeText;
- }
-
- /**
- * Gets the description of the source.
- *
- * @return The description.
- */
- public CharSequence getContentDescription() {
- return mContentDescription;
- }
-
- /**
- * Sets the description of the source.
- *
- * @param contentDescription The description.
- */
- public void setContentDescription(CharSequence contentDescription) {
- mContentDescription = contentDescription;
- }
-
- /**
- * Gets the {@link Parcelable} data.
- *
- * @return The parcelable data.
- */
- public Parcelable getParcelableData() {
- return mParcelableData;
- }
-
- /**
- * Sets the {@link Parcelable} data of the event.
- *
- * @param parcelableData The parcelable data.
- */
- public void setParcelableData(Parcelable parcelableData) {
- mParcelableData = parcelableData;
- }
-
- /**
* Returns a cached instance if such is available or a new one is
* instantiated with type property set.
*
@@ -595,11 +393,11 @@ public final class AccessibilityEvent implements Parcelable {
* <p>
* <b>Note: You must not touch the object after calling this function.</b>
*/
+ @Override
public void recycle() {
if (mIsInPool) {
return;
}
-
clear();
synchronized (mPoolLock) {
if (sPoolSize <= MAX_POOL_SIZE) {
@@ -614,44 +412,15 @@ public final class AccessibilityEvent implements Parcelable {
/**
* Clears the state of this instance.
*/
- private void clear() {
+ @Override
+ protected void clear() {
+ super.clear();
mEventType = 0;
- mBooleanProperties = 0;
- mCurrentItemIndex = INVALID_POSITION;
- mItemCount = 0;
- mFromIndex = 0;
- mAddedCount = 0;
- mRemovedCount = 0;
- mEventTime = 0;
- mClassName = null;
mPackageName = null;
- mContentDescription = null;
- mBeforeText = null;
- mParcelableData = null;
- mText.clear();
- }
-
- /**
- * Gets the value of a boolean property.
- *
- * @param property The property.
- * @return The value.
- */
- private boolean getBooleanProperty(int property) {
- return (mBooleanProperties & property) == property;
- }
-
- /**
- * Sets a boolean property.
- *
- * @param property The property.
- * @param value The value.
- */
- private void setBooleanProperty(int property, boolean value) {
- if (value) {
- mBooleanProperties |= property;
- } else {
- mBooleanProperties &= ~property;
+ mEventTime = 0;
+ while (!mRecords.isEmpty()) {
+ AccessibilityRecord record = mRecords.remove(0);
+ record.recycle();
}
}
@@ -662,38 +431,82 @@ public final class AccessibilityEvent implements Parcelable {
*/
public void initFromParcel(Parcel parcel) {
mEventType = parcel.readInt();
- mBooleanProperties = parcel.readInt();
- mCurrentItemIndex = parcel.readInt();
- mItemCount = parcel.readInt();
- mFromIndex = parcel.readInt();
- mAddedCount = parcel.readInt();
- mRemovedCount = parcel.readInt();
- mEventTime = parcel.readLong();
- mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- mParcelableData = parcel.readParcelable(null);
- parcel.readList(mText, null);
+ mEventTime = parcel.readLong();
+ readAccessibilityRecordFromParcel(this, parcel);
+
+ // Read the records.
+ final int recordCount = parcel.readInt();
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = AccessibilityRecord.obtain();
+ readAccessibilityRecordFromParcel(record, parcel);
+ mRecords.add(record);
+ }
}
+ /**
+ * Reads an {@link AccessibilityRecord} from a parcel.
+ *
+ * @param record The record to initialize.
+ * @param parcel The parcel to read from.
+ */
+ private void readAccessibilityRecordFromParcel(AccessibilityRecord record,
+ Parcel parcel) {
+ record.mBooleanProperties = parcel.readInt();
+ record.mCurrentItemIndex = parcel.readInt();
+ record.mItemCount = parcel.readInt();
+ record.mFromIndex = parcel.readInt();
+ record.mAddedCount = parcel.readInt();
+ record.mRemovedCount = parcel.readInt();
+ record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ record.mParcelableData = parcel.readParcelable(null);
+ parcel.readList(record.mText, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mEventType);
- parcel.writeInt(mBooleanProperties);
- parcel.writeInt(mCurrentItemIndex);
- parcel.writeInt(mItemCount);
- parcel.writeInt(mFromIndex);
- parcel.writeInt(mAddedCount);
- parcel.writeInt(mRemovedCount);
- parcel.writeLong(mEventTime);
- TextUtils.writeToParcel(mClassName, parcel, 0);
TextUtils.writeToParcel(mPackageName, parcel, 0);
- TextUtils.writeToParcel(mContentDescription, parcel, 0);
- TextUtils.writeToParcel(mBeforeText, parcel, 0);
- parcel.writeParcelable(mParcelableData, flags);
- parcel.writeList(mText);
+ parcel.writeLong(mEventTime);
+ writeAccessibilityRecordToParcel(this, parcel, flags);
+
+ // Write the records.
+ final int recordCount = getRecordCount();
+ parcel.writeInt(recordCount);
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = mRecords.get(i);
+ writeAccessibilityRecordToParcel(record, parcel, flags);
+ }
+ }
+
+ /**
+ * Writes an {@link AccessibilityRecord} to a parcel.
+ *
+ * @param record The record to write.
+ * @param parcel The parcel to which to write.
+ */
+ private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel,
+ int flags) {
+ parcel.writeInt(record.mBooleanProperties);
+ parcel.writeInt(record.mCurrentItemIndex);
+ parcel.writeInt(record.mItemCount);
+ parcel.writeInt(record.mFromIndex);
+ parcel.writeInt(record.mAddedCount);
+ parcel.writeInt(record.mRemovedCount);
+ TextUtils.writeToParcel(record.mClassName, parcel, flags);
+ TextUtils.writeToParcel(record.mContentDescription, parcel, flags);
+ TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
+ parcel.writeParcelable(record.mParcelableData, flags);
+ parcel.writeList(record.mText);
}
+ /**
+ * {@inheritDoc}
+ */
public int describeContents() {
return 0;
}
@@ -701,24 +514,21 @@ public final class AccessibilityEvent implements Parcelable {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append(super.toString());
builder.append("; EventType: " + mEventType);
builder.append("; EventTime: " + mEventTime);
- builder.append("; ClassName: " + mClassName);
builder.append("; PackageName: " + mPackageName);
- builder.append("; Text: " + mText);
- builder.append("; ContentDescription: " + mContentDescription);
- builder.append("; ItemCount: " + mItemCount);
- builder.append("; CurrentItemIndex: " + mCurrentItemIndex);
- builder.append("; IsEnabled: " + isEnabled());
- builder.append("; IsPassword: " + isPassword());
- builder.append("; IsChecked: " + isChecked());
- builder.append("; IsFullScreen: " + isFullScreen());
- builder.append("; BeforeText: " + mBeforeText);
- builder.append("; FromIndex: " + mFromIndex);
- builder.append("; AddedCount: " + mAddedCount);
- builder.append("; RemovedCount: " + mRemovedCount);
- builder.append("; ParcelableData: " + mParcelableData);
+ builder.append(" \n{\n");
+ builder.append(super.toString());
+ builder.append("\n");
+ for (int i = 0; i < mRecords.size(); i++) {
+ AccessibilityRecord record = mRecords.get(i);
+ builder.append(" Record ");
+ builder.append(i);
+ builder.append(":");
+ builder.append(record.toString());
+ builder.append("\n");
+ }
+ builder.append("}\n");
return builder.toString();
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 22cb0d4..dd77193 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -16,6 +16,8 @@
package android.view.accessibility;
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Binder;
@@ -44,6 +46,8 @@ import java.util.List;
* @see android.content.Context#getSystemService
*/
public final class AccessibilityManager {
+ private static final boolean DEBUG = false;
+
private static final String LOG_TAG = "AccessibilityManager";
static final Object sInstanceSync = new Object();
@@ -164,7 +168,7 @@ public final class AccessibilityManager {
long identityToken = Binder.clearCallingIdentity();
doRecycle = mService.sendAccessibilityEvent(event);
Binder.restoreCallingIdentity(identityToken);
- if (false) {
+ if (DEBUG) {
Log.i(LOG_TAG, event + " sent");
}
} catch (RemoteException re) {
@@ -185,7 +189,7 @@ public final class AccessibilityManager {
}
try {
mService.interrupt();
- if (false) {
+ if (DEBUG) {
Log.i(LOG_TAG, "Requested interrupt from all services");
}
} catch (RemoteException re) {
@@ -202,7 +206,33 @@ public final class AccessibilityManager {
List<ServiceInfo> services = null;
try {
services = mService.getAccessibilityServiceList();
- if (false) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
+ }
+ return Collections.unmodifiableList(services);
+ }
+
+ /**
+ * Returns the {@link ServiceInfo}s of the enabled accessibility services
+ * for a given feedback type.
+ *
+ * @param feedbackType The type of feedback.
+ * @return An unmodifiable list with {@link ServiceInfo}s.
+ *
+ * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
+ * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
+ * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
+ * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
+ * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
+ */
+ public List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
+ List<ServiceInfo> services = null;
+ try {
+ services = mService.getEnabledAccessibilityServiceList(feedbackType);
+ if (DEBUG) {
Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
}
} catch (RemoteException re) {
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
new file mode 100644
index 0000000..e095f43
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a record in an accessibility event. This class encapsulates
+ * the information for a {@link android.view.View}. Note that not all properties
+ * are applicable to all view types. For detailed information please refer to
+ * {@link AccessibilityEvent}.
+ *
+ * @see AccessibilityEvent
+ */
+public class AccessibilityRecord {
+
+ private static final int INVALID_POSITION = -1;
+
+ private static final int PROPERTY_CHECKED = 0x00000001;
+ private static final int PROPERTY_ENABLED = 0x00000002;
+ private static final int PROPERTY_PASSWORD = 0x00000004;
+ private static final int PROPERTY_FULL_SCREEN = 0x00000080;
+
+ private static final int MAX_POOL_SIZE = 10;
+ private static final Object mPoolLock = new Object();
+ private static AccessibilityRecord sPool;
+ private static int sPoolSize;
+
+ private AccessibilityRecord mNext;
+ private boolean mIsInPool;
+
+ protected int mBooleanProperties;
+ protected int mCurrentItemIndex;
+ protected int mItemCount;
+ protected int mFromIndex;
+ protected int mAddedCount;
+ protected int mRemovedCount;
+
+ protected CharSequence mClassName;
+ protected CharSequence mContentDescription;
+ protected CharSequence mBeforeText;
+ protected Parcelable mParcelableData;
+
+ protected final List<CharSequence> mText = new ArrayList<CharSequence>();
+
+ /*
+ * Hide constructor.
+ */
+ protected AccessibilityRecord() {
+
+ }
+
+ /**
+ * Gets if the source is checked.
+ *
+ * @return True if the view is checked, false otherwise.
+ */
+ public boolean isChecked() {
+ return getBooleanProperty(PROPERTY_CHECKED);
+ }
+
+ /**
+ * Sets if the source is checked.
+ *
+ * @param isChecked True if the view is checked, false otherwise.
+ */
+ public void setChecked(boolean isChecked) {
+ setBooleanProperty(PROPERTY_CHECKED, isChecked);
+ }
+
+ /**
+ * Gets if the source is enabled.
+ *
+ * @return True if the view is enabled, false otherwise.
+ */
+ public boolean isEnabled() {
+ return getBooleanProperty(PROPERTY_ENABLED);
+ }
+
+ /**
+ * Sets if the source is enabled.
+ *
+ * @param isEnabled True if the view is enabled, false otherwise.
+ */
+ public void setEnabled(boolean isEnabled) {
+ setBooleanProperty(PROPERTY_ENABLED, isEnabled);
+ }
+
+ /**
+ * Gets if the source is a password field.
+ *
+ * @return True if the view is a password field, false otherwise.
+ */
+ public boolean isPassword() {
+ return getBooleanProperty(PROPERTY_PASSWORD);
+ }
+
+ /**
+ * Sets if the source is a password field.
+ *
+ * @param isPassword True if the view is a password field, false otherwise.
+ */
+ public void setPassword(boolean isPassword) {
+ setBooleanProperty(PROPERTY_PASSWORD, isPassword);
+ }
+
+ /**
+ * Sets if the source is taking the entire screen.
+ *
+ * @param isFullScreen True if the source is full screen, false otherwise.
+ */
+ public void setFullScreen(boolean isFullScreen) {
+ setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
+ }
+
+ /**
+ * Gets if the source is taking the entire screen.
+ *
+ * @return True if the source is full screen, false otherwise.
+ */
+ public boolean isFullScreen() {
+ return getBooleanProperty(PROPERTY_FULL_SCREEN);
+ }
+
+ /**
+ * Gets the number of items that can be visited.
+ *
+ * @return The number of items.
+ */
+ public int getItemCount() {
+ return mItemCount;
+ }
+
+ /**
+ * Sets the number of items that can be visited.
+ *
+ * @param itemCount The number of items.
+ */
+ public void setItemCount(int itemCount) {
+ mItemCount = itemCount;
+ }
+
+ /**
+ * Gets the index of the source in the list of items the can be visited.
+ *
+ * @return The current item index.
+ */
+ public int getCurrentItemIndex() {
+ return mCurrentItemIndex;
+ }
+
+ /**
+ * Sets the index of the source in the list of items that can be visited.
+ *
+ * @param currentItemIndex The current item index.
+ */
+ public void setCurrentItemIndex(int currentItemIndex) {
+ mCurrentItemIndex = currentItemIndex;
+ }
+
+ /**
+ * Gets the index of the first character of the changed sequence.
+ *
+ * @return The index of the first character.
+ */
+ public int getFromIndex() {
+ return mFromIndex;
+ }
+
+ /**
+ * Sets the index of the first character of the changed sequence.
+ *
+ * @param fromIndex The index of the first character.
+ */
+ public void setFromIndex(int fromIndex) {
+ mFromIndex = fromIndex;
+ }
+
+ /**
+ * Gets the number of added characters.
+ *
+ * @return The number of added characters.
+ */
+ public int getAddedCount() {
+ return mAddedCount;
+ }
+
+ /**
+ * Sets the number of added characters.
+ *
+ * @param addedCount The number of added characters.
+ */
+ public void setAddedCount(int addedCount) {
+ mAddedCount = addedCount;
+ }
+
+ /**
+ * Gets the number of removed characters.
+ *
+ * @return The number of removed characters.
+ */
+ public int getRemovedCount() {
+ return mRemovedCount;
+ }
+
+ /**
+ * Sets the number of removed characters.
+ *
+ * @param removedCount The number of removed characters.
+ */
+ public void setRemovedCount(int removedCount) {
+ mRemovedCount = removedCount;
+ }
+
+ /**
+ * Gets the class name of the source.
+ *
+ * @return The class name.
+ */
+ public CharSequence getClassName() {
+ return mClassName;
+ }
+
+ /**
+ * Sets the class name of the source.
+ *
+ * @param className The lass name.
+ */
+ public void setClassName(CharSequence className) {
+ mClassName = className;
+ }
+
+ /**
+ * Gets the text of the event. The index in the list represents the priority
+ * of the text. Specifically, the lower the index the higher the priority.
+ *
+ * @return The text.
+ */
+ public List<CharSequence> getText() {
+ return mText;
+ }
+
+ /**
+ * Sets the text before a change.
+ *
+ * @return The text before the change.
+ */
+ public CharSequence getBeforeText() {
+ return mBeforeText;
+ }
+
+ /**
+ * Sets the text before a change.
+ *
+ * @param beforeText The text before the change.
+ */
+ public void setBeforeText(CharSequence beforeText) {
+ mBeforeText = beforeText;
+ }
+
+ /**
+ * Gets the description of the source.
+ *
+ * @return The description.
+ */
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * Sets the description of the source.
+ *
+ * @param contentDescription The description.
+ */
+ public void setContentDescription(CharSequence contentDescription) {
+ mContentDescription = contentDescription;
+ }
+
+ /**
+ * Gets the {@link Parcelable} data.
+ *
+ * @return The parcelable data.
+ */
+ public Parcelable getParcelableData() {
+ return mParcelableData;
+ }
+
+ /**
+ * Sets the {@link Parcelable} data of the event.
+ *
+ * @param parcelableData The parcelable data.
+ */
+ public void setParcelableData(Parcelable parcelableData) {
+ mParcelableData = parcelableData;
+ }
+
+ /**
+ * Gets the value of a boolean property.
+ *
+ * @param property The property.
+ * @return The value.
+ */
+ public boolean getBooleanProperty(int property) {
+ return (mBooleanProperties & property) == property;
+ }
+
+ /**
+ * Sets a boolean property.
+ *
+ * @param property The property.
+ * @param value The value.
+ */
+ private void setBooleanProperty(int property, boolean value) {
+ if (value) {
+ mBooleanProperties |= property;
+ } else {
+ mBooleanProperties &= ~property;
+ }
+ }
+
+ /**
+ * Returns a cached instance if such is available or a new one is
+ * instantiated.
+ *
+ * @return An instance.
+ */
+ protected static AccessibilityRecord obtain() {
+ synchronized (mPoolLock) {
+ if (sPool != null) {
+ AccessibilityRecord record = sPool;
+ sPool = sPool.mNext;
+ sPoolSize--;
+ record.mNext = null;
+ record.mIsInPool = false;
+ return record;
+ }
+ return new AccessibilityRecord();
+ }
+ }
+
+ /**
+ * Return an instance back to be reused.
+ * <p>
+ * <b>Note: You must not touch the object after calling this function.</b>
+ */
+ public void recycle() {
+ if (mIsInPool) {
+ return;
+ }
+ clear();
+ synchronized (mPoolLock) {
+ if (sPoolSize <= MAX_POOL_SIZE) {
+ mNext = sPool;
+ sPool = this;
+ mIsInPool = true;
+ sPoolSize++;
+ }
+ }
+ }
+
+ /**
+ * Clears the state of this instance.
+ */
+ protected void clear() {
+ mBooleanProperties = 0;
+ mCurrentItemIndex = INVALID_POSITION;
+ mItemCount = 0;
+ mFromIndex = 0;
+ mAddedCount = 0;
+ mRemovedCount = 0;
+ mClassName = null;
+ mContentDescription = null;
+ mBeforeText = null;
+ mParcelableData = null;
+ mText.clear();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(" [ ClassName: " + mClassName);
+ builder.append("; Text: " + mText);
+ builder.append("; ContentDescription: " + mContentDescription);
+ builder.append("; ItemCount: " + mItemCount);
+ builder.append("; CurrentItemIndex: " + mCurrentItemIndex);
+ builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED));
+ builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD));
+ builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED));
+ builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN));
+ builder.append("; BeforeText: " + mBeforeText);
+ builder.append("; FromIndex: " + mFromIndex);
+ builder.append("; AddedCount: " + mAddedCount);
+ builder.append("; RemovedCount: " + mRemovedCount);
+ builder.append("; ParcelableData: " + mParcelableData);
+ builder.append(" ]");
+ return builder.toString();
+ }
+}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 7633569..aaaae32 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -35,5 +35,7 @@ interface IAccessibilityManager {
List<ServiceInfo> getAccessibilityServiceList();
+ List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType);
+
void interrupt();
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 6cb5c35..d63d421 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -55,6 +55,7 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -2556,6 +2557,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
@Override
+ public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ // Add a record for ourselves as well.
+ AccessibilityEvent record = AccessibilityEvent.obtain();
+ // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent
+ record.setClassName(getClass().getName());
+ child.dispatchPopulateAccessibilityEvent(record);
+ event.appendRecord(record);
+ return true;
+ }
+
+ @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index f16efbd..060f1a9 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -876,7 +876,6 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = false;
// This is an exceptional case which occurs when a window gets the
// focus and sends a focus event via its focused child to announce
// current focus/selection. AdapterView fires selection but not focus
@@ -885,22 +884,27 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
- // we send selection events only from AdapterView to avoid
- // generation of such event for each child
+ // We first get a chance to populate the event.
+ onPopulateAccessibilityEvent(event);
+
+ // We send selection events only from AdapterView to avoid
+ // generation of such event for each child.
View selectedView = getSelectedView();
if (selectedView != null) {
- populated = selectedView.dispatchPopulateAccessibilityEvent(event);
+ return selectedView.dispatchPopulateAccessibilityEvent(event);
}
- if (!populated) {
- if (selectedView != null) {
- event.setEnabled(selectedView.isEnabled());
- }
- event.setItemCount(getCount());
- event.setCurrentItemIndex(getSelectedItemPosition());
- }
+ return false;
+ }
- return populated;
+ @Override
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ View selectedView = getSelectedView();
+ if (selectedView != null) {
+ event.setEnabled(selectedView.isEnabled());
+ }
+ event.setItemCount(getCount());
+ event.setCurrentItemIndex(getSelectedItemPosition());
}
@Override
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index bf63607..bd595a5 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -199,11 +199,8 @@ public class CheckedTextView extends TextView implements Checkable {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = super.dispatchPopulateAccessibilityEvent(event);
- if (!populated) {
- event.setChecked(mChecked);
- }
- return populated;
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+ event.setChecked(mChecked);
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 0df45cc..f050d41 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -208,22 +208,18 @@ public abstract class CompoundButton extends Button implements Checkable {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = super.dispatchPopulateAccessibilityEvent(event);
-
- if (!populated) {
- int resourceId = 0;
- if (mChecked) {
- resourceId = R.string.accessibility_compound_button_selected;
- } else {
- resourceId = R.string.accessibility_compound_button_unselected;
- }
- String state = getResources().getString(resourceId);
- event.getText().add(state);
- event.setChecked(mChecked);
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
+ int resourceId = 0;
+ if (mChecked) {
+ resourceId = R.string.accessibility_compound_button_selected;
+ } else {
+ resourceId = R.string.accessibility_compound_button_unselected;
}
-
- return populated;
+ String state = getResources().getString(resourceId);
+ event.getText().add(state);
+ event.setChecked(mChecked);
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 7210e21..30fb927 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -353,13 +353,14 @@ public class DatePicker extends FrameLayout {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
+ final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
| DateUtils.FORMAT_SHOW_YEAR;
String selectedDateUtterance = DateUtils.formatDateTime(mContext,
mCurrentDate.getTimeInMillis(), flags);
event.getText().add(selectedDateUtterance);
- return true;
}
/**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index d76a956..5618dbe 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1998,36 +1998,32 @@ public class ListView extends AbsListView {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = super.dispatchPopulateAccessibilityEvent(event);
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
// If the item count is less than 15 then subtract disabled items from the count and
// position. Otherwise ignore disabled items.
- if (!populated) {
- int itemCount = 0;
- int currentItemIndex = getSelectedItemPosition();
-
- ListAdapter adapter = getAdapter();
- if (adapter != null) {
- final int count = adapter.getCount();
- if (count < 15) {
- for (int i = 0; i < count; i++) {
- if (adapter.isEnabled(i)) {
- itemCount++;
- } else if (i <= currentItemIndex) {
- currentItemIndex--;
- }
+ int itemCount = 0;
+ int currentItemIndex = getSelectedItemPosition();
+
+ ListAdapter adapter = getAdapter();
+ if (adapter != null) {
+ final int count = adapter.getCount();
+ if (count < 15) {
+ for (int i = 0; i < count; i++) {
+ if (adapter.isEnabled(i)) {
+ itemCount++;
+ } else if (i <= currentItemIndex) {
+ currentItemIndex--;
}
- } else {
- itemCount = count;
}
+ } else {
+ itemCount = count;
}
-
- event.setItemCount(itemCount);
- event.setCurrentItemIndex(currentItemIndex);
}
- return populated;
+ event.setItemCount(itemCount);
+ event.setCurrentItemIndex(currentItemIndex);
}
/**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 8db34d9..96d41a0 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1027,12 +1027,10 @@ public class ProgressBar extends View {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- if (!super.dispatchPopulateAccessibilityEvent(event)) {
- event.setItemCount(mMax);
- event.setCurrentItemIndex(mProgress);
- }
- return true;
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+ event.setItemCount(mMax);
+ event.setCurrentItemIndex(mProgress);
}
/**
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 6f76dd0..31ec785 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -427,12 +427,19 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- event.setItemCount(getTabCount());
- event.setCurrentItemIndex(mSelectedTab);
+ onPopulateAccessibilityEvent(event);
+ // Dispatch only to the selected tab.
if (mSelectedTab != -1) {
- getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event);
+ return getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event);
}
- return true;
+ return false;
+ }
+
+ @Override
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+ event.setItemCount(getTabCount());
+ event.setCurrentItemIndex(mSelectedTab);
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 537709d..4d3aa68 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -81,8 +81,8 @@ import android.text.method.TextKeyListener;
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
import android.text.style.ClickableSpan;
-import android.text.style.SuggestionSpan;
import android.text.style.ParagraphStyle;
+import android.text.style.SuggestionSpan;
import android.text.style.URLSpan;
import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
@@ -2967,14 +2967,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
advancesIndex);
}
- public float getTextRunAdvancesICU(int start, int end, int contextStart,
+ public float getTextRunAdvances(int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex,
- Paint p) {
+ Paint p, int reserved) {
int count = end - start;
int contextCount = contextEnd - contextStart;
- return p.getTextRunAdvancesICU(mChars, start + mStart, count,
+ return p.getTextRunAdvances(mChars, start + mStart, count,
contextStart + mStart, contextCount, flags, advances,
- advancesIndex);
+ advancesIndex, reserved);
}
public int getTextRunCursor(int contextStart, int contextEnd, int flags,
@@ -7896,9 +7896,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
if (!isShown()) {
- return false;
+ return;
}
final boolean isPassword = hasPasswordTransformationMethod();
@@ -7914,7 +7914,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} else {
event.setPassword(isPassword);
}
- return false;
}
void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
@@ -8038,7 +8037,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case ID_SELECTION_MODE:
if (mSelectionActionMode != null) {
// Selection mode is already started, simply change selected part.
- updateSelectedRegion();
+ selectCurrentWord();
} else {
startSelectionActionMode();
}
@@ -8188,8 +8187,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
stopSelectionActionMode();
} else {
- // New selection at touch position
- updateSelectedRegion();
+ selectCurrentWord();
}
handled = true;
}
@@ -8205,17 +8203,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return handled;
}
- /**
- * When selection mode is already started, this method simply updates the selected part of text
- * to the text under the finger.
- */
- private void updateSelectedRegion() {
- // Start a new selection at current position, keep selectionAction mode on
- selectCurrentWord();
- // Updates handles' positions
- getSelectionController().show();
- }
-
private boolean touchPositionIsInSelection() {
int selectionStart = getSelectionStart();
int selectionEnd = getSelectionEnd();
@@ -8783,7 +8770,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private float mTouchOffsetY;
// Where the touch position should be on the handle to ensure a maximum cursor visibility
private float mIdealVerticalOffset;
- // Parent's (TextView) position in window
+ // Parent's (TextView) previous position in window
private int mLastParentX, mLastParentY;
// PopupWindow container absolute position with respect to the enclosing window
private int mContainerPositionX, mContainerPositionY;
@@ -8857,12 +8844,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public void show() {
- updateContainerPosition();
if (isShowing()) {
mContainer.update(mContainerPositionX, mContainerPositionY,
mRight - mLeft, mBottom - mTop);
-
- hideAssociatedPopupWindow();
} else {
mContainer.showAtLocation(TextView.this, 0,
mContainerPositionX, mContainerPositionY);
@@ -8877,7 +8861,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
protected void dismiss() {
mIsDragging = false;
mContainer.dismiss();
- hideAssociatedPopupWindow();
}
public void hide() {
@@ -8908,22 +8891,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int compoundPaddingLeft = getCompoundPaddingLeft();
final int compoundPaddingRight = getCompoundPaddingRight();
- final TextView hostView = TextView.this;
+ final TextView textView = TextView.this;
if (mTempRect == null) mTempRect = new Rect();
final Rect clip = mTempRect;
clip.left = compoundPaddingLeft;
clip.top = extendedPaddingTop;
- clip.right = hostView.getWidth() - compoundPaddingRight;
- clip.bottom = hostView.getHeight() - extendedPaddingBottom;
+ clip.right = textView.getWidth() - compoundPaddingRight;
+ clip.bottom = textView.getHeight() - extendedPaddingBottom;
- final ViewParent parent = hostView.getParent();
- if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) {
+ final ViewParent parent = textView.getParent();
+ if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
return false;
}
final int[] coords = mTempCoords;
- hostView.getLocationInWindow(coords);
+ textView.getLocationInWindow(coords);
final int posX = coords[0] + mPositionX + (int) mHotspotX;
final int posY = coords[1] + mPositionY;
@@ -8932,23 +8915,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
posY >= clip.top && posY <= clip.bottom;
}
- private void moveTo(int x, int y) {
- mPositionX = x - TextView.this.mScrollX;
- mPositionY = y - TextView.this.mScrollY;
-
- if (mIsDragging) {
- TextView.this.getLocationInWindow(mTempCoords);
- if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
- mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
- mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
- mLastParentX = mTempCoords[0];
- mLastParentY = mTempCoords[1];
- }
-
- hideAssociatedPopupWindow();
- }
- }
-
public abstract int getCurrentCursorOffset();
public abstract void updateOffset(int offset);
@@ -8957,44 +8923,44 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
protected void positionAtCursorOffset(int offset) {
addPositionToTouchUpFilter(offset);
- final int width = mDrawable.getIntrinsicWidth();
- final int height = mDrawable.getIntrinsicHeight();
final int line = mLayout.getLineForOffset(offset);
final int lineBottom = mLayout.getLineBottom(line);
- final Rect bounds = sCursorControllerTempRect;
- bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) +
- TextView.this.mScrollX;
- bounds.top = lineBottom + TextView.this.mScrollY;
-
- bounds.right = bounds.left + width;
- bounds.bottom = bounds.top + height;
+ mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX);
+ mPositionY = lineBottom;
- convertFromViewportToContentCoordinates(bounds);
- moveTo(bounds.left, bounds.top);
+ // Take TextView's padding into account.
+ mPositionX += viewportToContentHorizontalOffset();
+ mPositionY += viewportToContentVerticalOffset();
}
- /**
- * Updates the global container's position.
- * @return whether or not the position has actually changed
- */
- private boolean updateContainerPosition() {
+ protected boolean updateContainerPosition() {
positionAtCursorOffset(getCurrentCursorOffset());
+
+ final int previousContainerPositionX = mContainerPositionX;
+ final int previousContainerPositionY = mContainerPositionY;
+
TextView.this.getLocationInWindow(mTempCoords);
- final int containerPositionX = mTempCoords[0] + mPositionX;
- final int containerPositionY = mTempCoords[1] + mPositionY;
+ mContainerPositionX = mTempCoords[0] + mPositionX;
+ mContainerPositionY = mTempCoords[1] + mPositionY;
- if (containerPositionX != mContainerPositionX ||
- containerPositionY != mContainerPositionY) {
- mContainerPositionX = containerPositionX;
- mContainerPositionY = containerPositionY;
- return true;
- }
- return false;
+ return (previousContainerPositionX != mContainerPositionX ||
+ previousContainerPositionY != mContainerPositionY);
}
public boolean onPreDraw() {
if (updateContainerPosition()) {
+ if (mIsDragging) {
+ if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
+ mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
+ mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
+ mLastParentX = mTempCoords[0];
+ mLastParentY = mTempCoords[1];
+ }
+ }
+
+ onHandleMoved();
+
if (isPositionVisible()) {
mContainer.update(mContainerPositionX, mContainerPositionY,
mRight - mLeft, mBottom - mTop);
@@ -9007,9 +8973,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
dismiss();
}
}
-
- // Hide paste popup as soon as the view is scrolled or moved
- hideAssociatedPopupWindow();
}
return true;
}
@@ -9076,8 +9039,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mIsDragging;
}
- void hideAssociatedPopupWindow() {
- // No associated popup window by default
+ void onHandleMoved() {
+ // Does nothing by default
}
public void onDetached() {
@@ -9096,15 +9059,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private Runnable mHider;
private Runnable mPastePopupShower;
- public InsertionHandleView() {
- super();
- }
-
@Override
public void show() {
super.show();
hideDelayed();
- removePastePopupCallback();
+ hidePastePopupWindow();
}
public void show(int delayBeforePaste) {
@@ -9118,11 +9077,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mPastePopupShower == null) {
mPastePopupShower = new Runnable() {
public void run() {
- showAssociatedPopupWindow();
+ showPastePopupWindow();
}
};
}
- postDelayed(mPastePopupShower, delayBeforePaste);
+ TextView.this.postDelayed(mPastePopupShower, delayBeforePaste);
}
}
@@ -9132,11 +9091,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
onDetached();
}
- @Override
- public void hide() {
- super.hide();
- }
-
private void hideDelayed() {
removeHiderCallback();
if (mHider == null) {
@@ -9146,18 +9100,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
};
}
- postDelayed(mHider, DELAY_BEFORE_FADE_OUT);
- }
-
- private void removePastePopupCallback() {
- if (mPastePopupShower != null) {
- removeCallbacks(mPastePopupShower);
- }
+ TextView.this.postDelayed(mHider, DELAY_BEFORE_FADE_OUT);
}
private void removeHiderCallback() {
if (mHider != null) {
- removeCallbacks(mHider);
+ TextView.this.removeCallbacks(mHider);
}
}
@@ -9197,6 +9145,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
}
+ hideDelayed();
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ hideDelayed();
break;
default:
@@ -9214,31 +9167,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void updateOffset(int offset) {
Selection.setSelection((Spannable) mText, offset);
- positionAtCursorOffset(offset);
}
@Override
public void updatePosition(int x, int y) {
- final int previousOffset = getCurrentCursorOffset();
- final int newOffset = getOffset(x, y);
-
- if (newOffset != previousOffset) {
- updateOffset(newOffset);
- removePastePopupCallback();
- }
- hideDelayed();
+ updateOffset(getOffset(x, y));
}
- void showAssociatedPopupWindow() {
+ void showPastePopupWindow() {
if (mPastePopupWindow == null) {
- // Lazy initialisation: create when actually shown only.
mPastePopupWindow = new PastePopupWindow();
}
mPastePopupWindow.show();
}
@Override
- void hideAssociatedPopupWindow() {
+ void onHandleMoved() {
+ removeHiderCallback();
+ hidePastePopupWindow();
+ }
+
+ void hidePastePopupWindow() {
+ if (mPastePopupShower != null) {
+ TextView.this.removeCallbacks(mPastePopupShower);
+ }
if (mPastePopupWindow != null) {
mPastePopupWindow.hide();
}
@@ -9247,15 +9199,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onDetached() {
removeHiderCallback();
- removePastePopupCallback();
+ hidePastePopupWindow();
}
}
private class SelectionStartHandleView extends HandleView {
- public SelectionStartHandleView() {
- super();
- }
-
@Override
protected void initDrawable() {
if (mSelectHandleLeft == null) {
@@ -9274,7 +9222,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void updateOffset(int offset) {
Selection.setSelection((Spannable) mText, offset, getSelectionEnd());
- positionAtCursorOffset(offset);
}
@Override
@@ -9290,15 +9237,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (offset >= selectionEnd) offset = selectionEnd - 1;
Selection.setSelection((Spannable) mText, offset, selectionEnd);
- positionAtCursorOffset(offset);
}
}
private class SelectionEndHandleView extends HandleView {
- public SelectionEndHandleView() {
- super();
- }
-
@Override
protected void initDrawable() {
if (mSelectHandleRight == null) {
@@ -9317,7 +9259,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void updateOffset(int offset) {
Selection.setSelection((Spannable) mText, getSelectionStart(), offset);
- positionAtCursorOffset(offset);
}
@Override
@@ -9333,7 +9274,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (offset <= selectionStart) offset = selectionStart + 1;
Selection.setSelection((Spannable) mText, selectionStart, offset);
- positionAtCursorOffset(offset);
}
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 029d690..423e735 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -409,7 +409,9 @@ public class TimePicker extends FrameLayout {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
int flags = DateUtils.FORMAT_SHOW_TIME;
if (mIs24HourView) {
flags |= DateUtils.FORMAT_24HOUR;
@@ -421,7 +423,6 @@ public class TimePicker extends FrameLayout {
String selectedDateUtterance = DateUtils.formatDateTime(mContext,
mTempCalendar.getTimeInMillis(), flags);
event.getText().add(selectedDateUtterance);
- return true;
}
private void updateHourControl() {
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 16d5539..9652085 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -861,7 +861,7 @@ public class ActionBarImpl extends ActionBar {
@Override
public void setIcon(int resId) {
- mActionView.setIcon(mContext.getResources().getDrawable(resId));
+ mActionView.setIcon(resId);
}
@Override
@@ -871,7 +871,7 @@ public class ActionBarImpl extends ActionBar {
@Override
public void setLogo(int resId) {
- mActionView.setLogo(mContext.getResources().getDrawable(resId));
+ mActionView.setLogo(resId);
}
@Override
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index 71511c6..16f51fd 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -104,6 +104,10 @@ public abstract class BaseMenuPresenter implements MenuPresenter {
* @param childIndex Index within the parent to insert at
*/
protected void addItemView(View itemView, int childIndex) {
+ final ViewGroup currentParent = (ViewGroup) itemView.getParent();
+ if (currentParent != null) {
+ currentParent.removeView(itemView);
+ }
((ViewGroup) mMenuView).addView(itemView, childIndex);
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 42ef916..c6d386d 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -523,7 +523,9 @@ public final class MenuItemImpl implements MenuItem {
}
public boolean showsTextAsAction() {
- return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT;
+ return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT &&
+ mMenu.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.allow_action_menu_item_text_with_icon);
}
public void setShowAsAction(int actionEnum) {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 74a6ae7..fa8eb51 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -30,11 +30,13 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ActionMode;
import android.view.Gravity;
@@ -85,7 +87,6 @@ public class ActionBarView extends ViewGroup {
private CharSequence mSubtitle;
private Drawable mIcon;
private Drawable mLogo;
- private Drawable mDivider;
private View mHomeLayout;
private View mHomeAsUpView;
@@ -211,8 +212,6 @@ public class ActionBarView extends ViewGroup {
mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
- mDivider = a.getDrawable(R.styleable.ActionBar_divider);
-
a.recycle();
mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
@@ -434,6 +433,10 @@ public class ActionBarView extends ViewGroup {
}
}
+ public void setIcon(int resId) {
+ setIcon(mContext.getResources().getDrawableForDensity(resId, getPreferredIconDensity()));
+ }
+
public void setLogo(Drawable logo) {
mLogo = logo;
if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -441,6 +444,29 @@ public class ActionBarView extends ViewGroup {
}
}
+ public void setLogo(int resId) {
+ mContext.getResources().getDrawable(resId);
+ }
+
+ /**
+ * @return Drawable density to load that will best fit the available height.
+ */
+ private int getPreferredIconDensity() {
+ final Resources res = mContext.getResources();
+ final int availableHeight = getLayoutParams().height -
+ mIconView.getPaddingTop() - mIconView.getPaddingBottom();
+ int iconSize = res.getDimensionPixelSize(android.R.dimen.app_icon_size);
+
+ if (iconSize * DisplayMetrics.DENSITY_LOW >= availableHeight) {
+ return DisplayMetrics.DENSITY_LOW;
+ } else if (iconSize * DisplayMetrics.DENSITY_MEDIUM >= availableHeight) {
+ return DisplayMetrics.DENSITY_MEDIUM;
+ } else if (iconSize * DisplayMetrics.DENSITY_HIGH >= availableHeight) {
+ return DisplayMetrics.DENSITY_HIGH;
+ }
+ return DisplayMetrics.DENSITY_XHIGH;
+ }
+
public void setNavigationMode(int mode) {
final int oldMode = mNavigationMode;
if (mode != oldMode) {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 0a54e17..768b836 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -482,44 +482,28 @@ public:
return totalAdvance;
}
- static float getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+ static float getTextRunAdvances___CIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
- jint flags, jfloatArray advances, jint advancesIndex) {
+ jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
- jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
- index - contextIndex, count, contextCount, flags, advances, advancesIndex);
+ jfloat result = (reserved == 0) ?
+ doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
+ count, contextCount, flags, advances, advancesIndex) :
+ doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
+ count, contextCount, flags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
- static float getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+ static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
- jfloatArray advances, jint advancesIndex) {
+ jfloatArray advances, jint advancesIndex, jint reserved) {
const jchar* textArray = env->GetStringChars(text, NULL);
- jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
- start - contextStart, end - start, contextEnd - contextStart, flags, advances,
- advancesIndex);
- env->ReleaseStringChars(text, textArray);
- return result;
- }
-
- static float getTextRunAdvancesICU___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
- jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
- jint flags, jfloatArray advances, jint advancesIndex) {
- jchar* textArray = env->GetCharArrayElements(text, NULL);
- jfloat result = doTextRunAdvancesICU(env, paint, textArray + contextIndex,
- index - contextIndex, count, contextCount, flags, advances, advancesIndex);
- env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
- return result;
- }
-
- static float getTextRunAdvancesICU__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
- jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
- jfloatArray advances, jint advancesIndex) {
- const jchar* textArray = env->GetStringChars(text, NULL);
- jfloat result = doTextRunAdvancesICU(env, paint, textArray + contextStart,
- start - contextStart, end - start, contextEnd - contextStart, flags, advances,
- advancesIndex);
+ jfloat result = (reserved == 0) ?
+ doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
+ end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
+ doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
+ end - start, contextEnd - contextStart, flags, advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
return result;
}
@@ -816,14 +800,12 @@ static JNINativeMethod methods[] = {
{"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
{"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
- {"native_getTextRunAdvances","(I[CIIIII[FI)F",
- (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
- {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
- (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
- {"native_getTextRunAdvancesICU","(I[CIIIII[FI)F",
- (void*) SkPaintGlue::getTextRunAdvancesICU___CIIIII_FI},
- {"native_getTextRunAdvancesICU","(ILjava/lang/String;IIIII[FI)F",
- (void*) SkPaintGlue::getTextRunAdvancesICU__StringIIIII_FI},
+ {"native_getTextRunAdvances","(I[CIIIII[FII)F",
+ (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
+ {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
+ (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
+
+
{"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
(void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
{"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7f18121..2ed39e4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -550,6 +550,14 @@
android:description="@string/permdesc_sdcardWrite"
android:protectionLevel="dangerous" />
+ <!-- Allows an application to write to internal media storage
+ @hide -->
+ <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_mediaStorageWrite"
+ android:description="@string/permdesc_mediaStorageWrite"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- ============================================ -->
<!-- Permissions for low-level system interaction -->
<!-- ============================================ -->
diff --git a/core/res/res/layout-large/action_bar_home.xml b/core/res/res/layout-large/action_bar_home.xml
new file mode 100644
index 0000000..86580bc
--- /dev/null
+++ b/core/res/res/layout-large/action_bar_home.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.internal.widget.ActionBarView$HomeView"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground" >
+ <ImageView android:id="@android:id/up"
+ android:src="?android:attr/homeAsUpIndicator"
+ android:layout_gravity="center_vertical|left"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="-12dip" />
+ <ImageView android:id="@android:id/home"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:paddingTop="4dip"
+ android:paddingBottom="4dip"
+ android:adjustViewBounds="true"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter" />
+</view>
diff --git a/core/res/res/layout-large/action_mode_close_item.xml b/core/res/res/layout-large/action_mode_close_item.xml
new file mode 100644
index 0000000..321622e
--- /dev/null
+++ b/core/res/res/layout-large/action_mode_close_item.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_mode_close_button"
+ android:background="@drawable/btn_cab_done"
+ android:focusable="true"
+ android:clickable="true"
+ android:paddingLeft="16dip"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <ImageView android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:scaleType="center"
+ android:src="@drawable/ic_cab_close_holo" />
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="16dip"
+ android:textAppearance="@android:style/TextAppearance.Holo.Medium"
+ android:textColor="@android:color/white"
+ android:text="@string/action_mode_done" />
+</LinearLayout>
diff --git a/core/res/res/layout/action_bar_home.xml b/core/res/res/layout/action_bar_home.xml
index c82f91d..7f7c55c 100644
--- a/core/res/res/layout/action_bar_home.xml
+++ b/core/res/res/layout/action_bar_home.xml
@@ -25,12 +25,15 @@
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="-12dip" />
+ android:layout_marginRight="-4dip" />
<ImageView android:id="@android:id/home"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
+ android:layout_height="wrap_content"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:paddingTop="@dimen/action_bar_icon_vertical_padding"
+ android:paddingBottom="@dimen/action_bar_icon_vertical_padding"
android:layout_gravity="center"
- android:scaleType="center" />
+ android:adjustViewBounds="true"
+ android:scaleType="fitCenter" />
</view>
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 4a73368..5e828fa 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -31,10 +31,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
- android:paddingLeft="4dip"
- android:paddingRight="4dip"
- android:minHeight="56dip"
- android:scaleType="center"
+ android:padding="@dimen/action_bar_icon_vertical_padding"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true"
android:background="@null"
android:focusable="false" />
<Button android:id="@+id/textButton"
@@ -46,7 +45,6 @@
style="?attr/buttonStyleSmall"
android:textColor="?attr/actionMenuTextColor"
android:background="@null"
- android:paddingLeft="4dip"
- android:paddingRight="4dip"
+ android:padding="4dip"
android:focusable="false" />
</com.android.internal.view.menu.ActionMenuItemView>
diff --git a/core/res/res/layout/action_mode_close_item.xml b/core/res/res/layout/action_mode_close_item.xml
index 7badbac..2a4d8e0 100644
--- a/core/res/res/layout/action_mode_close_item.xml
+++ b/core/res/res/layout/action_mode_close_item.xml
@@ -19,20 +19,12 @@
android:background="@drawable/btn_cab_done"
android:focusable="true"
android:clickable="true"
- android:paddingLeft="16dip"
+ android:paddingLeft="8dip"
android:layout_width="wrap_content"
android:layout_height="match_parent">
- <ImageView android:layout_width="48dip"
+ <ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:scaleType="center"
+ android:scaleType="fitCenter"
android:src="@drawable/ic_cab_close_holo" />
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="16dip"
- android:textAppearance="@android:style/TextAppearance.Holo.Medium"
- android:textColor="@android:color/white"
- android:text="@string/action_mode_done" />
</LinearLayout>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 058daa8..8def578e 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -28,4 +28,8 @@
<dimen name="preference_screen_side_margin">96dp</dimen>
<dimen name="preference_screen_side_margin_negative">-100dp</dimen>
<dimen name="preference_widget_width">72dp</dimen>
+
+ <!-- Default height of an action bar. -->
+ <dimen name="action_bar_default_height">40dip</dimen>
+
</resources>
diff --git a/core/res/res/values-large/dimens.xml b/core/res/res/values-large/dimens.xml
index cd1847f..5355847 100644
--- a/core/res/res/values-large/dimens.xml
+++ b/core/res/res/values-large/dimens.xml
@@ -22,4 +22,10 @@
<!-- Preference UI dimensions for larger screens. -->
<dimen name="preference_widget_width">56dp</dimen>
+ <!-- The maximum number of action buttons that should be permitted within
+ an action bar/action mode. This will be used to determine how many
+ showAsAction="ifRoom" items can fit. "always" items can override this. -->
+ <integer name="max_action_buttons">5</integer>
+ <!-- Default height of an action bar. -->
+ <dimen name="action_bar_default_height">56dip</dimen>
</resources>
diff --git a/core/res/res/values-port/dimens.xml b/core/res/res/values-port/dimens.xml
new file mode 100644
index 0000000..bf0a342
--- /dev/null
+++ b/core/res/res/values-port/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- The maximum number of action buttons that should be permitted within
+ an action bar/action mode. This will be used to determine how many
+ showAsAction="ifRoom" items can fit. "always" items can override this. -->
+ <integer name="max_action_buttons">2</integer>
+</resources>
diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml
new file mode 100644
index 0000000..ea7eeb5
--- /dev/null
+++ b/core/res/res/values-w480dp/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <bool name="allow_action_menu_item_text_with_icon">true</bool>
+</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 33825c7..05a4810 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -68,7 +68,7 @@
<string name="serviceNotProvisioned" msgid="8614830180508686666">"無法提供此服務。"</string>
<string name="CLIRPermanent" msgid="5460892159398802465">"本機號碼顯示設定無法變更。"</string>
<string name="RestrictedChangedTitle" msgid="5592189398956187498">"受限存取已變更"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖資料傳輸服務。"</string>
+ <string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖數據傳輸服務。"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"已封鎖緊急服務。"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"已封鎖語音服務。"</string>
<string name="RestrictedOnAllVoice" msgid="1459318899842232234">"已封鎖所有語音服務。"</string>
@@ -700,15 +700,15 @@
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
<plurals name="num_seconds_ago">
<item quantity="one" msgid="4869870056547896011">"1 秒以前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
+ <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
</plurals>
<plurals name="num_minutes_ago">
<item quantity="one" msgid="3306787433088810191">"1 分鐘以前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
+ <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
</plurals>
<plurals name="num_hours_ago">
<item quantity="one" msgid="9150797944610821849">"1 小時以前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
+ <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
</plurals>
<plurals name="last_num_days">
<item quantity="other" msgid="3069992808164318268">"最近 <xliff:g id="COUNT">%d</xliff:g> 天"</item>
@@ -717,7 +717,7 @@
<string name="older" msgid="5211975022815554840">"較舊"</string>
<plurals name="num_days_ago">
<item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
+ <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
</plurals>
<plurals name="in_num_seconds">
<item quantity="one" msgid="2729745560954905102">"1 秒內"</item>
@@ -745,11 +745,11 @@
</plurals>
<plurals name="abbrev_num_hours_ago">
<item quantity="one" msgid="4796212039724722116">"1 小時以前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
+ <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
<item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
+ <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
<item quantity="one" msgid="5842225370795066299">"1 秒內"</item>
@@ -922,14 +922,14 @@
<string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"USB 儲存裝置已毀損"</string>
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"SD 卡已損壞"</string>
<string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB 儲存裝置已損壞,您可能必須重新格式化。"</string>
- <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD 卡已毀損,您可能必須予以重新格式化。"</string>
- <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB 儲存裝置已意外移除"</string>
+ <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD 卡已毀損,您可能必須重新格式化。"</string>
+ <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB 儲存裝置未正常移除"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD 卡未正常移除"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"請先卸載 USB 儲存裝置,再將其移除,以免資料遺失。"</string>
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"請先卸載 SD 卡,再將其移除,以免資料遺失。"</string>
<string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB 儲存裝置已可安全移除"</string>
<string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"可安全移除 SD 卡"</string>
- <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"您可安全移除 USB 儲存裝置了。"</string>
+ <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"您現在可以安全地移除 USB 儲存裝置。"</string>
<string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"您現在可以安全地移除 SD 卡。"</string>
<string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"USB 儲存裝置已移除"</string>
<string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"已移除 SD 卡"</string>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
new file mode 100644
index 0000000..c7dcb51
--- /dev/null
+++ b/core/res/res/values/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <bool name="allow_action_menu_item_text_with_icon">false</bool>
+</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index da1c157..a1511b3 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -28,7 +28,7 @@
<!-- The maximum number of action buttons that should be permitted within
an action bar/action mode. This will be used to determine how many
showAsAction="ifRoom" items can fit. "always" items can override this. -->
- <integer name="max_action_buttons">5</integer>
+ <integer name="max_action_buttons">3</integer>
<dimen name="toast_y_offset">64dip</dimen>
<!-- Height of the status bar -->
<dimen name="status_bar_height">25dip</dimen>
@@ -79,4 +79,9 @@
<!-- Minimum width of the search view text entry area. -->
<dimen name="search_view_text_min_width">160dip</dimen>
+
+ <!-- Default height of an action bar. -->
+ <dimen name="action_bar_default_height">48dip</dimen>
+ <!-- Vertical padding around action bar icons. -->
+ <dimen name="action_bar_icon_vertical_padding">4dip</dimen>
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b9fd6a5..be7b42f 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -276,7 +276,7 @@
<item name="actionModeStyle">@style/Widget.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.ActionButton.CloseMode</item>
<item name="actionBarStyle">@android:style/Widget.ActionBar</item>
- <item name="actionBarSize">56dip</item>
+ <item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">?android:attr/popupWindowStyle</item>
<item name="actionMenuTextAppearance">?android:attr/textAppearanceMedium</item>
<item name="actionMenuTextColor">?android:attr/textColorPrimary</item>
@@ -1009,7 +1009,7 @@
<item name="actionModeStyle">@style/Widget.Holo.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Holo.ActionButton.CloseMode</item>
<item name="actionBarStyle">@android:style/Widget.Holo.ActionBar</item>
- <item name="actionBarSize">56dip</item>
+ <item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">@android:style/Widget.Holo.PopupWindow.ActionMode</item>
<item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item>
@@ -1294,7 +1294,7 @@
<item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Holo.Light.ActionButton.CloseMode</item>
<item name="actionBarStyle">@android:style/Widget.Holo.Light.ActionBar</item>
- <item name="actionBarSize">56dip</item>
+ <item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item>
<item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index df80546..1870a4a 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,6 +58,10 @@
<group gid="sdcard_rw" />
</permission>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE" >
+ <group gid="media_rw" />
+ </permission>
+
<permission name="android.permission.ACCESS_MTP" >
<group gid="mtp" />
</permission>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index d8898ae..7e13569 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -429,21 +429,18 @@ private class MyTabListener implements ActionBar.TabListener {
private TabContentFragment mFragment;
// Called to create an instance of the listener when adding a new tab
- public TabListener(TabContentFragment fragment) {
+ public MyTabListener(TabContentFragment fragment) {
mFragment = fragment;
}
- &#64;Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.add(R.id.fragment_content, mFragment, null);
}
- &#64;Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(mFragment);
}
- &#64;Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// do nothing
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 0949beb..962f22c 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1501,48 +1501,20 @@ public class Paint {
public float getTextRunAdvances(char[] chars, int index, int count,
int contextIndex, int contextCount, int flags, float[] advances,
int advancesIndex) {
-
- if ((index | count | contextIndex | contextCount | advancesIndex
- | (index - contextIndex)
- | ((contextIndex + contextCount) - (index + count))
- | (chars.length - (contextIndex + contextCount))
- | (advances == null ? 0 :
- (advances.length - (advancesIndex + count)))) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown flags value: " + flags);
- }
-
- if (!mHasCompatScaling) {
- return native_getTextRunAdvances(mNativePaint, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
- }
-
- final float oldSize = getTextSize();
- setTextSize(oldSize * mCompatScaling);
- float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
- setTextSize(oldSize);
-
- if (advances != null) {
- for (int i = advancesIndex, e = i + count; i < e; i++) {
- advances[i] *= mInvCompatScaling;
- }
- }
- return res * mInvCompatScaling; // assume errors are not significant
+ return getTextRunAdvances(chars, index, count, contextIndex, contextCount, flags,
+ advances, advancesIndex, 0 /* use Harfbuzz*/);
}
/**
* Convenience overload that takes a char array instead of a
* String.
*
- * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+ * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int, int)
* @hide
*/
- public float getTextRunAdvancesICU(char[] chars, int index, int count,
+ public float getTextRunAdvances(char[] chars, int index, int count,
int contextIndex, int contextCount, int flags, float[] advances,
- int advancesIndex) {
+ int advancesIndex, int reserved) {
if ((index | count | contextIndex | contextCount | advancesIndex
| (index - contextIndex)
@@ -1557,14 +1529,14 @@ public class Paint {
}
if (!mHasCompatScaling) {
- return native_getTextRunAdvancesICU(mNativePaint, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
+ return native_getTextRunAdvances(mNativePaint, chars, index, count,
+ contextIndex, contextCount, flags, advances, advancesIndex, reserved);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
- float res = native_getTextRunAdvancesICU(mNativePaint, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
+ float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
+ contextIndex, contextCount, flags, advances, advancesIndex, reserved);
setTextSize(oldSize);
if (advances != null) {
@@ -1585,29 +1557,8 @@ public class Paint {
public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, int flags, float[] advances,
int advancesIndex) {
-
- if (text instanceof String) {
- return getTextRunAdvances((String) text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
- }
- if (text instanceof SpannedString ||
- text instanceof SpannableString) {
- return getTextRunAdvances(text.toString(), start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
- }
- if (text instanceof GraphicsOperations) {
- return ((GraphicsOperations) text).getTextRunAdvances(start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, this);
- }
-
- int contextLen = contextEnd - contextStart;
- int len = end - start;
- char[] buf = TemporaryBuffer.obtain(contextLen);
- TextUtils.getChars(text, start, end, buf, 0);
- float result = getTextRunAdvances(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesIndex);
- TemporaryBuffer.recycle(buf);
- return result;
+ return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
+ advances, advancesIndex, 0 /* use Harfbuzz */);
}
/**
@@ -1617,21 +1568,21 @@ public class Paint {
* @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
* @hide
*/
- public float getTextRunAdvancesICU(CharSequence text, int start, int end,
+ public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, int flags, float[] advances,
- int advancesIndex) {
+ int advancesIndex, int reserved) {
if (text instanceof String) {
- return getTextRunAdvancesICU((String) text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ return getTextRunAdvances((String) text, start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex, reserved);
}
if (text instanceof SpannedString ||
text instanceof SpannableString) {
- return getTextRunAdvancesICU(text.toString(), start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ return getTextRunAdvances(text.toString(), start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex, reserved);
}
if (text instanceof GraphicsOperations) {
- return ((GraphicsOperations) text).getTextRunAdvancesICU(start, end,
+ return ((GraphicsOperations) text).getTextRunAdvances(start, end,
contextStart, contextEnd, flags, advances, advancesIndex, this);
}
@@ -1639,8 +1590,8 @@ public class Paint {
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, start, end, buf, 0);
- float result = getTextRunAdvancesICU(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesIndex);
+ float result = getTextRunAdvances(buf, start - contextStart, len,
+ 0, contextLen, flags, advances, advancesIndex, reserved);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -1689,44 +1640,55 @@ public class Paint {
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex) {
-
- if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
- | (start - contextStart) | (contextEnd - end)
- | (text.length() - contextEnd)
- | (advances == null ? 0 :
- (advances.length - advancesIndex - (end - start)))) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown flags value: " + flags);
- }
-
- if (!mHasCompatScaling) {
- return native_getTextRunAdvances(mNativePaint, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
- }
-
- final float oldSize = getTextSize();
- setTextSize(oldSize * mCompatScaling);
- float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
- setTextSize(oldSize);
-
- if (advances != null) {
- for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
- advances[i] *= mInvCompatScaling;
- }
- }
- return totalAdvance * mInvCompatScaling; // assume errors are insignificant
+ return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
+ advances, advancesIndex, 0 /* use Harfbuzz*/);
}
/**
- * Temporary - DO NOT USE
+ * Returns the total advance width for the characters in the run
+ * between start and end, and if advances is not null, the advance
+ * assigned to each of these characters (java chars).
+ *
+ * <p>The trailing surrogate in a valid surrogate pair is assigned
+ * an advance of 0. Thus the number of returned advances is
+ * always equal to count, not to the number of unicode codepoints
+ * represented by the run.
+ *
+ * <p>In the case of conjuncts or combining marks, the total
+ * advance is assigned to the first logical character, and the
+ * following characters are assigned an advance of 0.
+ *
+ * <p>This generates the sum of the advances of glyphs for
+ * characters in a reordered cluster as the width of the first
+ * logical character in the cluster, and 0 for the widths of all
+ * other characters in the cluster. In effect, such clusters are
+ * treated like conjuncts.
+ *
+ * <p>The shaping bounds limit the amount of context available
+ * outside start and end that can be used for shaping analysis.
+ * These bounds typically reflect changes in bidi level or font
+ * metrics across which shaping does not occur.
+ *
+ * @param text the text to measure
+ * @param start the index of the first character to measure
+ * @param end the index past the last character to measure
+ * @param contextStart the index of the first character to use for shaping context,
+ * must be <= start
+ * @param contextEnd the index past the last character to use for shaping context,
+ * must be >= end
+ * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+ * or {@link #DIRECTION_RTL}
+ * @param advances array to receive the advances, must have room for all advances,
+ * can be null if only total advance is needed
+ * @param advancesIndex the position in advances at which to put the
+ * advance corresponding to the character at start
+ * @param reserved int reserved value
+ * @return the total advance
*
* @hide
*/
- public float getTextRunAdvancesICU(String text, int start, int end, int contextStart,
- int contextEnd, int flags, float[] advances, int advancesIndex) {
+ public float getTextRunAdvances(String text, int start, int end, int contextStart,
+ int contextEnd, int flags, float[] advances, int advancesIndex, int reserved) {
if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
| (start - contextStart) | (contextEnd - end)
@@ -1740,14 +1702,14 @@ public class Paint {
}
if (!mHasCompatScaling) {
- return native_getTextRunAdvancesICU(mNativePaint, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ return native_getTextRunAdvances(mNativePaint, text, start, end,
+ contextStart, contextEnd, flags, advances, advancesIndex, reserved);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, flags, advances, advancesIndex, reserved);
setTextSize(oldSize);
if (advances != null) {
@@ -2017,17 +1979,10 @@ public class Paint {
private static native float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex);
+ int flags, float[] advances, int advancesIndex, int reserved);
private static native float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex);
-
- private static native float native_getTextRunAdvancesICU(int native_object,
- char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex);
- private static native float native_getTextRunAdvancesICU(int native_object,
- String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex);
+ int flags, float[] advances, int advancesIndex, int reserved);
private native int native_getTextRunCursor(int native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt);
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index c6c86b2..b752850 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -197,7 +197,7 @@ nContextSetSurface(JNIEnv *_env, jobject _this, RsContext con, jint width, jint
window = (Surface*) android_Surface_getNativeWindow(_env, wnd).get();
}
- rsContextSetSurface(con, width, height, window);
+ rsContextSetSurface(con, width, height, window, 1);
}
static void
@@ -309,7 +309,11 @@ nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobj
nameArray[ct] = _env->GetStringUTFChars(s, NULL);
sizeArray[ct] = _env->GetStringUTFLength(s);
}
- jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray, (const uint32_t *)arraySizes);
+ jint id = (jint)rsElementCreate2(con,
+ (RsElement *)ids, fieldCount,
+ nameArray, fieldCount,
+ sizeArray, fieldCount,
+ (const uint32_t *)arraySizes, fieldCount);
for (int ct=0; ct < fieldCount; ct++) {
jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
_env->ReleaseStringUTFChars(s, nameArray[ct]);
@@ -579,7 +583,8 @@ nAllocationRead_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jintAr
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAllocationRead(con, (RsAllocation)alloc, ptr);
+ jsize length = _env->GetArrayLength(data);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr, length);
_env->ReleaseIntArrayElements(data, ptr, 0);
}
@@ -589,7 +594,8 @@ nAllocationRead_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jshort
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jshort *ptr = _env->GetShortArrayElements(data, NULL);
- rsAllocationRead(con, (RsAllocation)alloc, ptr);
+ jsize length = _env->GetArrayLength(data);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr, length);
_env->ReleaseShortArrayElements(data, ptr, 0);
}
@@ -599,7 +605,8 @@ nAllocationRead_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jbyteA
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jbyte *ptr = _env->GetByteArrayElements(data, NULL);
- rsAllocationRead(con, (RsAllocation)alloc, ptr);
+ jsize length = _env->GetArrayLength(data);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr, length);
_env->ReleaseByteArrayElements(data, ptr, 0);
}
@@ -609,7 +616,8 @@ nAllocationRead_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jfloat
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationRead_f, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAllocationRead(con, (RsAllocation)alloc, ptr);
+ jsize length = _env->GetArrayLength(data);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr, length);
_env->ReleaseFloatArrayElements(data, ptr, 0);
}
@@ -713,7 +721,9 @@ nFontCreateFromFile(JNIEnv *_env, jobject _this, RsContext con,
jstring fileName, jfloat fontSize, jint dpi)
{
AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
- jint id = (jint)rsFontCreateFromFile(con, fileNameUTF.c_str(), fontSize, dpi);
+ jint id = (jint)rsFontCreateFromFile(con,
+ fileNameUTF.c_str(), fileNameUTF.length(),
+ fontSize, dpi);
return id;
}
@@ -725,7 +735,9 @@ nFontCreateFromAssetStream(JNIEnv *_env, jobject _this, RsContext con,
Asset* asset = reinterpret_cast<Asset*>(native_asset);
AutoJavaStringToUTF8 nameUTF(_env, name);
- jint id = (jint)rsFontCreateFromMemory(con, nameUTF.c_str(), fontSize, dpi,
+ jint id = (jint)rsFontCreateFromMemory(con,
+ nameUTF.c_str(), nameUTF.length(),
+ fontSize, dpi,
asset->getBuffer(false), asset->getLength());
return id;
}
@@ -745,7 +757,9 @@ nFontCreateFromAsset(JNIEnv *_env, jobject _this, RsContext con, jobject _assetM
return 0;
}
- jint id = (jint)rsFontCreateFromMemory(con, str.c_str(), fontSize, dpi,
+ jint id = (jint)rsFontCreateFromMemory(con,
+ str.c_str(), str.length(),
+ fontSize, dpi,
asset->getBuffer(false), asset->getLength());
delete asset;
return id;
@@ -877,7 +891,9 @@ nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con,
//rsScriptCSetText(con, (const char *)script_ptr, length);
- ret = (jint)rsScriptCCreate(con, resNameUTF.c_str(), cacheDirUTF.c_str(),
+ ret = (jint)rsScriptCCreate(con,
+ resNameUTF.c_str(), resNameUTF.length(),
+ cacheDirUTF.c_str(), cacheDirUTF.length(),
(const char *)script_ptr, length);
exit:
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index e272839..db81721 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -265,11 +265,12 @@ public:
// (-1000,-1000) is the upper left point. (1000, 1000) is the lower right
// point. The length and width of focus areas cannot be 0 or negative.
//
- // The fifth element is the weight. The weight ranges from 1 to 1000.
- // The sum of the weights of all focus areas must be 1000. Focus areas
- // can partially overlap and the driver will add the weights in the
- // overlap region. But apps should not set two focus areas that have
- // identical coordinates.
+ // The fifth element is the weight. Values for weight must range from 1 to
+ // 1000. The weight should be interpreted as a per-pixel weight - all
+ // pixels in the area have the specified weight. This means a small area
+ // with the same weight as a larger area will have less influence on the
+ // focusing than the larger area. Focus areas can partially overlap and the
+ // driver will add the weights in the overlap region.
//
// A special case of single focus area (0,0,0,0,0) means driver to decide
// the focus area. For example, the driver may use more signals to decide
@@ -327,10 +328,12 @@ public:
// is the lower right point. The length and width of metering areas cannot
// be 0 or negative.
//
- // The weight ranges from 1 to 1000. The sum of the weights of all metering
- // areas must be 1000. Metering areas can partially overlap and the driver
- // will add the weights in the overlap region. But apps should not set two
- // metering areas that have identical coordinates.
+ // The fifth element is the weight. Values for weight must range from 1 to
+ // 1000. The weight should be interpreted as a per-pixel weight - all
+ // pixels in the area have the specified weight. This means a small area
+ // with the same weight as a larger area will have less influence on the
+ // metering than the larger area. Metering areas can partially overlap and
+ // the driver will add the weights in the overlap region.
//
// A special case of all-zero single metering area means driver to decide
// the metering area. For example, the driver may use more signals to decide
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index df5be32..765c039 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -55,7 +55,7 @@ private:
status_t doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client,
- ExceptionCheck exceptionCheck, void *exceptionEnv);
+ bool noMedia, ExceptionCheck exceptionCheck, void *exceptionEnv);
MediaScanner(const MediaScanner &);
MediaScanner &operator=(const MediaScanner &);
@@ -72,10 +72,9 @@ public:
void endFile();
virtual bool scanFile(const char* path, long long lastModified,
- long long fileSize, bool isDirectory) = 0;
+ long long fileSize, bool isDirectory, bool noMedia) = 0;
virtual bool handleStringTag(const char* name, const char* value) = 0;
virtual bool setMimeType(const char* mimeType) = 0;
- virtual bool addNoMediaFolder(const char* path) = 0;
protected:
void convertValues(uint32_t encoding);
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index c650141..6b69b8a 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -31,6 +31,8 @@ public class Credentials {
public static final String INSTALL_ACTION = "android.credentials.INSTALL";
+ public static final String UNLOCK_ACTION = "com.android.credentials.UNLOCK";
+
/** Key prefix for CA certificates. */
public static final String CA_CERTIFICATE = "CACERT_";
@@ -69,7 +71,7 @@ public class Credentials {
public void unlock(Context context) {
try {
- Intent intent = new Intent("com.android.credentials.UNLOCK");
+ Intent intent = new Intent(UNLOCK_ACTION);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, e.toString());
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
new file mode 100644
index 0000000..64f5a48
--- /dev/null
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security;
+
+import android.os.Bundle;
+
+/**
+ * Caller is required to ensure that {@link KeyStore#unlock
+ * KeyStore.unlock} was successful.
+ *
+ * @hide
+ */
+interface IKeyChainService {
+ byte[] getPrivate(String alias, String authToken);
+ byte[] getCertificate(String alias, String authToken);
+ byte[] getCaCertificate(String alias, String authToken);
+ String findIssuer(in Bundle cert);
+}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
new file mode 100644
index 0000000..69847bf
--- /dev/null
+++ b/keystore/java/android/security/KeyChain.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import dalvik.system.CloseGuard;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
+import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
+
+/**
+ * @hide
+ */
+public final class KeyChain {
+
+ private static final String TAG = "KeyChain";
+
+ /**
+ * @hide Also used by KeyChainService implementation
+ */
+ public static final String ACCOUNT_TYPE = "com.android.keychain";
+
+ /**
+ * @hide Also used by KeyChainService implementation
+ */
+ // TODO This non-localized CA string to be removed when CAs moved out of keystore
+ public static final String CA_SUFFIX = " CA";
+
+ public static final String KEY_INTENT = "intent";
+
+ /**
+ * Intentionally not public to leave open the future possibility
+ * of hardware based keys. Callers should use {@link #toPrivateKey
+ * toPrivateKey} in order to convert a bundle to a {@code
+ * PrivateKey}
+ */
+ private static final String KEY_PKCS8 = "pkcs8";
+
+ /**
+ * Intentionally not public to leave open the future possibility
+ * of hardware based certs. Callers should use {@link
+ * #toCertificate toCertificate} in order to convert a bundle to a
+ * {@code PrivateKey}
+ */
+ private static final String KEY_X509 = "x509";
+
+ /**
+ * Returns an {@code Intent} for use with {@link
+ * android.app.Activity#startActivityForResult
+ * startActivityForResult}. The result will be returned via {@link
+ * android.app.Activity#onActivityResult onActivityResult} with
+ * {@link android.app.Activity#RESULT_OK RESULT_OK} and the alias
+ * in the returned {@code Intent}'s extra data with key {@link
+ * android.content.Intent#EXTRA_TEXT Intent.EXTRA_TEXT}.
+ */
+ public static Intent chooseAlias() {
+ return new Intent("com.android.keychain.CHOOSER");
+ }
+
+ /**
+ * Returns a new {@code KeyChain} instance. When the caller is
+ * done using the {@code KeyChain}, it must be closed with {@link
+ * #close()} or resource leaks will occur.
+ */
+ public static KeyChain getInstance(Context context) throws InterruptedException {
+ return new KeyChain(context);
+ }
+
+ private final AccountManager mAccountManager;
+
+ private final Object mServiceLock = new Object();
+ private IKeyChainService mService;
+ private boolean mIsBound;
+
+ private Account mAccount;
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mServiceLock) {
+ mService = IKeyChainService.Stub.asInterface(service);
+ mServiceLock.notifyAll();
+
+ // Account is created if necessary during binding of the IKeyChainService
+ mAccount = mAccountManager.getAccountsByType(ACCOUNT_TYPE)[0];
+ }
+ }
+
+ @Override public void onServiceDisconnected(ComponentName name) {
+ synchronized (mServiceLock) {
+ mService = null;
+ }
+ }
+ };
+
+ private final Context mContext;
+
+ private final CloseGuard mGuard = CloseGuard.get();
+
+ private KeyChain(Context context) throws InterruptedException {
+ if (context == null) {
+ throw new NullPointerException("context == null");
+ }
+ mContext = context;
+ ensureNotOnMainThread();
+ mAccountManager = AccountManager.get(mContext);
+ mIsBound = mContext.bindService(new Intent(IKeyChainService.class.getName()),
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ if (!mIsBound) {
+ throw new AssertionError();
+ }
+ synchronized (mServiceLock) {
+ // there is a race between binding on this thread and the
+ // callback on the main thread. wait until binding is done
+ // to be sure we have the mAccount initialized.
+ if (mService == null) {
+ mServiceLock.wait();
+ }
+ }
+ mGuard.open("close");
+ }
+
+ /**
+ * {@code Bundle} will contain {@link #KEY_INTENT} if user needs
+ * to confirm application access to requested key. In the alias
+ * does not exist or there is an error, null is
+ * returned. Otherwise the {@code Bundle} contains information
+ * representing the private key which can be interpreted with
+ * {@link #toPrivateKey toPrivateKey}.
+ *
+ * non-null alias
+ */
+ public Bundle getPrivate(String alias) {
+ return get(alias, Credentials.USER_PRIVATE_KEY);
+ }
+
+ public Bundle getCertificate(String alias) {
+ return get(alias, Credentials.USER_CERTIFICATE);
+ }
+
+ public Bundle getCaCertificate(String alias) {
+ return get(alias, Credentials.CA_CERTIFICATE);
+ }
+
+ private Bundle get(String alias, String type) {
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ ensureNotOnMainThread();
+
+ String authAlias = (type.equals(Credentials.CA_CERTIFICATE)) ? (alias + CA_SUFFIX) : alias;
+ AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount,
+ authAlias,
+ false,
+ null,
+ null);
+ Bundle bundle;
+ try {
+ bundle = future.getResult();
+ } catch (OperationCanceledException e) {
+ throw new AssertionError(e);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ } catch (AuthenticatorException e) {
+ throw new AssertionError(e);
+ }
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent != null) {
+ Bundle result = new Bundle();
+ // we don't want this Eclair compatability flag,
+ // it will prevent onActivityResult from being called
+ intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
+ result.putParcelable(KEY_INTENT, intent);
+ return result;
+ }
+ String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
+ if (authToken == null) {
+ throw new AssertionError("Invalid authtoken");
+ }
+
+ byte[] bytes;
+ try {
+ if (type.equals(Credentials.USER_PRIVATE_KEY)) {
+ bytes = mService.getPrivate(alias, authToken);
+ } else if (type.equals(Credentials.USER_CERTIFICATE)) {
+ bytes = mService.getCertificate(alias, authToken);
+ } else if (type.equals(Credentials.CA_CERTIFICATE)) {
+ bytes = mService.getCaCertificate(alias, authToken);
+ } else {
+ throw new AssertionError();
+ }
+ } catch (RemoteException e) {
+ throw new AssertionError(e);
+ }
+ if (bytes == null) {
+ throw new AssertionError();
+ }
+ Bundle result = new Bundle();
+ if (type.equals(Credentials.USER_PRIVATE_KEY)) {
+ result.putByteArray(KEY_PKCS8, bytes);
+ } else if (type.equals(Credentials.USER_CERTIFICATE)) {
+ result.putByteArray(KEY_X509, bytes);
+ } else if (type.equals(Credentials.CA_CERTIFICATE)) {
+ result.putByteArray(KEY_X509, bytes);
+ } else {
+ throw new AssertionError();
+ }
+ return result;
+ }
+
+ public static PrivateKey toPrivateKey(Bundle bundle) {
+ byte[] bytes = bundle.getByteArray(KEY_PKCS8);
+ if (bytes == null) {
+ throw new IllegalArgumentException("not a private key bundle");
+ }
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ } catch (InvalidKeySpecException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static Bundle fromPrivateKey(PrivateKey privateKey) {
+ Bundle bundle = new Bundle();
+ String format = privateKey.getFormat();
+ if (!format.equals("PKCS#8")) {
+ throw new IllegalArgumentException("Unsupported private key format " + format);
+ }
+ bundle.putByteArray(KEY_PKCS8, privateKey.getEncoded());
+ return bundle;
+ }
+
+ public static X509Certificate toCertificate(Bundle bundle) {
+ byte[] bytes = bundle.getByteArray(KEY_X509);
+ if (bytes == null) {
+ throw new IllegalArgumentException("not a certificate bundle");
+ }
+ try {
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
+ return (X509Certificate) cert;
+ } catch (CertificateException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static Bundle fromCertificate(Certificate cert) {
+ Bundle bundle = new Bundle();
+ String type = cert.getType();
+ if (!type.equals("X.509")) {
+ throw new IllegalArgumentException("Unsupported certificate type " + type);
+ }
+ try {
+ bundle.putByteArray(KEY_X509, cert.getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new AssertionError(e);
+ }
+ return bundle;
+ }
+
+ private void ensureNotOnMainThread() {
+ Looper looper = Looper.myLooper();
+ if (looper != null && looper == mContext.getMainLooper()) {
+ throw new IllegalStateException(
+ "calling this from your main thread can lead to deadlock");
+ }
+ }
+
+ public Bundle findIssuer(X509Certificate cert) {
+ if (cert == null) {
+ throw new NullPointerException("cert == null");
+ }
+ ensureNotOnMainThread();
+
+ // check and see if the issuer is already known to the default IndexedPKIXParameters
+ IndexedPKIXParameters index = SSLParametersImpl.getDefaultIndexedPKIXParameters();
+ try {
+ TrustAnchor anchor = index.findTrustAnchor(cert);
+ if (anchor != null && anchor.getTrustedCert() != null) {
+ X509Certificate ca = anchor.getTrustedCert();
+ return fromCertificate(ca);
+ }
+ } catch (CertPathValidatorException ignored) {
+ }
+
+ // otherwise, it might be a user installed CA in the keystore
+ String alias;
+ try {
+ alias = mService.findIssuer(fromCertificate(cert));
+ } catch (RemoteException e) {
+ throw new AssertionError(e);
+ }
+ if (alias == null) {
+ Log.w(TAG, "Lookup failed for issuer");
+ return null;
+ }
+
+ Bundle bundle = get(alias, Credentials.CA_CERTIFICATE);
+ Intent intent = bundle.getParcelable(KEY_INTENT);
+ if (intent != null) {
+ // permission still required
+ return bundle;
+ }
+ // add the found CA to the index for next time
+ X509Certificate ca = toCertificate(bundle);
+ index.index(new TrustAnchor(ca, null));
+ return bundle;
+ }
+
+ public void close() {
+ if (mIsBound) {
+ mContext.unbindService(mServiceConnection);
+ mIsBound = false;
+ mGuard.close();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ // note we don't close, we just warn.
+ // shouldn't be doing I/O in a finalizer,
+ // which the unbind would cause.
+ try {
+ if (mGuard != null) {
+ mGuard.warnIfOpen();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7f28959..75f5a5f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -897,7 +897,8 @@ void OpenGLRenderer::setupDrawColor(int color) {
void OpenGLRenderer::setupDrawColor(int color, int alpha) {
mColorA = alpha / 255.0f;
- // BUG on this next line? a is alpha divided by 255 *twice*
+ // Second divide of a by 255 is an optimization, allowing us to simply multiply
+ // the rgb values by a instead of also dividing by 255
const float a = mColorA / 255.0f;
mColorR = a * ((color >> 16) & 0xFF);
mColorG = a * ((color >> 8) & 0xFF);
@@ -908,6 +909,8 @@ void OpenGLRenderer::setupDrawColor(int color, int alpha) {
void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
mColorA = alpha / 255.0f;
+ // Double-divide of a by 255 is an optimization, allowing us to simply multiply
+ // the rgb values by a instead of also dividing by 255
const float a = mColorA / 255.0f;
mColorR = a * ((color >> 16) & 0xFF);
mColorG = a * ((color >> 8) & 0xFF);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index cead75b..18d98cb 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -57,7 +57,6 @@ namespace uirenderer {
#define PROGRAM_KEY_COLOR_BLEND 0x80
#define PROGRAM_KEY_BITMAP_NPOT 0x100
#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
-#define PROGRAM_KEY_VERTEX_WIDTH 0x4000
#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
@@ -76,6 +75,8 @@ namespace uirenderer {
#define PROGRAM_IS_POINT_SHIFT 36
+#define PROGRAM_HAS_WIDTH_SHIFT 37
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
@@ -205,7 +206,6 @@ struct ProgramDescription {
programid key() const {
programid key = 0;
if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
- if (hasWidth) key |= PROGRAM_KEY_VERTEX_WIDTH;
if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
if (hasBitmap) {
key |= PROGRAM_KEY_BITMAP;
@@ -239,6 +239,7 @@ struct ProgramDescription {
if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
+ if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
return key;
}
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index bd1fd0e..093e311 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -243,13 +243,15 @@ static void SC_MatrixTranspose_2x2(Matrix2x2 *m) {
static float SC_randf(float max) {
float r = (float)rand();
r *= max;
- return r / RAND_MAX;
+ r /= RAND_MAX;
+ return r;
}
static float SC_randf2(float min, float max) {
float r = (float)rand();
+ r /= RAND_MAX;
r = r * (max - min) + min;
- return r / RAND_MAX;
+ return r;
}
static int SC_randi(int max) {
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index a7f473c..dac5cec 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -51,9 +51,8 @@ ContextDestroyWorker {
}
AssignName {
- param void *obj
+ param RsObjectBase obj
param const char *name
- param size_t len
}
ObjDestroy {
@@ -69,7 +68,6 @@ ElementCreate {
}
ElementCreate2 {
- param size_t count
param const RsElement * elements
param const char ** names
param const size_t * nameLengths
@@ -80,7 +78,6 @@ ElementCreate2 {
AllocationCopyToBitmap {
param RsAllocation alloc
param void * data
- param size_t dataLen
}
@@ -90,7 +87,6 @@ Allocation1DData {
param uint32_t lod
param uint32_t count
param const void *data
- param uint32_t bytes
handcodeApi
togglePlay
}
@@ -101,7 +97,6 @@ Allocation1DElementData {
param uint32_t lod
param const void *data
param uint32_t comp_offset
- param uint32_t bytes
handcodeApi
togglePlay
}
@@ -115,7 +110,6 @@ Allocation2DData {
param uint32_t w
param uint32_t h
param const void *data
- param uint32_t bytes
}
Allocation2DElementData {
@@ -126,7 +120,6 @@ Allocation2DElementData {
param RsAllocationCubemapFace face
param const void *data
param uint32_t element_offset
- param uint32_t bytes
}
AllocationGenerateMipmaps {
@@ -184,7 +177,6 @@ ScriptBindAllocation {
ScriptSetTimeZone {
param RsScript s
param const char * timeZone
- param uint32_t length
}
@@ -197,7 +189,6 @@ ScriptInvokeV {
param RsScript s
param uint32_t slot
param const void * data
- param uint32_t dataLen
handcodeApi
togglePlay
}
@@ -236,7 +227,6 @@ ScriptSetVarV {
param RsScript s
param uint32_t slot
param const void * data
- param uint32_t dataLen
handcodeApi
togglePlay
}
@@ -246,7 +236,6 @@ ScriptCCreate {
param const char * resName
param const char * cacheDir
param const char * text
- param uint32_t length
ret RsScript
}
@@ -294,17 +283,13 @@ ProgramBindSampler {
ProgramFragmentCreate {
param const char * shaderText
- param uint32_t shaderLength
param const uint32_t * params
- param uint32_t paramLength
ret RsProgramFragment
}
ProgramVertexCreate {
param const char * shaderText
- param uint32_t shaderLength
param const uint32_t * params
- param uint32_t paramLength
ret RsProgramVertex
}
@@ -319,8 +304,7 @@ FontCreateFromMemory {
param const char *name
param float fontSize
param uint32_t dpi
- param const void *data
- param uint32_t dataLen
+ param const void *data
ret RsFont
}
@@ -346,14 +330,3 @@ MeshBindVertex {
MeshInitVertexAttribs {
param RsMesh mesh
}
-
-AnimationCreate {
- param const float *inValues
- param const float *outValues
- param uint32_t valueCount
- param RsAnimationInterpolation interp
- param RsAnimationEdge pre
- param RsAnimationEdge post
- ret RsAnimation
- }
-
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 6b37e03..a759004 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -780,7 +780,7 @@ void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t
a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes);
}
-void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) {
+void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data, size_t data_length) {
Allocation *a = static_cast<Allocation *>(va);
a->read(data);
}
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 20fa367..0ca892d 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -705,9 +705,9 @@ void rsi_ContextBindFont(Context *rsc, RsFont vfont) {
rsc->setFont(font);
}
-void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len) {
+void rsi_AssignName(Context *rsc, RsObjectBase obj, const char *name, uint32_t name_length) {
ObjectBase *ob = static_cast<ObjectBase *>(obj);
- rsc->assignName(ob, name, len);
+ rsc->assignName(ob, name, name_length);
}
void rsi_ObjDestroy(Context *rsc, void *optr) {
@@ -724,7 +724,7 @@ void rsi_ContextResume(Context *rsc) {
rsc->resume();
}
-void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur) {
+void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur, size_t sur_length) {
rsc->setSurface(w, h, sur);
}
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 477cb61..d5d5ca5 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -348,12 +348,15 @@ RsElement rsi_ElementCreate(Context *rsc,
}
RsElement rsi_ElementCreate2(Context *rsc,
- size_t count,
const RsElement * ein,
+ size_t ein_length,
const char ** names,
+ size_t names_length,
const size_t * nameLengths,
- const uint32_t * arraySizes) {
- const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes);
+ size_t nameLengths_length,
+ const uint32_t * arraySizes,
+ size_t arraySizes_length) {
+ const Element *e = Element::create(rsc, ein_length, (const Element **)ein, names, nameLengths, arraySizes);
e->incUserRef();
return (RsElement)e;
}
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index c30b857..b7b85b6 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -827,7 +827,9 @@ bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOri
namespace android {
namespace renderscript {
-RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
+RsFont rsi_FontCreateFromFile(Context *rsc,
+ char const *name, size_t name_length,
+ float fontSize, uint32_t dpi) {
Font *newFont = Font::create(rsc, name, fontSize, dpi);
if (newFont) {
newFont->incUserRef();
@@ -835,8 +837,11 @@ RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, ui
return newFont;
}
-RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
- Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
+RsFont rsi_FontCreateFromMemory(Context *rsc,
+ char const *name, size_t name_length,
+ float fontSize, uint32_t dpi,
+ const void *data, size_t data_length) {
+ Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
if (newFont) {
newFont->incUserRef();
}
diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h
index 57da10a..da51d95 100644
--- a/libs/rs/rsHandcode.h
+++ b/libs/rs/rsHandcode.h
@@ -7,7 +7,7 @@ static inline void rsHCAPI_ContextFinish (RsContext rsc) {
io->mToCore.commitSync(RS_CMD_ID_ContextFinish, size);
}
-static inline void rsHCAPI_ScriptInvokeV (RsContext rsc, RsScript va, uint32_t slot, const void * data, uint32_t sizeBytes) {
+static inline void rsHCAPI_ScriptInvokeV (RsContext rsc, RsScript va, uint32_t slot, const void * data, size_t sizeBytes) {
ThreadIO *io = &((Context *)rsc)->mIO;
uint32_t size = sizeof(RS_CMD_ScriptInvokeV);
if (sizeBytes < DATA_SYNC_SIZE) {
@@ -16,7 +16,7 @@ static inline void rsHCAPI_ScriptInvokeV (RsContext rsc, RsScript va, uint32_t s
RS_CMD_ScriptInvokeV *cmd = static_cast<RS_CMD_ScriptInvokeV *>(io->mToCore.reserve(size));
cmd->s = va;
cmd->slot = slot;
- cmd->dataLen = sizeBytes;
+ cmd->data_length = sizeBytes;
cmd->data = data;
if (sizeBytes < DATA_SYNC_SIZE) {
cmd->data = (void *)(cmd+1);
@@ -28,7 +28,7 @@ static inline void rsHCAPI_ScriptInvokeV (RsContext rsc, RsScript va, uint32_t s
}
-static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t slot, const void * data, uint32_t sizeBytes) {
+static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t slot, const void * data, size_t sizeBytes) {
ThreadIO *io = &((Context *)rsc)->mIO;
uint32_t size = sizeof(RS_CMD_ScriptSetVarV);
if (sizeBytes < DATA_SYNC_SIZE) {
@@ -37,7 +37,7 @@ static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t s
RS_CMD_ScriptSetVarV *cmd = static_cast<RS_CMD_ScriptSetVarV *>(io->mToCore.reserve(size));
cmd->s = va;
cmd->slot = slot;
- cmd->dataLen = sizeBytes;
+ cmd->data_length = sizeBytes;
cmd->data = data;
if (sizeBytes < DATA_SYNC_SIZE) {
cmd->data = (void *)(cmd+1);
@@ -49,7 +49,7 @@ static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t s
}
static inline void rsHCAPI_Allocation1DData (RsContext rsc, RsAllocation va, uint32_t xoff, uint32_t lod,
- uint32_t count, const void * data, uint32_t sizeBytes) {
+ uint32_t count, const void * data, size_t sizeBytes) {
ThreadIO *io = &((Context *)rsc)->mIO;
uint32_t size = sizeof(RS_CMD_Allocation1DData);
if (sizeBytes < DATA_SYNC_SIZE) {
@@ -61,7 +61,7 @@ static inline void rsHCAPI_Allocation1DData (RsContext rsc, RsAllocation va, uin
cmd->lod = lod;
cmd->count = count;
cmd->data = data;
- cmd->bytes = sizeBytes;
+ cmd->data_length = sizeBytes;
if (sizeBytes < DATA_SYNC_SIZE) {
cmd->data = (void *)(cmd+1);
memcpy(cmd+1, data, sizeBytes);
@@ -72,7 +72,7 @@ static inline void rsHCAPI_Allocation1DData (RsContext rsc, RsAllocation va, uin
}
static inline void rsHCAPI_Allocation1DElementData (RsContext rsc, RsAllocation va, uint32_t x, uint32_t lod,
- const void * data, uint32_t comp_offset, uint32_t sizeBytes) {
+ const void * data, size_t sizeBytes, uint32_t comp_offset) {
ThreadIO *io = &((Context *)rsc)->mIO;
uint32_t size = sizeof(RS_CMD_Allocation1DElementData);
if (sizeBytes < DATA_SYNC_SIZE) {
@@ -84,7 +84,7 @@ static inline void rsHCAPI_Allocation1DElementData (RsContext rsc, RsAllocation
cmd->lod = lod;
cmd->data = data;
cmd->comp_offset = comp_offset;
- cmd->bytes = sizeBytes;
+ cmd->data_length = sizeBytes;
if (sizeBytes < DATA_SYNC_SIZE) {
cmd->data = (void *)(cmd+1);
memcpy(cmd+1, data, sizeBytes);
diff --git a/libs/rs/rsMatrix4x4.cpp b/libs/rs/rsMatrix4x4.cpp
index 2d90a98..f34af47 100644
--- a/libs/rs/rsMatrix4x4.cpp
+++ b/libs/rs/rsMatrix4x4.cpp
@@ -305,3 +305,10 @@ void Matrix4x4::vectorMultiply(float *out, const float *in) const {
out[2] = (m[2] * in[0]) + (m[6] * in[1]) + (m[10] * in[2]) + m[14];
out[3] = (m[3] * in[0]) + (m[7] * in[1]) + (m[11] * in[2]) + m[15];
}
+
+void Matrix4x4::logv(const char *s) const {
+ LOGV("%s {%f, %f, %f, %f", s, m[0], m[4], m[8], m[12]);
+ LOGV("%s %f, %f, %f, %f", s, m[1], m[5], m[9], m[13]);
+ LOGV("%s %f, %f, %f, %f", s, m[2], m[6], m[10], m[14]);
+ LOGV("%s %f, %f, %f, %f}", s, m[3], m[7], m[11], m[15]);
+}
diff --git a/libs/rs/rsMatrix4x4.h b/libs/rs/rsMatrix4x4.h
index abf34a3..d30184f 100644
--- a/libs/rs/rsMatrix4x4.h
+++ b/libs/rs/rsMatrix4x4.h
@@ -54,6 +54,7 @@ struct Matrix4x4 : public rs_matrix4x4 {
bool inverseTranspose();
void transpose();
+ void logv(const char *s) const;
void multiply(const rs_matrix4x4 *rhs) {
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index c379b8b..6d0701d 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -267,12 +267,13 @@ namespace android {
namespace renderscript {
RsScript rsi_ScriptCCreate(Context *rsc,
- const char *resName, const char *cacheDir,
- const char *text, uint32_t len)
+ const char *resName, size_t resName_length,
+ const char *cacheDir, size_t cacheDir_length,
+ const char *text, uint32_t text_length)
{
ScriptC *s = new ScriptC(rsc);
- if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, len)) {
+ if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) {
// Error during compile, destroy s and return null.
delete s;
return NULL;
diff --git a/libs/rs/spec.l b/libs/rs/spec.l
index 6a9010fe..c8af891 100644
--- a/libs/rs/spec.l
+++ b/libs/rs/spec.l
@@ -20,6 +20,19 @@ ID [a-zA-Z_][a-zA-Z0-9_]*
int typeNextState;
+ void checkPointerType() {
+ VarType *lastType = currType;
+ if (lastType->ptrLevel) {
+ currType = &apis[apiCount].params[apis[apiCount].paramCount];
+ currType->type = 4;
+ sprintf(currType->typeName, "%s", "size_t");
+ if (lastType->name[0]) {
+ sprintf(currType->name, "%s_length", lastType->name);
+ }
+ apis[apiCount].paramCount++;
+ }
+ }
+
extern "C" int yylex();
%%
@@ -145,6 +158,7 @@ ID [a-zA-Z_][a-zA-Z0-9_]*
<api_entry_param>{ID} {
memcpy(currType->name, yytext, yyleng);
+ checkPointerType();
BEGIN(api_entry2);
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index a7ac9ed..80cc94e 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -422,9 +422,10 @@ public class MediaScanner
private long mFileSize;
private String mWriter;
private int mCompilation;
+ private boolean mNoMedia; // flag to suppress file from appearing in media tables
public FileCacheEntry beginFile(String path, String mimeType, long lastModified,
- long fileSize, boolean isDirectory) {
+ long fileSize, boolean isDirectory, boolean noMedia) {
mMimeType = mimeType;
mFileType = 0;
mFileSize = fileSize;
@@ -435,28 +436,31 @@ public class MediaScanner
// to avoid memory allocation
int lastSlash = path.lastIndexOf('/');
if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
- // ignore those ._* files created by MacOS
- if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
- return null;
- }
-
- // ignore album art files created by Windows Media Player:
- // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
- // and AlbumArt_{...}_Small.jpg
- if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
- if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
- path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
- return null;
+ if (!noMedia) {
+ // ignore those ._* files created by MacOS
+ if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
+ noMedia = true;
}
- int length = path.length() - lastSlash - 1;
- if ((length == 17 && path.regionMatches(
- true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
- (length == 10
- && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
- return null;
+
+ // ignore album art files created by Windows Media Player:
+ // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
+ // and AlbumArt_{...}_Small.jpg
+ if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
+ if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
+ path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
+ noMedia = true;
+ }
+ int length = path.length() - lastSlash - 1;
+ if ((length == 17 && path.regionMatches(
+ true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
+ (length == 10
+ && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
+ noMedia = true;
+ }
}
}
}
+ mNoMedia = noMedia;
// try mimeType first, if it is specified
if (mimeType != null) {
@@ -523,36 +527,41 @@ public class MediaScanner
return entry;
}
- public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory) {
+ public void scanFile(String path, long lastModified, long fileSize,
+ boolean isDirectory, boolean noMedia) {
// This is the callback funtion from native codes.
// Log.v(TAG, "scanFile: "+path);
- doScanFile(path, null, lastModified, fileSize, isDirectory, false);
+ doScanFile(path, null, lastModified, fileSize, isDirectory, false, noMedia);
}
public Uri doScanFile(String path, String mimeType, long lastModified,
- long fileSize, boolean isDirectory, boolean scanAlways) {
+ long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) {
Uri result = null;
// long t1 = System.currentTimeMillis();
try {
FileCacheEntry entry = beginFile(path, mimeType, lastModified,
- fileSize, isDirectory);
+ fileSize, isDirectory, noMedia);
// rescan for metadata if file was modified since last scan
if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
- String lowpath = path.toLowerCase();
- boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0);
- boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0);
- boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);
- boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);
- boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
- (!ringtones && !notifications && !alarms && !podcasts);
-
- // we only extract metadata for audio and video files
- if (MediaFile.isAudioFileType(mFileType)
- || MediaFile.isVideoFileType(mFileType)) {
- processFile(path, mimeType, this);
- }
+ if (noMedia) {
+ result = endFile(entry, false, false, false, false, false);
+ } else {
+ String lowpath = path.toLowerCase();
+ boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0);
+ boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0);
+ boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);
+ boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);
+ boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
+ (!ringtones && !notifications && !alarms && !podcasts);
+
+ // we only extract metadata for audio and video files
+ if (MediaFile.isAudioFileType(mFileType)
+ || MediaFile.isVideoFileType(mFileType)) {
+ processFile(path, mimeType, this);
+ }
- result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
+ result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
+ }
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
@@ -689,27 +698,31 @@ public class MediaScanner
map.put(MediaStore.MediaColumns.SIZE, mFileSize);
map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
- if (MediaFile.isVideoFileType(mFileType)) {
- map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING));
- map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING));
- map.put(Video.Media.DURATION, mDuration);
- // FIXME - add RESOLUTION
- } else if (MediaFile.isImageFileType(mFileType)) {
- // FIXME - add DESCRIPTION
- } else if (MediaFile.isAudioFileType(mFileType)) {
- map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
- mArtist : MediaStore.UNKNOWN_STRING);
- map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
- mAlbumArtist.length() > 0) ? mAlbumArtist : null);
- map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
- mAlbum : MediaStore.UNKNOWN_STRING);
- map.put(Audio.Media.COMPOSER, mComposer);
- if (mYear != 0) {
- map.put(Audio.Media.YEAR, mYear);
+ if (!mNoMedia) {
+ if (MediaFile.isVideoFileType(mFileType)) {
+ map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0
+ ? mArtist : MediaStore.UNKNOWN_STRING));
+ map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0
+ ? mAlbum : MediaStore.UNKNOWN_STRING));
+ map.put(Video.Media.DURATION, mDuration);
+ // FIXME - add RESOLUTION
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ // FIXME - add DESCRIPTION
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
+ mArtist : MediaStore.UNKNOWN_STRING);
+ map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
+ mAlbumArtist.length() > 0) ? mAlbumArtist : null);
+ map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
+ mAlbum : MediaStore.UNKNOWN_STRING);
+ map.put(Audio.Media.COMPOSER, mComposer);
+ if (mYear != 0) {
+ map.put(Audio.Media.YEAR, mYear);
+ }
+ map.put(Audio.Media.TRACK, mTrack);
+ map.put(Audio.Media.DURATION, mDuration);
+ map.put(Audio.Media.COMPILATION, mCompilation);
}
- map.put(Audio.Media.TRACK, mTrack);
- map.put(Audio.Media.DURATION, mDuration);
- map.put(Audio.Media.COMPILATION, mCompilation);
}
return map;
}
@@ -719,7 +732,7 @@ public class MediaScanner
throws RemoteException {
// update database
- // use album artist if artist is missing
+ // use album artist if artist is missing
if (mArtist == null || mArtist.length() == 0) {
mArtist = mAlbumArtist;
}
@@ -761,7 +774,7 @@ public class MediaScanner
values.put(Audio.Media.IS_ALARM, alarms);
values.put(Audio.Media.IS_MUSIC, music);
values.put(Audio.Media.IS_PODCAST, podcasts);
- } else if (mFileType == MediaFile.FILE_TYPE_JPEG) {
+ } else if (mFileType == MediaFile.FILE_TYPE_JPEG && !mNoMedia) {
ExifInterface exif = null;
try {
exif = new ExifInterface(entry.mPath);
@@ -814,12 +827,14 @@ public class MediaScanner
}
Uri tableUri = mFilesUri;
- if (MediaFile.isVideoFileType(mFileType)) {
- tableUri = mVideoUri;
- } else if (MediaFile.isImageFileType(mFileType)) {
- tableUri = mImagesUri;
- } else if (MediaFile.isAudioFileType(mFileType)) {
- tableUri = mAudioUri;
+ if (!mNoMedia) {
+ if (MediaFile.isVideoFileType(mFileType)) {
+ tableUri = mVideoUri;
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ tableUri = mImagesUri;
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ tableUri = mAudioUri;
+ }
}
Uri result = null;
if (rowId == 0) {
@@ -930,25 +945,6 @@ public class MediaScanner
}
}
- public void addNoMediaFolder(String path) {
- ContentValues values = new ContentValues();
- values.put(MediaStore.Images.ImageColumns.DATA, "");
- String [] pathSpec = new String[] {path + '%'};
- try {
- // These tables have DELETE_FILE triggers that delete the file from the
- // sd card when deleting the database entry. We don't want to do this in
- // this case, since it would cause those files to be removed if a .nomedia
- // file was added after the fact, when in that case we only want the database
- // entries to be removed.
- mMediaProvider.update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values,
- MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
- mMediaProvider.update(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values,
- MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
- } catch (RemoteException e) {
- throw new RuntimeException();
- }
- }
-
private int getFileTypeFromDrm(String path) {
if (!isDrmEnabled()) {
return 0;
@@ -1228,13 +1224,37 @@ public class MediaScanner
// always scan the file, so we can return the content://media Uri for existing files
return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),
- false, true);
+ false, true, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
return null;
}
}
+ public static boolean isNoMediaPath(String path) {
+ if (path == null) return false;
+
+ // return true if file or any parent directory has name starting with a dot
+ if (path.indexOf("/.") >= 0) return true;
+
+ // now check to see if any parent directories have a ".nomedia" file
+ // start from 1 so we don't bother checking in the root directory
+ int offset = 1;
+ while (offset >= 0) {
+ int slashIndex = path.indexOf('/', offset);
+ if (slashIndex > offset) {
+ slashIndex++; // move past slash
+ File file = new File(path.substring(0, slashIndex) + ".nomedia");
+ if (file.exists()) {
+ // we have a .nomedia in one of the parent directories
+ return true;
+ }
+ }
+ offset = slashIndex;
+ }
+ return false;
+ }
+
public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
initialize(volumeName);
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
@@ -1279,7 +1299,7 @@ public class MediaScanner
// always scan the file, so we can return the content://media Uri for existing files
mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(),
- (format == MtpConstants.FORMAT_ASSOCIATION), true);
+ (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path));
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
diff --git a/media/java/android/media/MediaScannerClient.java b/media/java/android/media/MediaScannerClient.java
index ac326ef..b326671 100644
--- a/media/java/android/media/MediaScannerClient.java
+++ b/media/java/android/media/MediaScannerClient.java
@@ -21,9 +21,8 @@ package android.media;
*/
public interface MediaScannerClient
{
- public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory);
-
- public void addNoMediaFolder(String path);
+ public void scanFile(String path, long lastModified, long fileSize,
+ boolean isDirectory, boolean noMedia);
/**
* Called by native code to return metadata extracted from media files.
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index a3dd136..9151799 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -67,7 +67,7 @@ public:
mScanFileMethodID = env->GetMethodID(
mediaScannerClientInterface,
"scanFile",
- "(Ljava/lang/String;JJZ)V");
+ "(Ljava/lang/String;JJZZ)V");
mHandleStringTagMethodID = env->GetMethodID(
mediaScannerClientInterface,
@@ -78,11 +78,6 @@ public:
mediaScannerClientInterface,
"setMimeType",
"(Ljava/lang/String;)V");
-
- mAddNoMediaFolderMethodID = env->GetMethodID(
- mediaScannerClientInterface,
- "addNoMediaFolder",
- "(Ljava/lang/String;)V");
}
}
@@ -95,7 +90,7 @@ public:
// Returns true if it succeeded, false if an exception occured
// in the Java code
virtual bool scanFile(const char* path, long long lastModified,
- long long fileSize, bool isDirectory)
+ long long fileSize, bool isDirectory, bool noMedia)
{
LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)",
path, lastModified, fileSize, isDirectory);
@@ -106,7 +101,7 @@ public:
}
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
- fileSize, isDirectory);
+ fileSize, isDirectory, noMedia);
mEnv->DeleteLocalRef(pathStr);
return (!mEnv->ExceptionCheck());
@@ -149,30 +144,12 @@ public:
return (!mEnv->ExceptionCheck());
}
- // Returns true if it succeeded, false if an exception occured
- // in the Java code
- virtual bool addNoMediaFolder(const char* path)
- {
- LOGV("addNoMediaFolder: path(%s)", path);
- jstring pathStr;
- if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
- return false;
- }
-
- mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
-
- mEnv->DeleteLocalRef(pathStr);
- return (!mEnv->ExceptionCheck());
- }
-
-
private:
JNIEnv *mEnv;
jobject mClient;
jmethodID mScanFileMethodID;
jmethodID mHandleStringTagMethodID;
jmethodID mSetMimeTypeMethodID;
- jmethodID mAddNoMediaFolderMethodID;
};
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 06708da..585cd30 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -29,6 +29,7 @@
#include "MtpDatabase.h"
#include "MtpDataPacket.h"
+#include "MtpObjectInfo.h"
#include "MtpProperty.h"
#include "MtpStringBuffer.h"
#include "MtpUtils.h"
@@ -138,7 +139,7 @@ public:
MtpDataPacket& packet);
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet);
+ MtpObjectInfo& info);
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
MtpString& outFilePath,
@@ -744,7 +745,7 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
}
MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet) {
+ MtpObjectInfo& info) {
char date[20];
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -754,46 +755,27 @@ MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
- MtpStorageID storageID = intValues[0];
- MtpObjectFormat format = intValues[1];
- MtpObjectHandle parent = intValues[2];
+ info.mStorageID = intValues[0];
+ info.mFormat = intValues[1];
+ info.mParent = intValues[2];
env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
uint64_t size = longValues[0];
- uint64_t modified = longValues[1];
+ info.mCompressedSize = (size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size);
+ info.mDateModified = longValues[1];
env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
-// int associationType = (format == MTP_FORMAT_ASSOCIATION ?
+// info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
// MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
// MTP_ASSOCIATION_TYPE_UNDEFINED);
- int associationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
-
- packet.putUInt32(storageID);
- packet.putUInt16(format);
- packet.putUInt16(0); // protection status
- packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
- packet.putUInt16(0); // thumb format
- packet.putUInt32(0); // thumb compressed size
- packet.putUInt32(0); // thumb pix width
- packet.putUInt32(0); // thumb pix height
- packet.putUInt32(0); // image pix width
- packet.putUInt32(0); // image pix height
- packet.putUInt32(0); // image bit depth
- packet.putUInt32(parent);
- packet.putUInt16(associationType);
- packet.putUInt32(0); // association desc
- packet.putUInt32(0); // sequence number
+ info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
- packet.putString(str); // file name
+ MtpString temp(str);
+ info.mName = strdup((const char *)temp);
env->ReleaseCharArrayElements(mStringBuffer, str, 0);
- packet.putEmptyString();
- formatDateTime(modified, date, sizeof(date));
- packet.putString(date); // date modified
- packet.putEmptyString(); // keywords
-
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return MTP_RESPONSE_OK;
}
diff --git a/media/jni/mediaeditor/VideoBrowserInternal.h b/media/jni/mediaeditor/VideoBrowserInternal.h
index ed63129..3cfb6b9 100755
--- a/media/jni/mediaeditor/VideoBrowserInternal.h
+++ b/media/jni/mediaeditor/VideoBrowserInternal.h
@@ -67,7 +67,7 @@
{ \
if (M4OSA_NULL != p) \
{ \
- M4OSA_free((M4OSA_MemAddr32)p) ; \
+ free(p) ; \
p = M4OSA_NULL ; \
} \
}
diff --git a/media/jni/mediaeditor/VideoBrowserMain.c b/media/jni/mediaeditor/VideoBrowserMain.c
index cddab60..6ef688d 100755
--- a/media/jni/mediaeditor/VideoBrowserMain.c
+++ b/media/jni/mediaeditor/VideoBrowserMain.c
@@ -73,7 +73,7 @@ M4OSA_ERR videoBrowserSetWindow(
if (pC->m_frameColorType == VideoBrowser_kGB565) {
pC->m_outputPlane[0].u_stride = pC->m_outputPlane[0].u_width << 1;
- pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)M4OSA_malloc(
+ pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(
pC->m_outputPlane[0].u_stride * pC->m_outputPlane[0].u_height,
VIDEOBROWSER, (M4OSA_Char *)"output plane");
@@ -154,7 +154,7 @@ M4OSA_ERR videoBrowserCreate(
CHECK_PTR(videoBrowserCreate, pURL, err, M4ERR_PARAMETER);
/*--- Create context ---*/
- pContext = (VideoBrowserContext*)M4OSA_malloc(
+ pContext = (VideoBrowserContext*)M4OSA_32bitAlignedMalloc(
sizeof(VideoBrowserContext),
VIDEOBROWSER, (M4OSA_Char*)"Video browser context");
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index ea73e11..5696433 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -28,7 +28,6 @@ extern "C" {
#include <M4OSA_FileWriter.h>
#include <M4OSA_Memory.h>
#include <M4OSA_Debug.h>
-#include <M4OSA_String.h>
#include <M4OSA_Thread.h>
#include <M4VSS3GPP_API.h>
#include <M4xVSS_API.h>
@@ -2465,7 +2464,7 @@ videoEditClasses_getEffectSettings(
if (pSettings->xVSS.pFramingFilePath != M4OSA_NULL)
{
pSettings->xVSS.pFramingBuffer =
- (M4VIFI_ImagePlane *)M4OSA_malloc(sizeof(M4VIFI_ImagePlane),
+ (M4VIFI_ImagePlane *)M4OSA_32bitAlignedMalloc(sizeof(M4VIFI_ImagePlane),
0x00,(M4OSA_Char *)"framing buffer");
}
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index b792295..c95a0c2 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -41,15 +41,12 @@ extern "C" {
#include <M4OSA_FileCommon.h>
#include <M4OSA_FileReader.h>
#include <M4OSA_FileWriter.h>
-#include <M4OSA_FileExtra.h>
#include <M4OSA_Memory.h>
-#include <M4OSA_String.h>
#include <M4OSA_Thread.h>
#include <M4xVSS_API.h>
#include <M4VSS3GPP_ErrorCodes.h>
#include <M4MCS_API.h>
#include <M4MCS_ErrorCodes.h>
-#include <M4MDP_API.h>
#include <M4READER_Common.h>
#include <M4WRITER_common.h>
};
@@ -416,7 +413,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
LOGV("MSG_TYPE_OVERLAY_UPDATE");
if (pContext->mOverlayFileName != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName);
+ free(pContext->mOverlayFileName);
pContext->mOverlayFileName = NULL;
}
@@ -424,7 +421,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
strlen((const char*)pContext->pEditSettings->Effects[overlayEffectIndex].xVSS.pFramingFilePath);
pContext->mOverlayFileName =
- (char*)M4OSA_malloc(overlayFileNameLen+1,
+ (char*)M4OSA_32bitAlignedMalloc(overlayFileNameLen+1,
M4VS, (M4OSA_Char*)"videoEdito JNI overlayFile");
if (pContext->mOverlayFileName != NULL) {
strncpy (pContext->mOverlayFileName,
@@ -454,7 +451,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
case MSG_TYPE_OVERLAY_CLEAR:
isSendProgress = false;
if (pContext->mOverlayFileName != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName);
+ free(pContext->mOverlayFileName);
pContext->mOverlayFileName = NULL;
}
@@ -504,7 +501,7 @@ static int videoEditor_stopPreview(JNIEnv* pEnv,
lastProgressTimeMs = pContext->mPreviewController->stopPreview();
if (pContext->mOverlayFileName != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName);
+ free(pContext->mOverlayFileName);
pContext->mOverlayFileName = NULL;
}
@@ -750,7 +747,7 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
framesizeYuv = width * height * 1.5;
- pixelArray = (M4VIFI_UInt8 *)M4OSA_malloc(framesizeYuv, M4VS,
+ pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,
(M4OSA_Char*)"videoEditor pixelArray");
if (pixelArray == M4OSA_NULL) {
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
@@ -768,7 +765,7 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
ClipProperties.uiVideoHeight,
&tnTimeMs);
if (result != M4NO_ERROR) {
- M4OSA_free((M4OSA_MemAddr32)pixelArray);
+ free(pixelArray);
ThumbnailClose(tnContext);
return -1;
}
@@ -792,12 +789,12 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
/**
* Allocate output YUV planes
*/
- yuvPlane = (M4VIFI_ImagePlane*)M4OSA_malloc(3*sizeof(M4VIFI_ImagePlane), M4VS,
+ yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS,
(M4OSA_Char*)"videoEditor_renderPreviewFrame Output plane YUV");
if (yuvPlane == M4OSA_NULL) {
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
"videoEditor_renderPreviewFrame() malloc error for yuv plane");
- M4OSA_free((M4OSA_MemAddr32)pixelArray);
+ free(pixelArray);
pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
return -1;
@@ -902,10 +899,10 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==\
/*M4VIDEOEDITING_kFileType_JPG */ M4VIDEOEDITING_kFileType_ARGB8888) {
- M4OSA_free((M4OSA_MemAddr32)frameStr.pBuffer);
+ free(frameStr.pBuffer);
} else {
- M4OSA_free((M4OSA_MemAddr32)yuvPlane[0].pac_data);
- M4OSA_free((M4OSA_MemAddr32)yuvPlane);
+ free(yuvPlane[0].pac_data);
+ free(yuvPlane);
}
return tnTimeMs;
}
@@ -981,7 +978,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
framesizeYuv = ((frameWidth)*(frameHeight)*1.5);
- pixelArray = (M4VIFI_UInt8 *)M4OSA_malloc(framesizeYuv, M4VS,\
+ pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,\
(M4OSA_Char*)"videoEditor pixelArray");
if (pixelArray == M4OSA_NULL) {
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
@@ -996,7 +993,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
frameWidth,
frameHeight, &timeMs);
if (result != M4NO_ERROR) {
- M4OSA_free((M4OSA_MemAddr32)pixelArray);
+ free(pixelArray);
ThumbnailClose(tnContext);
return fromMs;
}
@@ -1066,7 +1063,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
(M4NO_ERROR != result), result);
/* free the pixelArray and yuvPlane[0].pac_data */
- M4OSA_free((M4OSA_MemAddr32)yuvPlane[0].pac_data);
+ free(yuvPlane[0].pac_data);
ThumbnailClose(tnContext);
@@ -1148,7 +1145,7 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_init()");
- pOutputParams = (M4MCS_OutputParams *)M4OSA_malloc(
+ pOutputParams = (M4MCS_OutputParams *)M4OSA_32bitAlignedMalloc(
sizeof(M4MCS_OutputParams),0x00,
(M4OSA_Char *)"M4MCS_OutputParams");
videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
@@ -1158,14 +1155,14 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
return M4ERR_ALLOC;
}
- pEncodingParams = (M4MCS_EncodingParams *)M4OSA_malloc(
+ pEncodingParams = (M4MCS_EncodingParams *)M4OSA_32bitAlignedMalloc(
sizeof(M4MCS_EncodingParams),0x00,
(M4OSA_Char *)"M4MCS_EncodingParams");
videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
(M4OSA_NULL == pEncodingParams),
"not initialized");
if (needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return M4ERR_ALLOC;
}
@@ -1179,15 +1176,15 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
(M4OSA_NULL == mcsContext),
"not initialized");
if(needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return result;
}
// generate the path for temp 3gp output file
- pTemp3gpFilePath = (M4OSA_Char*) M4OSA_malloc (
+ pTemp3gpFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc (
(strlen((const char*)pContext->initParams.pTempPath)
+ strlen((const char*)TEMP_MCS_OUT_FILE_PATH)) + 1 /* for null termination */ , 0x0,
(M4OSA_Char*)"Malloc for temp 3gp file");
@@ -1204,9 +1201,9 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
}
else {
M4MCS_abort(mcsContext);
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return M4ERR_ALLOC;
}
@@ -1231,12 +1228,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
if(needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+ free(pTemp3gpFilePath);
pTemp3gpFilePath = M4OSA_NULL;
M4MCS_abort(mcsContext);
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return result;
}
@@ -1281,12 +1278,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
if (needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+ free(pTemp3gpFilePath);
pTemp3gpFilePath = M4OSA_NULL;
M4MCS_abort(mcsContext);
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return result;
}
@@ -1311,12 +1308,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
if (needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+ free(pTemp3gpFilePath);
pTemp3gpFilePath = M4OSA_NULL;
M4MCS_abort(mcsContext);
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return result;
}
@@ -1327,12 +1324,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
if (needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+ free(pTemp3gpFilePath);
pTemp3gpFilePath = M4OSA_NULL;
M4MCS_abort(mcsContext);
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return result;
}
@@ -1379,12 +1376,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4MCS_WAR_TRANSCODING_DONE != result), result);
if (needToBeLoaded == false) {
- M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+ free(pTemp3gpFilePath);
pTemp3gpFilePath = M4OSA_NULL;
M4MCS_abort(mcsContext);
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
pOutputParams = M4OSA_NULL;
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
pEncodingParams = M4OSA_NULL;
return result;
}
@@ -1399,13 +1396,13 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio() EXIT ");
if (pTemp3gpFilePath != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath);
+ free(pTemp3gpFilePath);
}
if (pOutputParams != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)pOutputParams);
+ free(pOutputParams);
}
if(pEncodingParams != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)pEncodingParams);
+ free(pEncodingParams);
}
return result;
}
@@ -1420,7 +1417,7 @@ static int removeAlphafromRGB8888 (
LOGV("removeAlphafromRGB8888: width %d", pFramingCtx->width);
- M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_malloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data");
+ M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data");
if (pTmpData == M4OSA_NULL) {
LOGE("Failed to allocate memory for Image clip");
return M4ERR_ALLOC;
@@ -1433,7 +1430,7 @@ static int removeAlphafromRGB8888 (
if ((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL))
{
LOGE("removeAlphafromRGB8888: Can not open the file ");
- M4OSA_free((M4OSA_MemAddr32)pTmpData);
+ free(pTmpData);
return M4ERR_FILE_NOT_FOUND;
}
@@ -1443,22 +1440,22 @@ static int removeAlphafromRGB8888 (
{
LOGE("removeAlphafromRGB8888: can not read the data ");
M4OSA_fileReadClose(lImageFileFp);
- M4OSA_free((M4OSA_MemAddr32)pTmpData);
+ free(pTmpData);
return lerr;
}
M4OSA_fileReadClose(lImageFileFp);
M4OSA_UInt32 frameSize = (pFramingCtx->width * pFramingCtx->height * 3); //Size of RGB 888 data.
- pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_malloc(
+ pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(
sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"Image clip RGB888 data");
- pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_malloc(
+ pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(
frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data");
if (pFramingCtx->FramingRgb == M4OSA_NULL)
{
LOGE("Failed to allocate memory for Image clip");
- M4OSA_free((M4OSA_MemAddr32)pTmpData);
+ free(pTmpData);
return M4ERR_ALLOC;
}
@@ -1468,7 +1465,7 @@ static int removeAlphafromRGB8888 (
pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i];
j++;
}
- M4OSA_free((M4OSA_MemAddr32)pTmpData);
+ free(pTmpData);
return M4NO_ERROR;
}
@@ -1566,7 +1563,7 @@ videoEditor_populateSettings(
{
if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) {
if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\
+ free(pContext->pEditSettings->\
Effects[j].xVSS.pFramingBuffer);
pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL;
}
@@ -1613,7 +1610,7 @@ videoEditor_populateSettings(
if (pContext->pEditSettings->nbEffects > 0)
{
pOverlayIndex
- = (int*) M4OSA_malloc(pContext->pEditSettings->nbEffects * sizeof(int), 0,
+ = (int*) M4OSA_32bitAlignedMalloc(pContext->pEditSettings->nbEffects * sizeof(int), 0,
(M4OSA_Char*)"pOverlayIndex");
if (pOverlayIndex == M4OSA_NULL) {
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
@@ -1633,7 +1630,7 @@ videoEditor_populateSettings(
M4xVSS_FramingStruct *aFramingCtx = M4OSA_NULL;
aFramingCtx
- = (M4xVSS_FramingStruct*)M4OSA_malloc(sizeof(M4xVSS_FramingStruct), M4VS,
+ = (M4xVSS_FramingStruct*)M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_FramingStruct), M4VS,
(M4OSA_Char*)"M4xVSS_internalDecodeGIF: Context of the framing effect");
if (aFramingCtx == M4OSA_NULL)
{
@@ -1671,7 +1668,7 @@ videoEditor_populateSettings(
if (needToBeLoaded == false) {
M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect returned 0x%x", result);
if (aFramingCtx != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx);
+ free(aFramingCtx);
aFramingCtx = M4OSA_NULL;
}
goto videoEditor_populateSettings_cleanup;
@@ -1699,7 +1696,7 @@ videoEditor_populateSettings(
//for RGB565
pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0;
pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data =
- (M4VIFI_UInt8 *)M4OSA_malloc(width*height*2,
+ (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(width*height*2,
0x00,(M4OSA_Char *)"pac_data buffer");
if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data == M4OSA_NULL) {
@@ -1720,31 +1717,31 @@ videoEditor_populateSettings(
if (aFramingCtx->FramingYuv != M4OSA_NULL )
{
if (aFramingCtx->FramingYuv[0].pac_data != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv[0].pac_data);
+ free(aFramingCtx->FramingYuv[0].pac_data);
aFramingCtx->FramingYuv[0].pac_data = M4OSA_NULL;
}
if (aFramingCtx->FramingYuv[1].pac_data != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv[1].pac_data);
+ free(aFramingCtx->FramingYuv[1].pac_data);
aFramingCtx->FramingYuv[1].pac_data = M4OSA_NULL;
}
if (aFramingCtx->FramingYuv[2].pac_data != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv[2].pac_data);
+ free(aFramingCtx->FramingYuv[2].pac_data);
aFramingCtx->FramingYuv[2].pac_data = M4OSA_NULL;
}
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv);
+ free(aFramingCtx->FramingYuv);
aFramingCtx->FramingYuv = M4OSA_NULL;
}
if (aFramingCtx->FramingRgb->pac_data != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingRgb->pac_data);
+ free(aFramingCtx->FramingRgb->pac_data);
aFramingCtx->FramingRgb->pac_data = M4OSA_NULL;
}
if (aFramingCtx->FramingRgb != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingRgb);
+ free(aFramingCtx->FramingRgb);
aFramingCtx->FramingRgb = M4OSA_NULL;
}
if (aFramingCtx != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)aFramingCtx);
+ free(aFramingCtx);
aFramingCtx = M4OSA_NULL;
}
nbOverlays++;
@@ -1775,11 +1772,11 @@ videoEditor_populateSettings(
/* free previous allocations , if any */
if (pContext->mAudioSettings != M4OSA_NULL) {
if (pContext->mAudioSettings->pFile != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pFile);
+ free(pContext->mAudioSettings->pFile);
pContext->mAudioSettings->pFile = M4OSA_NULL;
}
if (pContext->mAudioSettings->pPCMFilePath != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pPCMFilePath);
+ free(pContext->mAudioSettings->pPCMFilePath);
pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
}
}
@@ -1850,7 +1847,7 @@ videoEditor_populateSettings(
strPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPath, M4OSA_NULL);
if (pTempChar != NULL) {
- pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_malloc(
+ pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(
(M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0,
(M4OSA_Char*)"strPath allocation " );
if (pContext->mAudioSettings->pFile != M4OSA_NULL) {
@@ -1875,7 +1872,7 @@ videoEditor_populateSettings(
strPCMPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPCMPath, M4OSA_NULL);
if (pTempChar != NULL) {
- pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_malloc(
+ pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(
(M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0,
(M4OSA_Char*)"strPCMPath allocation " );
if (pContext->mAudioSettings->pPCMFilePath != M4OSA_NULL) {
@@ -1986,7 +1983,7 @@ videoEditor_populateSettings_cleanup:
{
if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data != \
M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\
+ free(pContext->pEditSettings->\
Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data);
pContext->pEditSettings->\
Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data = M4OSA_NULL;
@@ -1999,7 +1996,7 @@ videoEditor_populateSettings_cleanup:
{
if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) {
if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\
+ free(pContext->pEditSettings->\
Effects[j].xVSS.pFramingBuffer);
pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL;
}
@@ -2009,7 +2006,7 @@ videoEditor_populateSettings_cleanup:
if (pOverlayIndex != M4OSA_NULL)
{
- M4OSA_free((M4OSA_MemAddr32)pOverlayIndex);
+ free(pOverlayIndex);
pOverlayIndex = M4OSA_NULL;
}
return;
@@ -2498,7 +2495,7 @@ videoEditor_init(
(M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath,
NULL, M4OSA_NULL);
pContext->initParams.pTempPath = (M4OSA_Char *)
- M4OSA_malloc(strlen((const char *)tmpString) + 1, 0x0,
+ M4OSA_32bitAlignedMalloc(strlen((const char *)tmpString) + 1, 0x0,
(M4OSA_Char *)"tempPath");
//initialize the first char. so that strcat works.
M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath;
@@ -2506,7 +2503,7 @@ videoEditor_init(
strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString,
(size_t)strlen((const char *)tmpString));
strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1);
- M4OSA_free((M4OSA_MemAddr32)tmpString);
+ free(tmpString);
pContext->mIsUpdateOverlay = false;
pContext->mOverlayFileName = NULL;
}
@@ -2564,7 +2561,7 @@ videoEditor_init(
"not initialized");
pContext->mAudioSettings =
(M4xVSS_AudioMixingSettings *)
- M4OSA_malloc(sizeof(M4xVSS_AudioMixingSettings),0x0,
+ M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_AudioMixingSettings),0x0,
(M4OSA_Char *)"mAudioSettings");
videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
(M4OSA_NULL == pContext->mAudioSettings),
@@ -3066,15 +3063,15 @@ videoEditor_release(
if(pContext->mAudioSettings != M4OSA_NULL)
{
if (pContext->mAudioSettings->pFile != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pFile);
+ free(pContext->mAudioSettings->pFile);
pContext->mAudioSettings->pFile = M4OSA_NULL;
}
if (pContext->mAudioSettings->pPCMFilePath != NULL) {
- M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pPCMFilePath);
+ free(pContext->mAudioSettings->pPCMFilePath);
pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
}
- M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings);
+ free(pContext->mAudioSettings);
pContext->mAudioSettings = M4OSA_NULL;
}
videoEditor_freeContext(pEnv, &pContext);
@@ -3252,7 +3249,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL,
*******************************************************************************/
samplesCountInBytes = (samplesPerValue * sizeof(M4OSA_UInt16) * channels);
- bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_malloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0,
+ bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0,
(M4OSA_Char*)"AudioGraph" );
if ( bufferIn.m_dataAddress != M4OSA_NULL) {
bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16);
@@ -3380,7 +3377,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL,
/******************************************************************************
CLOSE AND FREE ALLOCATIONS
*******************************************************************************/
- M4OSA_free((M4OSA_MemAddr32)bufferIn.m_dataAddress);
+ free(bufferIn.m_dataAddress);
M4OSA_fileReadClose(inputFileHandle);
M4OSA_fileWriteClose(outFileHandle);
/* final finish callback */
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index 339c0d1..53e7de1 100755
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -25,7 +25,6 @@ extern "C" {
#include <M4OSA_FileReader.h>
#include <M4OSA_FileWriter.h>
#include <M4OSA_Memory.h>
-#include <M4OSA_String.h>
#include <M4OSA_Thread.h>
#include <M4xVSS_API.h>
#include <M4VSS3GPP_ErrorCodes.h>
@@ -82,14 +81,6 @@ static const VideoEdit_Osal_Result gkRESULTS[] =
VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_BAD_MODE_ACCESS ),
VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_INVALID_POSITION ),
- // M4OSA_String.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_BAD_STRING ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_CONV_FAILED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_OVERFLOW ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_BAD_ARGS ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_STR_OVERFLOW ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_STR_NOT_FOUND ),
-
// M4OSA_Thread.h
VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_THREAD_NOT_STARTED ),
@@ -276,7 +267,7 @@ videoEditOsal_alloc(
if (*pResult)
{
// Allocate memory for the settings.
- pData = (M4VSS3GPP_EditSettings*)M4OSA_malloc(size, 0, (M4OSA_Char*)pDescription);
+ pData = (M4VSS3GPP_EditSettings*)M4OSA_32bitAlignedMalloc(size, 0, (M4OSA_Char*)pDescription);
if (M4OSA_NULL != pData)
{
// Reset the allocated memory.
@@ -314,10 +305,10 @@ videoEditOsal_free(
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "videoEditOsal_free()");
// Log the API call.
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "M4OSA_free()");
+ VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "free");
// Free the memory.
- M4OSA_free((M4OSA_MemAddr32)pData);
+ free(pData);
#ifdef OSAL_MEM_LEAK_DEBUG
// Update the allocated block count.
gAllocatedBlockCount--;
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index 39221f3..9de7207 100755
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -34,13 +34,11 @@ extern "C" {
#include <M4OSA_FileReader.h>
#include <M4OSA_FileWriter.h>
#include <M4OSA_Memory.h>
-#include <M4OSA_String.h>
#include <M4OSA_Thread.h>
#include <M4VSS3GPP_API.h>
#include <M4VSS3GPP_ErrorCodes.h>
#include <M4MCS_API.h>
#include <M4MCS_ErrorCodes.h>
-#include <M4MDP_API.h>
#include <M4READER_Common.h>
#include <M4WRITER_common.h>
#include <M4DECODER_Common.h>
diff --git a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
index 461bdd0..fe3734f 100755
--- a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
@@ -165,7 +165,7 @@ M4OSA_ERR ThumbnailOpen(M4OSA_Context *pPContext,
CHECK_PTR(ThumbnailOpen, pString, err, M4ERR_BAD_CONTEXT);
/*--- Create context ---*/
- pContext = (ThumbnailContext*)M4OSA_malloc(sizeof(ThumbnailContext), VIDEOBROWSER,
+ pContext = (ThumbnailContext*)M4OSA_32bitAlignedMalloc(sizeof(ThumbnailContext), VIDEOBROWSER,
(M4OSA_Char*)"Thumbnail context") ;
M4OSA_TRACE3_1("context value is = %d",pContext);
CHECK_PTR(ThumbnailOpen, pContext, err, M4ERR_ALLOC);
@@ -211,7 +211,7 @@ ThumbnailOpen_cleanUp:
{
videoBrowserCleanUp(pContext->m_pVideoBrowser) ;
}
- M4OSA_free((M4OSA_MemAddr32)pContext) ;
+ free(pContext) ;
}
return err;
}
@@ -320,7 +320,7 @@ void ThumbnailClose(const M4OSA_Context pContext)
{
videoBrowserCleanUp(pC->m_pVideoBrowser);
}
- M4OSA_free((M4OSA_MemAddr32)pC);
+ free(pC);
}
ThumbnailClose_cleanUp:
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 2399216..8885bd5 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -192,8 +192,9 @@ public:
}
status_t invoke(const Parcel& request, Parcel *reply)
- { // Avoid doing any extra copy. The interface descriptor should
- // have been set by MediaPlayer.java.
+ {
+ // Avoid doing any extra copy. The interface descriptor should
+ // have been set by MediaPlayer.java.
return remote()->transact(INVOKE, request, reply);
}
@@ -334,8 +335,8 @@ status_t BnMediaPlayer::onTransact(
} break;
case INVOKE: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
- invoke(data, reply);
- return NO_ERROR;
+ status_t result = invoke(data, reply);
+ return result;
} break;
case SET_METADATA_FILTER: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 5ec573e..4e22175 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -70,8 +70,7 @@ status_t MediaScanner::processDirectory(
client.setLocale(locale());
status_t result =
- doProcessDirectory(
- pathBuffer, pathRemaining, client, exceptionCheck, exceptionEnv);
+ doProcessDirectory(pathBuffer, pathRemaining, client, false, exceptionCheck, exceptionEnv);
free(pathBuffer);
@@ -80,20 +79,18 @@ status_t MediaScanner::processDirectory(
status_t MediaScanner::doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client,
- ExceptionCheck exceptionCheck, void *exceptionEnv) {
+ bool noMedia, ExceptionCheck exceptionCheck, void *exceptionEnv) {
// place to copy file or directory name
char* fileSpot = path + strlen(path);
struct dirent* entry;
struct stat statbuf;
- // ignore directories that contain a ".nomedia" file
+ // Treat all files as non-media in directories that contain a ".nomedia" file
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
if (access(path, F_OK) == 0) {
- LOGD("found .nomedia, skipping directory\n");
- fileSpot[0] = 0;
- client.addNoMediaFolder(path);
- return OK;
+ LOGD("found .nomedia, setting noMedia flag\n");
+ noMedia = true;
}
// restore path
@@ -138,19 +135,20 @@ status_t MediaScanner::doProcessDirectory(
}
if (type == DT_REG || type == DT_DIR) {
if (type == DT_DIR) {
- // ignore directories with a name that starts with '.'
+ // set noMedia flag on directories with a name that starts with '.'
// for example, the Mac ".Trashes" directory
- if (name[0] == '.') continue;
+ if (name[0] == '.')
+ noMedia = true;
// report the directory to the client
if (stat(path, &statbuf) == 0) {
- client.scanFile(path, statbuf.st_mtime, 0, true);
+ client.scanFile(path, statbuf.st_mtime, 0, true, noMedia);
}
// and now process its contents
strcat(fileSpot, "/");
int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
- exceptionCheck, exceptionEnv);
+ noMedia, exceptionCheck, exceptionEnv);
if (err) {
// pass exceptions up - ignore other errors
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
@@ -159,7 +157,7 @@ status_t MediaScanner::doProcessDirectory(
}
} else {
stat(path, &statbuf);
- client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false);
+ client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false, noMedia);
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
}
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index f9db1a1..01d0a92 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2028,14 +2028,18 @@ status_t MPEG4Source::read(
size_t dstOffset = 0;
while (srcOffset < size) {
- CHECK(srcOffset + mNALLengthSize <= size);
- size_t nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
- srcOffset += mNALLengthSize;
+ bool isMalFormed = (srcOffset + mNALLengthSize > size);
+ size_t nalLength = 0;
+ if (!isMalFormed) {
+ nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
+ srcOffset += mNALLengthSize;
+ isMalFormed = srcOffset + nalLength > size;
+ }
- if (srcOffset + nalLength > size) {
+ if (isMalFormed) {
+ LOGE("Video is malformed");
mBuffer->release();
mBuffer = NULL;
-
return ERROR_MALFORMED;
}
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
index 616836c..0d0d6c2 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -41,8 +41,6 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
return NULL;
}
- LOGI("Found XING header.");
-
return seeker;
}
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 4d9a1ae..d7bde00 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -23,6 +23,7 @@ namespace android {
class MtpDataPacket;
class MtpProperty;
+class MtpObjectInfo;
class MtpDatabase {
public:
@@ -81,7 +82,7 @@ public:
MtpDataPacket& packet) = 0;
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet) = 0;
+ MtpObjectInfo& info) = 0;
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
MtpString& outFilePath,
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 1668ecf..9f3037d 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -63,6 +63,12 @@ static const CodeEntry sOperationCodes[] = {
{ "MTP_OPERATION_GET_OBJECT_REFERENCES", 0x9810 },
{ "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 },
{ "MTP_OPERATION_SKIP", 0x9820 },
+ // android extensions
+ { "MTP_OPERATION_GET_PARTIAL_OBJECT_64", 0x95C1 },
+ { "MTP_OPERATION_SEND_PARTIAL_OBJECT", 0x95C2 },
+ { "MTP_OPERATION_TRUNCATE_OBJECT", 0x95C3 },
+ { "MTP_OPERATION_BEGIN_EDIT_OBJECT", 0x95C4 },
+ { "MTP_OPERATION_END_EDIT_OBJECT", 0x95C5 },
{ 0, 0 },
};
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 37e02a3..b744b5b 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -30,6 +30,7 @@
#include "MtpDebug.h"
#include "MtpDatabase.h"
+#include "MtpObjectInfo.h"
#include "MtpProperty.h"
#include "MtpServer.h"
#include "MtpStorage.h"
@@ -79,6 +80,12 @@ static const MtpOperationCode kSupportedOperationCodes[] = {
MTP_OPERATION_GET_OBJECT_REFERENCES,
MTP_OPERATION_SET_OBJECT_REFERENCES,
// MTP_OPERATION_SKIP,
+ // Android extension for direct file IO
+ MTP_OPERATION_GET_PARTIAL_OBJECT_64,
+ MTP_OPERATION_SEND_PARTIAL_OBJECT,
+ MTP_OPERATION_TRUNCATE_OBJECT,
+ MTP_OPERATION_BEGIN_EDIT_OBJECT,
+ MTP_OPERATION_END_EDIT_OBJECT,
};
static const MtpEventCode kSupportedEventCodes[] = {
@@ -218,6 +225,15 @@ void MtpServer::run() {
}
}
+ // commit any open edits
+ int count = mObjectEditList.size();
+ for (int i = 0; i < count; i++) {
+ ObjectEdit* edit = mObjectEditList[i];
+ commitEdit(edit);
+ delete edit;
+ }
+ mObjectEditList.clear();
+
if (mSessionOpen)
mDatabase->sessionEnded();
}
@@ -252,6 +268,39 @@ void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
}
}
+void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
+ uint64_t size, MtpObjectFormat format, int fd) {
+ ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
+ mObjectEditList.add(edit);
+}
+
+MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
+ int count = mObjectEditList.size();
+ for (int i = 0; i < count; i++) {
+ ObjectEdit* edit = mObjectEditList[i];
+ if (edit->mHandle == handle) return edit;
+ }
+ return NULL;
+}
+
+void MtpServer::removeEditObject(MtpObjectHandle handle) {
+ int count = mObjectEditList.size();
+ for (int i = 0; i < count; i++) {
+ ObjectEdit* edit = mObjectEditList[i];
+ if (edit->mHandle == handle) {
+ delete edit;
+ mObjectEditList.removeAt(i);
+ return;
+ }
+ }
+ LOGE("ObjectEdit not found in removeEditObject");
+}
+
+void MtpServer::commitEdit(ObjectEdit* edit) {
+ mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
+}
+
+
bool MtpServer::handleRequest() {
Mutex::Autolock autoLock(mMutex);
@@ -322,7 +371,8 @@ bool MtpServer::handleRequest() {
response = doGetObject();
break;
case MTP_OPERATION_GET_PARTIAL_OBJECT:
- response = doGetPartialObject();
+ case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
+ response = doGetPartialObject(operation);
break;
case MTP_OPERATION_SEND_OBJECT_INFO:
response = doSendObjectInfo();
@@ -339,6 +389,18 @@ bool MtpServer::handleRequest() {
case MTP_OPERATION_GET_DEVICE_PROP_DESC:
response = doGetDevicePropDesc();
break;
+ case MTP_OPERATION_SEND_PARTIAL_OBJECT:
+ response = doSendPartialObject();
+ break;
+ case MTP_OPERATION_TRUNCATE_OBJECT:
+ response = doTruncateObject();
+ break;
+ case MTP_OPERATION_BEGIN_EDIT_OBJECT:
+ response = doBeginEditObject();
+ break;
+ case MTP_OPERATION_END_EDIT_OBJECT:
+ response = doEndEditObject();
+ break;
default:
LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
@@ -363,7 +425,7 @@ MtpResponseCode MtpServer::doGetDeviceInfo() {
mData.putUInt16(MTP_STANDARD_VERSION);
mData.putUInt32(6); // MTP Vendor Extension ID
mData.putUInt16(MTP_STANDARD_VERSION);
- string.set("microsoft.com: 1.0;");
+ string.set("microsoft.com: 1.0; android.com: 1.0;");
mData.putString(string); // MTP Extensions
mData.putUInt16(0); //Functional Mode
mData.putAUInt16(kSupportedOperationCodes,
@@ -601,7 +663,40 @@ MtpResponseCode MtpServer::doGetObjectInfo() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1);
- return mDatabase->getObjectInfo(handle, mData);
+ MtpObjectInfo info(handle);
+ MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
+ if (result == MTP_RESPONSE_OK) {
+ char date[20];
+
+ mData.putUInt32(info.mStorageID);
+ mData.putUInt16(info.mFormat);
+ mData.putUInt16(info.mProtectionStatus);
+
+ // if object is being edited the database size may be out of date
+ uint32_t size = info.mCompressedSize;
+ ObjectEdit* edit = getEditObject(handle);
+ if (edit)
+ size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
+ mData.putUInt32(size);
+
+ mData.putUInt16(info.mThumbFormat);
+ mData.putUInt32(info.mThumbCompressedSize);
+ mData.putUInt32(info.mThumbPixWidth);
+ mData.putUInt32(info.mThumbPixHeight);
+ mData.putUInt32(info.mImagePixWidth);
+ mData.putUInt32(info.mImagePixHeight);
+ mData.putUInt32(info.mImagePixDepth);
+ mData.putUInt32(info.mParent);
+ mData.putUInt16(info.mAssociationType);
+ mData.putUInt32(info.mAssociationDesc);
+ mData.putUInt32(info.mSequenceNumber);
+ mData.putString(info.mName);
+ mData.putEmptyString(); // date created
+ formatDateTime(info.mDateModified, date, sizeof(date));
+ mData.putString(date); // date modified
+ mData.putEmptyString(); // keywords
+ }
+ return result;
}
MtpResponseCode MtpServer::doGetObject() {
@@ -641,12 +736,22 @@ MtpResponseCode MtpServer::doGetObject() {
return MTP_RESPONSE_OK;
}
-MtpResponseCode MtpServer::doGetPartialObject() {
+MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1);
- uint32_t offset = mRequest.getParameter(2);
- uint32_t length = mRequest.getParameter(3);
+ uint64_t offset;
+ uint32_t length;
+ offset = mRequest.getParameter(2);
+ if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
+ // android extension with 64 bit offset
+ uint64_t offset2 = mRequest.getParameter(3);
+ offset = offset | (offset2 << 32);
+ length = mRequest.getParameter(4);
+ } else {
+ // standard GetPartialObject
+ length = mRequest.getParameter(3);
+ }
MtpString pathBuf;
int64_t fileLength;
MtpObjectFormat format;
@@ -933,4 +1038,113 @@ MtpResponseCode MtpServer::doGetDevicePropDesc() {
return MTP_RESPONSE_OK;
}
+MtpResponseCode MtpServer::doSendPartialObject() {
+ if (!hasStorage())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ uint64_t offset = mRequest.getParameter(2);
+ uint64_t offset2 = mRequest.getParameter(3);
+ offset = offset | (offset2 << 32);
+ uint32_t length = mRequest.getParameter(4);
+
+ ObjectEdit* edit = getEditObject(handle);
+ if (!edit) {
+ LOGE("object not open for edit in doSendPartialObject");
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+
+ // can't start writing past the end of the file
+ if (offset > edit->mSize) {
+ LOGD("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize);
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+
+ // read the header
+ int ret = mData.readDataHeader(mFD);
+ // FIXME - check for errors here.
+
+ // reset so we don't attempt to send this back
+ mData.reset();
+
+ const char* filePath = (const char *)edit->mPath;
+ LOGV("receiving partial %s %lld %ld\n", filePath, offset, length);
+ mtp_file_range mfr;
+ mfr.fd = edit->mFD;
+ mfr.offset = offset;
+ mfr.length = length;
+
+ // transfer the file
+ ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ LOGV("MTP_RECEIVE_FILE returned %d", ret);
+ if (ret < 0) {
+ mResponse.setParameter(1, 0);
+ if (errno == ECANCELED)
+ return MTP_RESPONSE_TRANSACTION_CANCELLED;
+ else
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+ mResponse.setParameter(1, length);
+ uint64_t end = offset + length;
+ if (end > edit->mSize) {
+ edit->mSize = end;
+ }
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doTruncateObject() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ ObjectEdit* edit = getEditObject(handle);
+ if (!edit) {
+ LOGE("object not open for edit in doTruncateObject");
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+
+ uint64_t offset = mRequest.getParameter(2);
+ uint64_t offset2 = mRequest.getParameter(3);
+ offset |= (offset2 << 32);
+ if (ftruncate(edit->mFD, offset) != 0) {
+ return MTP_RESPONSE_GENERAL_ERROR;
+ } else {
+ edit->mSize = offset;
+ return MTP_RESPONSE_OK;
+ }
+}
+
+MtpResponseCode MtpServer::doBeginEditObject() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ if (getEditObject(handle)) {
+ LOGE("object already open for edit in doBeginEditObject");
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+
+ MtpString path;
+ int64_t fileLength;
+ MtpObjectFormat format;
+ int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
+ if (result != MTP_RESPONSE_OK)
+ return result;
+
+ int fd = open((const char *)path, O_RDWR | O_EXCL);
+ if (fd < 0) {
+ LOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+
+ addEditObject(handle, path, fileLength, format, fd);
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doEndEditObject() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ ObjectEdit* edit = getEditObject(handle);
+ if (!edit) {
+ LOGE("object not open for edit in doEndEditObject");
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+
+ commitEdit(edit);
+ removeEditObject(handle);
+ return MTP_RESPONSE_OK;
+}
+
} // namespace android
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index fa729a8..b06eb28 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -65,6 +65,27 @@ private:
Mutex mMutex;
+ // represents an MTP object that is being edited using the android extensions
+ // for direct editing (BeginEditObject, SendPartialObject, TruncateObject and EndEditObject)
+ class ObjectEdit {
+ public:
+ MtpObjectHandle mHandle;
+ MtpString mPath;
+ uint64_t mSize;
+ MtpObjectFormat mFormat;
+ int mFD;
+
+ ObjectEdit(MtpObjectHandle handle, const char* path, uint64_t size,
+ MtpObjectFormat format, int fd)
+ : mHandle(handle), mPath(path), mSize(size), mFormat(format), mFD(fd) {
+ }
+
+ virtual ~ObjectEdit() {
+ close(mFD);
+ }
+ };
+ Vector<ObjectEdit*> mObjectEditList;
+
public:
MtpServer(int fd, MtpDatabase* database,
int fileGroup, int filePerm, int directoryPerm);
@@ -86,6 +107,12 @@ private:
void sendStoreRemoved(MtpStorageID id);
void sendEvent(MtpEventCode code, uint32_t param1);
+ void addEditObject(MtpObjectHandle handle, MtpString& path,
+ uint64_t size, MtpObjectFormat format, int fd);
+ ObjectEdit* getEditObject(MtpObjectHandle handle);
+ void removeEditObject(MtpObjectHandle handle);
+ void commitEdit(ObjectEdit* edit);
+
bool handleRequest();
MtpResponseCode doGetDeviceInfo();
@@ -106,12 +133,16 @@ private:
MtpResponseCode doGetObjectPropList();
MtpResponseCode doGetObjectInfo();
MtpResponseCode doGetObject();
- MtpResponseCode doGetPartialObject();
+ MtpResponseCode doGetPartialObject(MtpOperationCode operation);
MtpResponseCode doSendObjectInfo();
MtpResponseCode doSendObject();
MtpResponseCode doDeleteObject();
MtpResponseCode doGetObjectPropDesc();
MtpResponseCode doGetDevicePropDesc();
+ MtpResponseCode doSendPartialObject();
+ MtpResponseCode doTruncateObject();
+ MtpResponseCode doBeginEditObject();
+ MtpResponseCode doEndEditObject();
};
}; // namespace android
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index 8bc2e22..d270df5 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -391,6 +391,19 @@
#define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811
#define MTP_OPERATION_SKIP 0x9820
+// Android extensions for direct file IO
+
+// Same as GetPartialObject, but with 64 bit offset
+#define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1
+// Same as GetPartialObject64, but copying host to device
+#define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2
+// Truncates file to 64 bit length
+#define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3
+// Must be called before using SendPartialObject and TruncateObject
+#define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4
+// Called to commit changes made by SendPartialObject and TruncateObject
+#define MTP_OPERATION_END_EDIT_OBJECT 0x95C5
+
// MTP Response Codes
#define MTP_RESPONSE_UNDEFINED 0x2000
#define MTP_RESPONSE_OK 0x2001
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
index aeba213..96cde57 100755
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py
@@ -38,7 +38,7 @@ def generate_api(lines):
"glShaderSource", "glTexImage2D", "glTexSubImage2D"]
# these also needs to be forwarded to DbgContext
- contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
+ contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
for line in lines:
@@ -114,10 +114,10 @@ def generate_api(lines):
else:
getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType)
paramType += "*"
- else:
+ else:
if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0:
setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
- else:
+ else:
setMsgParameters += " msg.set_arg%d(%s);\n" % (paramIndex, paramName)
if paramIndex < len(parameters) - 1:
arguments += ', '
@@ -156,7 +156,7 @@ def generate_api(lines):
} caller;"""
print setCallerMembers
print setMsgParameters
-
+
if line.find("*") >= 0 or line.find(":") >= 0:
print " // FIXME: check for pointer usage"
if inout in ["in", "inout"]:
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 57e008c..535b13e 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -25,7 +25,7 @@ def generate_egl_entries(output, lines, i):
line = line.split(",")[1].strip() #extract EGL function name
output.write(" %s = %d;\n" % (line, i))
i += 1
- return i
+ return i
def generate_gl_entries(output,lines,i):
@@ -118,7 +118,7 @@ message Message
optional int32 arg4 = 16;
optional int32 arg5 = 17;
optional int32 arg6 = 18;
- optional int32 arg7 = 19;
+ optional int32 arg7 = 19; // glDrawArrays/Elements sets this to active number of attributes
optional int32 arg8 = 20;
optional bytes data = 10; // variable length data used for GL call
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 879f1a8..73003c8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -511,7 +511,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
// This will populate st.shownPanelView
- if (!initializePanelContent(st) || (st.shownPanelView == null)) {
+ if (!initializePanelContent(st) || !st.hasPanelItems()) {
return;
}
@@ -2976,6 +2976,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
refreshDecorView = false;
}
+ public boolean hasPanelItems() {
+ if (shownPanelView == null) return false;
+
+ if (isInExpandedMode) {
+ return expandedMenuPresenter.getAdapter().getCount() > 0;
+ } else {
+ return ((ViewGroup) shownPanelView).getChildCount() > 0;
+ }
+ }
+
/**
* Unregister and free attached MenuPresenters. They will be recreated as needed.
*/
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 65321b7..a37ccc7 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2615,6 +2615,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ public int getLockedRotationLw() {
+ synchronized (mLock) {
+ if (false) {
+ // Not yet working.
+ if (mHdmiPlugged) {
+ return Surface.ROTATION_0;
+ } else if (mLidOpen == LID_OPEN) {
+ return mLidOpenRotation;
+ } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
+ return mCarDockRotation;
+ } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
+ return mDeskDockRotation;
+ } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
+ return mUserRotation;
+ }
+ }
+ return -1;
+ }
+ }
+
private int getCurrentLandscapeRotation(int lastRotation) {
// if the user has locked rotation, we ignore the sensor
if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index ced8feb..8ba0a0b 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -20,8 +20,8 @@ import com.android.server.wm.InputFilter;
import android.content.Context;
import android.util.Slog;
+import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy;
@@ -32,10 +32,35 @@ import android.view.WindowManagerPolicy;
*/
public class AccessibilityInputFilter extends InputFilter {
private static final String TAG = "AccessibilityInputFilter";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private final Context mContext;
+ /**
+ * This is an interface for explorers that take a {@link MotionEvent}
+ * stream and perform touch exploration of the screen content.
+ */
+ public interface Explorer {
+ /**
+ * Handles a {@link MotionEvent}.
+ *
+ * @param event The event to handle.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ public void onMotionEvent(MotionEvent event, int policyFlags);
+
+ /**
+ * Requests that the explorer clears its internal state.
+ *
+ * @param event The last received event.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ public void clear(MotionEvent event, int policyFlags);
+ }
+
+ private TouchExplorer mTouchExplorer;
+ private int mTouchscreenSourceDeviceId;
+
public AccessibilityInputFilter(Context context) {
super(context.getMainLooper());
mContext = context;
@@ -60,27 +85,27 @@ public class AccessibilityInputFilter extends InputFilter {
@Override
public void onInputEvent(InputEvent event, int policyFlags) {
if (DEBUG) {
- Slog.d(TAG, "Accessibility input filter received input event: "
- + event + ", policyFlags=0x" + Integer.toHexString(policyFlags));
+ Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
+ + Integer.toHexString(policyFlags));
}
-
- // To prove that this is working as intended, we will silently transform
- // Q key presses into non-repeating Z's as part of this stub implementation.
- // TODO: Replace with the real thing.
- if (event instanceof KeyEvent) {
- final KeyEvent keyEvent = (KeyEvent)event;
- if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_Q) {
- if (keyEvent.getRepeatCount() == 0) {
- sendInputEvent(new KeyEvent(keyEvent.getDownTime(), keyEvent.getEventTime(),
- keyEvent.getAction(), KeyEvent.KEYCODE_Z, keyEvent.getRepeatCount(),
- keyEvent.getMetaState(), keyEvent.getDeviceId(), keyEvent.getScanCode(),
- keyEvent.getFlags(), keyEvent.getSource()),
- policyFlags | WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
+ if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
+ MotionEvent motionEvent = (MotionEvent) event;
+ int deviceId = event.getDeviceId();
+ if (mTouchscreenSourceDeviceId != deviceId) {
+ mTouchscreenSourceDeviceId = deviceId;
+ if (mTouchExplorer != null) {
+ mTouchExplorer.clear(motionEvent, policyFlags);
+ } else {
+ mTouchExplorer = new TouchExplorer(this, mContext);
}
- return;
}
+ if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) != 0) {
+ mTouchExplorer.onMotionEvent(motionEvent, policyFlags);
+ } else {
+ mTouchExplorer.clear(motionEvent, policyFlags);
+ }
+ } else {
+ super.onInputEvent(event, policyFlags);
}
-
- super.onInputEvent(event, policyFlags);
}
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7a483aa..1ad8047 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -56,6 +56,7 @@ import android.view.accessibility.IAccessibilityManagerClient;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -74,6 +75,8 @@ import java.util.Set;
public class AccessibilityManagerService extends IAccessibilityManager.Stub
implements HandlerCaller.Callback {
+ private static final boolean DEBUG = false;
+
private static final String LOG_TAG = "AccessibilityManagerService";
private static int sIdCounter = 0;
@@ -102,6 +105,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':');
+ private final SparseArray<List<ServiceInfo>> mFeedbackTypeToEnabledServicesMap =
+ new SparseArray<List<ServiceInfo>>();
+
private PackageManager mPackageManager;
private int mHandledFeedbackTypes = 0;
@@ -211,7 +217,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
manageServicesLocked();
- updateInputFilterLocked();
}
return;
@@ -252,7 +257,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
unbindAllServicesLocked();
}
updateClientsLocked();
- updateInputFilterLocked();
}
}
});
@@ -300,6 +304,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ public List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
+ synchronized (mLock) {
+ List<ServiceInfo> enabledServices = mFeedbackTypeToEnabledServicesMap.get(feedbackType);
+ if (enabledServices == null) {
+ return Collections.emptyList();
+ }
+ return enabledServices;
+ }
+ }
+
public void interrupt() {
synchronized (mLock) {
for (int i = 0, count = mServices.size(); i < count; i++) {
@@ -339,6 +353,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
service.mNotificationTimeout = info.notificationTimeout;
service.mIsDefault = (info.flags & AccessibilityServiceInfo.DEFAULT) != 0;
+
+ updateStateOnEnabledService(service);
}
return;
default:
@@ -449,7 +465,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
try {
listener.onAccessibilityEvent(event);
- if (false) {
+ if (DEBUG) {
Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
}
} catch (RemoteException re) {
@@ -469,10 +485,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* @return True if the service was removed, false otherwise.
*/
private boolean removeDeadServiceLocked(Service service) {
- if (false) {
+ if (DEBUG) {
Slog.i(LOG_TAG, "Dead service " + service.mService + " removed");
}
mHandler.removeMessages(service.mId);
+ updateStateOnDisabledService(service);
return mServices.remove(service);
}
@@ -593,7 +610,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (isEnabled) {
if (enabledServices.contains(componentName)) {
if (service == null) {
- service = new Service(componentName);
+ service = new Service(componentName, intalledService);
}
service.bind();
} else if (!enabledServices.contains(componentName)) {
@@ -644,6 +661,47 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
/**
+ * Updates the set of enabled services for a given feedback type and
+ * if more than one of them provides spoken feedback enables touch
+ * exploration.
+ *
+ * @param service An enable service.
+ */
+ private void updateStateOnEnabledService(Service service) {
+ int feedbackType = service.mFeedbackType;
+ List<ServiceInfo> enabledServices = mFeedbackTypeToEnabledServicesMap.get(feedbackType);
+ if (enabledServices == null) {
+ enabledServices = new ArrayList<ServiceInfo>();
+ mFeedbackTypeToEnabledServicesMap.put(feedbackType, enabledServices);
+ }
+ enabledServices.add(service.mServiceInfo);
+
+ // We enable touch exploration if at least one
+ // enabled service provides spoken feedback.
+ if (enabledServices.size() > 0
+ && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) {
+ updateClientsLocked();
+ updateInputFilterLocked();
+ }
+ }
+
+ private void updateStateOnDisabledService(Service service) {
+ List<ServiceInfo> enabledServices =
+ mFeedbackTypeToEnabledServicesMap.get(service.mFeedbackType);
+ if (enabledServices == null) {
+ return;
+ }
+ enabledServices.remove(service.mServiceInfo);
+ // We disable touch exploration if no
+ // enabled service provides spoken feedback.
+ if (enabledServices.isEmpty()
+ && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) {
+ updateClientsLocked();
+ updateInputFilterLocked();
+ }
+ }
+
+ /**
* This class represents an accessibility service. It stores all per service
* data required for the service management, provides API for starting/stopping the
* service and is responsible for adding/removing the service in the data structures
@@ -654,6 +712,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
class Service extends IAccessibilityServiceConnection.Stub implements ServiceConnection {
int mId = 0;
+ ServiceInfo mServiceInfo;
+
IBinder mService;
IEventListener mServiceInterface;
@@ -678,9 +738,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final SparseArray<AccessibilityEvent> mPendingEvents =
new SparseArray<AccessibilityEvent>();
- Service(ComponentName componentName) {
+ Service(ComponentName componentName, ServiceInfo serviceInfo) {
mId = sIdCounter++;
mComponentName = componentName;
+ mServiceInfo = serviceInfo;
mIntent = new Intent().setComponent(mComponentName);
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.accessibility_binding_label);
@@ -712,6 +773,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mContext.unbindService(this);
mComponentNameToServiceMap.remove(mComponentName);
mServices.remove(this);
+ updateStateOnDisabledService(this);
return true;
}
return false;
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
new file mode 100644
index 0000000..4ba6060
--- /dev/null
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -0,0 +1,1540 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END;
+import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START;
+
+import com.android.server.accessibility.AccessibilityInputFilter.Explorer;
+import com.android.server.wm.InputFilter;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.view.WindowManagerPolicy;
+import android.view.MotionEvent.PointerCoords;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import java.util.Arrays;
+
+/**
+ * This class is a strategy for performing touch exploration. It
+ * transforms the motion event stream by modifying, adding, replacing,
+ * and consuming certain events. The interaction model is:
+ *
+ * <ol>
+ * <li>1. One finger moving around performs touch exploration.</li>
+ * <li>2. Two close fingers moving in the same direction perform a drag.</li>
+ * <li>3. Multi-finger gestures are delivered to view hierarchy.</li>
+ * <li>4. Pointers that have not moved more than a specified distance after they
+ * went down are considered inactive.</li>
+ * <li>5. Two fingers moving too far from each other or in different directions
+ * are considered a multi-finger gesture.</li>
+ * <li>6. Tapping on the last touch explored location within given time and
+ * distance slop performs a click.</li>
+ * <li>7. Tapping and holding for a while on the last touch explored location within
+ * given time and distance slop performs a long press.</li>
+ * <ol>
+ *
+ * @hide
+ */
+public class TouchExplorer implements Explorer {
+ private static final boolean DEBUG = false;
+
+ // Tag for logging received events.
+ private static final String LOG_TAG_RECEIVED = "TouchExplorer-RECEIVED";
+ // Tag for logging injected events.
+ private static final String LOG_TAG_INJECTED = "TouchExplorer-INJECTED";
+ // Tag for logging the current state.
+ private static final String LOG_TAG_STATE = "TouchExplorer-STATE";
+
+ // States this explorer can be in.
+ private static final int STATE_TOUCH_EXPLORING = 0x00000001;
+ private static final int STATE_DRAGGING = 0x00000002;
+ private static final int STATE_DELEGATING = 0x00000004;
+
+ // Human readable symbolic names for the states of the explorer.
+ private static final SparseArray<String> sStateSymbolicNames = new SparseArray<String>();
+ static {
+ SparseArray<String> symbolicNames = sStateSymbolicNames;
+ symbolicNames.append(STATE_TOUCH_EXPLORING, "STATE_TOUCH_EXPLORING");
+ symbolicNames.append(STATE_DRAGGING, "STATE_DRAGING");
+ symbolicNames.append(STATE_DELEGATING, "STATE_DELEGATING");
+ }
+
+ // Invalid pointer ID.
+ private static final int INVALID_POINTER_ID = -1;
+
+ // The coefficient by which to multiply
+ // ViewConfiguration.#getScaledTouchExplorationTapSlop()
+ // to compute #mDraggingDistance.
+ private static final int COEFFICIENT_DRAGGING_DISTANCE = 2;
+
+ // The time slop in milliseconds for activating an item after it has
+ // been touch explored. Tapping on an item within this slop will perform
+ // a click and tapping and holding down a long press.
+ private static final long ACTIVATION_TIME_SLOP = 2000;
+
+ // This constant captures the current implementation detail that
+ // pointer IDs are between 0 and 31 inclusive (subject to change).
+ // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
+ private static final int MAX_POINTER_COUNT = 32;
+
+ // The minimum of the cosine between the vectors of two moving
+ // pointers so they can be considered moving in the same direction.
+ private static final float MIN_ANGLE_COS = 0.866025404f; // cos(pi/6)
+
+ // The delay for sending a hover enter event.
+ private static final long DELAY_SEND_HOVER_MOVE = 200;
+
+ // Temporary array for storing pointer IDs.
+ private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
+
+ // Temporary array for mapping new to old pointer IDs while filtering inactive pointers.
+ private final int [] mTempNewToOldPointerIndexMap = new int[MAX_POINTER_COUNT];
+
+ // Temporary array for storing PointerCoords
+ private final PointerCoords[] mTempPointerCoords= new PointerCoords[MAX_POINTER_COUNT];
+
+ // The maximal distance between two pointers so they are
+ // considered to be performing a drag operation.
+ private final float mDraggingDistance;
+
+ // The distance from the last touch explored location tapping within
+ // which would perform a click and tapping and holding a long press.
+ private final int mTouchExplorationTapSlop;
+
+ // Context handle for accessing resources.
+ private final Context mContext;
+
+ // The InputFilter this tracker is associated with i.e. the filter
+ // which delegates event processing to this touch explorer.
+ private final InputFilter mInputFilter;
+
+ // Helper class for tracking pointers on the screen, for example which
+ // pointers are down, which are active, etc.
+ private final PointerTracker mPointerTracker;
+
+ // Handle to the accessibility manager for firing accessibility events
+ // announcing touch exploration gesture start and end.
+ private final AccessibilityManager mAccessibilityManager;
+
+ // The last event that was received while performing touch exploration.
+ private MotionEvent mLastTouchExploreEvent;
+
+ // The current state of the touch explorer.
+ private int mCurrentState = STATE_TOUCH_EXPLORING;
+
+ // Flag whether a touch exploration gesture is in progress.
+ private boolean mTouchExploreGestureInProgress;
+
+ // The ID of the pointer used for dragging.
+ private int mDraggingPointerId;
+
+ // Handler for performing asynchronous operations.
+ private final Handler mHandler;
+
+ // Command for delayed sending of a hover event.
+ private final SendHoverDelayed mSendHoverDelayed;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param inputFilter The input filter associated with this explorer.
+ * @param context A context handle for accessing resources.
+ */
+ public TouchExplorer(InputFilter inputFilter, Context context) {
+ mInputFilter = inputFilter;
+ mTouchExplorationTapSlop =
+ ViewConfiguration.get(context).getScaledTouchExplorationTapSlop();
+ mDraggingDistance = mTouchExplorationTapSlop * COEFFICIENT_DRAGGING_DISTANCE;
+ mPointerTracker = new PointerTracker(context);
+ mContext = context;
+ mHandler = new Handler(context.getMainLooper());
+ mSendHoverDelayed = new SendHoverDelayed();
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
+
+ // Populate the temporary array with PointerCorrds to be reused.
+ for (int i = 0, count = mTempPointerCoords.length; i < count; i++) {
+ mTempPointerCoords[i] = new PointerCoords();
+ }
+ }
+
+ public void clear(MotionEvent event, int policyFlags) {
+ sendUpForInjectedDownPointers(event, policyFlags);
+ clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onMotionEvent(MotionEvent event, int policyFlags) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG_RECEIVED, "Received event: " + event + ", policyFlags=0x"
+ + Integer.toHexString(policyFlags));
+ Slog.d(LOG_TAG_STATE, sStateSymbolicNames.get(mCurrentState));
+ }
+
+ // Keep track of the pointers's state.
+ mPointerTracker.onReceivedMotionEvent(event);
+
+ switch(mCurrentState) {
+ case STATE_TOUCH_EXPLORING: {
+ handleMotionEventStateTouchExploring(event, policyFlags);
+ } break;
+ case STATE_DRAGGING: {
+ handleMotionEventStateDragging(event, policyFlags);
+ } break;
+ case STATE_DELEGATING: {
+ handleMotionEventStateDelegating(event, policyFlags);
+ } break;
+ default: {
+ throw new IllegalStateException("Illegal state: " + mCurrentState);
+ }
+ }
+ }
+
+ /**
+ * Handles a motion event in touch exploring state.
+ *
+ * @param event The event to be handled.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) {
+ PointerTracker pointerTracker = mPointerTracker;
+ final int activePointerCount = pointerTracker.getActivePointerCount();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ // Send a hover for every finger down so the user gets feedback
+ // where she is currently touching.
+ mSendHoverDelayed.forceSendAndRemove();
+ mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, 0, policyFlags,
+ DELAY_SEND_HOVER_MOVE);
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ switch (activePointerCount) {
+ case 0: {
+ throw new IllegalStateException("The must always be one active pointer in"
+ + "touch exploring state!");
+ }
+ case 1: {
+ // Schedule a hover event which will lead to firing an
+ // accessibility event from the hovered view.
+ mSendHoverDelayed.remove();
+ final int pointerId = pointerTracker.getPrimaryActivePointerId();
+ final int pointerIndex = event.findPointerIndex(pointerId);
+ final int lastAction = pointerTracker.getLastInjectedHoverAction();
+ // If a schedules hover enter for another pointer is delivered we send move.
+ final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER)
+ ? MotionEvent.ACTION_HOVER_MOVE
+ : MotionEvent.ACTION_HOVER_ENTER;
+ mSendHoverDelayed.post(event, action, pointerIndex, policyFlags,
+ DELAY_SEND_HOVER_MOVE);
+
+ if (mLastTouchExploreEvent == null) {
+ break;
+ }
+
+ // If more pointers down on the screen since the last touch
+ // exploration we discard the last cached touch explore event.
+ if (event.getPointerCount() != mLastTouchExploreEvent.getPointerCount()) {
+ mLastTouchExploreEvent = null;
+ }
+ } break;
+ default: {
+ /* do nothing - let the code for ACTION_MOVE decide what to do */
+ } break;
+ }
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ switch (activePointerCount) {
+ case 0: {
+ /* do nothing - no active pointers so we swallow the event */
+ } break;
+ case 1: {
+ final int pointerId = pointerTracker.getPrimaryActivePointerId();
+ final int pointerIndex = event.findPointerIndex(pointerId);
+
+ // Detect touch exploration gesture start by having one active pointer
+ // that moved more than a given distance.
+ if (!mTouchExploreGestureInProgress) {
+ final float deltaX = pointerTracker.getReceivedPointerDownX(pointerId)
+ - event.getX(pointerIndex);
+ final float deltaY = pointerTracker.getReceivedPointerDownY(pointerId)
+ - event.getY(pointerIndex);
+ final double moveDelta = Math.hypot(deltaX, deltaY);
+
+ if (moveDelta > mTouchExplorationTapSlop) {
+ mTouchExploreGestureInProgress = true;
+ sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
+ // Make sure the scheduled down/move event is sent.
+ mSendHoverDelayed.forceSendAndRemove();
+ sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex,
+ policyFlags);
+ }
+ } else {
+ // Touch exploration gesture in progress so send a hover event.
+ sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex,
+ policyFlags);
+ }
+
+ // Detect long press on the last touch explored position.
+ if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null) {
+
+ // If the down was not in the time slop => nothing else to do.
+ final long pointerDownTime =
+ pointerTracker.getReceivedPointerDownTime(pointerId);
+ final long lastExploreTime = mLastTouchExploreEvent.getEventTime();
+ final long deltaTimeExplore = pointerDownTime - lastExploreTime;
+ if (deltaTimeExplore > ACTIVATION_TIME_SLOP) {
+ mLastTouchExploreEvent = null;
+ break;
+ }
+
+ // If the pointer moved more than the tap slop => nothing else to do.
+ final float deltaX = mLastTouchExploreEvent.getX(pointerIndex)
+ - event.getX(pointerIndex);
+ final float deltaY = mLastTouchExploreEvent.getY(pointerIndex)
+ - event.getY(pointerIndex);
+ final float moveDelta = (float) Math.hypot(deltaX, deltaY);
+ if (moveDelta > mTouchExplorationTapSlop) {
+ mLastTouchExploreEvent = null;
+ break;
+ }
+
+ // If down for long enough we get a long press.
+ final long deltaTimeMove = event.getEventTime() - pointerDownTime;
+ if (deltaTimeMove > ViewConfiguration.getLongPressTimeout()) {
+ mCurrentState = STATE_DELEGATING;
+ // Make sure the scheduled hover exit is delivered.
+ mSendHoverDelayed.forceSendAndRemove();
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ sendMotionEvent(event, policyFlags);
+ mTouchExploreGestureInProgress = false;
+ mLastTouchExploreEvent = null;
+ }
+ }
+ } break;
+ case 2: {
+ // Make sure the scheduled hover enter is delivered.
+ mSendHoverDelayed.forceSendAndRemove();
+ // We want to no longer hover over the location so subsequent
+ // touch at the same spot will generate a hover enter.
+ final int pointerId = pointerTracker.getPrimaryActivePointerId();
+ final int pointerIndex = event.findPointerIndex(pointerId);
+ sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex,
+ policyFlags);
+
+ if (isDraggingGesture(event)) {
+ // Two pointers moving in the same direction within
+ // a given distance perform a drag.
+ mCurrentState = STATE_DRAGGING;
+ if (mTouchExploreGestureInProgress) {
+ sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+ mTouchExploreGestureInProgress = false;
+ }
+ mDraggingPointerId = pointerTracker.getPrimaryActivePointerId();
+ sendDragEvent(event, MotionEvent.ACTION_DOWN, policyFlags);
+ } else {
+ // Two pointers moving arbitrary are delegated to the view hierarchy.
+ mCurrentState = STATE_DELEGATING;
+ if (mTouchExploreGestureInProgress) {
+ sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+ mTouchExploreGestureInProgress = false;
+ }
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ }
+ } break;
+ default: {
+ // Make sure the scheduled hover enter is delivered.
+ mSendHoverDelayed.forceSendAndRemove();
+ // We want to no longer hover over the location so subsequent
+ // touch at the same spot will generate a hover enter.
+ final int pointerId = pointerTracker.getPrimaryActivePointerId();
+ final int pointerIndex = event.findPointerIndex(pointerId);
+ sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex,
+ policyFlags);
+
+ // More than two pointers are delegated to the view hierarchy.
+ mCurrentState = STATE_DELEGATING;
+ mSendHoverDelayed.remove();
+ if (mTouchExploreGestureInProgress) {
+ sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+ mTouchExploreGestureInProgress = false;
+ }
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ }
+ }
+ } break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP: {
+ switch (activePointerCount) {
+ case 0: {
+ // If the pointer that went up was not active we have nothing to do.
+ if (!pointerTracker.wasLastReceivedUpPointerActive()) {
+ break;
+ }
+
+ // If touch exploring announce the end of the gesture.
+ if (mTouchExploreGestureInProgress) {
+ sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+ mTouchExploreGestureInProgress = false;
+ }
+
+ // Detect whether to activate i.e. click on the last explored location.
+ if (mLastTouchExploreEvent != null) {
+ final int pointerId = pointerTracker.getLastReceivedUpPointerId();
+
+ // If the down was not in the time slop => nothing else to do.
+ final long eventTime =
+ pointerTracker.getLastReceivedUpPointerDownTime();
+ final long exploreTime = mLastTouchExploreEvent.getEventTime();
+ final long deltaTime = eventTime - exploreTime;
+ if (deltaTime > ACTIVATION_TIME_SLOP) {
+ mSendHoverDelayed.forceSendAndRemove();
+ scheduleHoverExit(event, policyFlags);
+ mLastTouchExploreEvent = MotionEvent.obtain(event);
+ break;
+ }
+
+ // If the pointer moved more than the tap slop => nothing else to do.
+ final int pointerIndex = event.findPointerIndex(pointerId);
+ final float deltaX = pointerTracker.getLastReceivedUpPointerDownX()
+ - event.getX(pointerIndex);
+ final float deltaY = pointerTracker.getLastReceivedUpPointerDownY()
+ - event.getY(pointerIndex);
+ final float deltaMove = (float) Math.hypot(deltaX, deltaY);
+ if (deltaMove > mTouchExplorationTapSlop) {
+ mSendHoverDelayed.forceSendAndRemove();
+ scheduleHoverExit(event, policyFlags);
+ mLastTouchExploreEvent = MotionEvent.obtain(event);
+ break;
+ }
+
+ // All preconditions are met, so click the last explored location.
+ mSendHoverDelayed.forceSendAndRemove();
+ sendActionDownAndUp(mLastTouchExploreEvent, policyFlags);
+ mLastTouchExploreEvent = null;
+ } else {
+ mSendHoverDelayed.forceSendAndRemove();
+ scheduleHoverExit(event, policyFlags);
+ mLastTouchExploreEvent = MotionEvent.obtain(event);
+ }
+ } break;
+ }
+ } break;
+ case MotionEvent.ACTION_CANCEL: {
+ final int lastAction = pointerTracker.getLastInjectedHoverAction();
+ if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
+ final int pointerId = pointerTracker.getPrimaryActivePointerId();
+ final int pointerIndex = event.findPointerIndex(pointerId);
+ sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex,
+ policyFlags);
+ }
+ clear();
+ } break;
+ }
+ }
+
+ /**
+ * Handles a motion event in dragging state.
+ *
+ * @param event The event to be handled.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ throw new IllegalStateException("Dragging state can be reached only if two "
+ + "pointers are already down");
+ }
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ // We are in dragging state so we have two pointers and another one
+ // goes down => delegate the three pointers to the view hierarchy
+ mCurrentState = STATE_DELEGATING;
+ sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ final int activePointerCount = mPointerTracker.getActivePointerCount();
+ switch (activePointerCount) {
+ case 2: {
+ if (isDraggingGesture(event)) {
+ // If still dragging send a drag event.
+ sendDragEvent(event, MotionEvent.ACTION_MOVE, policyFlags);
+ } else {
+ // The two pointers are moving either in different directions or
+ // no close enough => delegate the gesture to the view hierarchy.
+ mCurrentState = STATE_DELEGATING;
+ // Send an event to the end of the drag gesture.
+ sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ // Deliver all active pointers to the view hierarchy.
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ }
+ } break;
+ default: {
+ mCurrentState = STATE_DELEGATING;
+ // Send an event to the end of the drag gesture.
+ sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ // Deliver all active pointers to the view hierarchy.
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ }
+ }
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ mCurrentState = STATE_TOUCH_EXPLORING;
+ // Send an event to the end of the drag gesture.
+ sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ } break;
+ case MotionEvent.ACTION_CANCEL: {
+ clear();
+ } break;
+ }
+ }
+
+ /**
+ * Handles a motion event in delegating state.
+ *
+ * @param event The event to be handled.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ public void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ throw new IllegalStateException("Delegating state can only be reached if "
+ + "there is at least one pointer down!");
+ }
+ case MotionEvent.ACTION_UP: {
+ mCurrentState = STATE_TOUCH_EXPLORING;
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ // Check whether some other pointer became active because they have moved
+ // a given distance and if such exist send them to the view hierarchy
+ final int notInjectedCount = mPointerTracker.getNotInjectedActivePointerCount();
+ if (notInjectedCount > 0) {
+ sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+ }
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ // No active pointers => go to initial state.
+ if (mPointerTracker.getActivePointerCount() == 0) {
+ mCurrentState = STATE_TOUCH_EXPLORING;
+ }
+ } break;
+ case MotionEvent.ACTION_CANCEL: {
+ clear();
+ } break;
+ }
+ // Deliver the event striping out inactive pointers.
+ sendMotionEventStripInactivePointers(event, policyFlags);
+ }
+
+ /**
+ * Schedules a hover up event so subsequent poking on the same location after
+ * the scheduled delay will perform exploration.
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void scheduleHoverExit(MotionEvent prototype,
+ int policyFlags) {
+ final int pointerId = mPointerTracker.getLastReceivedUpPointerId();
+ final int pointerIndex = prototype.findPointerIndex(pointerId);
+ // We want to no longer hover over the location so subsequent
+ // touch at the same spot will generate a hover enter.
+ mSendHoverDelayed.post(prototype, MotionEvent.ACTION_HOVER_EXIT,
+ pointerIndex, policyFlags, ACTIVATION_TIME_SLOP);
+ }
+
+ /**
+ * Sends down events to the view hierarchy for all active pointers which are
+ * not already being delivered i.e. pointers that are not yet injected.
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) {
+ PointerCoords[] pointerCoords = mTempPointerCoords;
+ PointerTracker pointerTracker = mPointerTracker;
+ int[] pointerIds = mTempPointerIds;
+ int pointerDataIndex = 0;
+
+ final int pinterCount = prototype.getPointerCount();
+ for (int i = 0; i < pinterCount; i++) {
+ final int pointerId = prototype.getPointerId(i);
+
+ // Skip inactive pointers.
+ if (!pointerTracker.isActivePointer(pointerId)) {
+ continue;
+ }
+ // Skip already delivered pointers.
+ if (pointerTracker.isInjectedPointerDown(pointerId)) {
+ continue;
+ }
+
+ // Populate and inject an event for the current pointer.
+ pointerIds[pointerDataIndex] = pointerId;
+ prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]);
+
+ final long downTime = pointerTracker.getLastInjectedDownEventTime();
+ final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, pointerDataIndex);
+ final int pointerCount = pointerDataIndex + 1;
+ final long pointerDownTime = SystemClock.uptimeMillis();
+
+ MotionEvent event = MotionEvent.obtain(downTime, pointerDownTime,
+ action, pointerCount, pointerIds, pointerCoords, prototype.getMetaState(),
+ prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
+ prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags());
+ sendMotionEvent(event, policyFlags);
+ event.recycle();
+
+ pointerDataIndex++;
+ }
+ }
+
+ /**
+ * Sends up events to the view hierarchy for all active pointers which are
+ * already being delivered i.e. pointers that are injected.
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) {
+ PointerTracker pointerTracker = mPointerTracker;
+ PointerCoords[] pointerCoords = mTempPointerCoords;
+ int[] pointerIds = mTempPointerIds;
+ int pointerDataIndex = 0;
+
+ final int pointerCount = prototype.getPointerCount();
+ for (int i = 0; i < pointerCount; i++) {
+ final int pointerId = prototype.getPointerId(i);
+
+ // Skip non injected down pointers.
+ if (!pointerTracker.isInjectedPointerDown(pointerId)) {
+ continue;
+ }
+
+ // Populate and inject event.
+ pointerIds[pointerDataIndex] = pointerId;
+ prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]);
+
+ final long downTime = pointerTracker.getLastInjectedDownEventTime();
+ final int action = computeInjectionAction(MotionEvent.ACTION_UP, pointerDataIndex);
+ final int newPointerCount = pointerDataIndex + 1;
+ final long eventTime = SystemClock.uptimeMillis();
+
+ MotionEvent event = MotionEvent.obtain(downTime, eventTime, action,
+ newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(),
+ prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
+ prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags());
+
+ sendMotionEvent(event, policyFlags);
+ event.recycle();
+
+ pointerDataIndex++;
+ }
+ }
+
+ /**
+ * Sends a motion event by first stripping the inactive pointers.
+ *
+ * @param prototype The prototype from which to create the injected event.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) {
+ PointerTracker pointerTracker = mPointerTracker;
+
+ // All pointers active therefore we just inject the event as is.
+ if (prototype.getPointerCount() == pointerTracker.getActivePointerCount()) {
+ sendMotionEvent(prototype, policyFlags);
+ return;
+ }
+
+ // No active pointers and the one that just went up was not
+ // active, therefore we have nothing to do.
+ if (pointerTracker.getActivePointerCount() == 0
+ && !pointerTracker.wasLastReceivedUpPointerActive()) {
+ return;
+ }
+
+ // Filter out inactive pointers from the event and inject it.
+ PointerCoords[] pointerCoords = mTempPointerCoords;
+ int[] pointerIds = mTempPointerIds;
+ int [] newToOldPointerIndexMap = mTempNewToOldPointerIndexMap;
+ int newPointerIndex = 0;
+ int actionIndex = prototype.getActionIndex();
+
+ final int oldPointerCount = prototype.getPointerCount();
+ for (int oldPointerIndex = 0; oldPointerIndex < oldPointerCount; oldPointerIndex++) {
+ final int pointerId = prototype.getPointerId(oldPointerIndex);
+
+ // If the pointer is inactive or the pointer that just went up
+ // was inactive we strip the pointer data from the event.
+ if (!pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
+ if (oldPointerIndex <= prototype.getActionIndex()) {
+ actionIndex--;
+ }
+ continue;
+ }
+
+ newToOldPointerIndexMap[newPointerIndex] = oldPointerIndex;
+ pointerIds[newPointerIndex] = pointerId;
+ prototype.getPointerCoords(oldPointerIndex, pointerCoords[newPointerIndex]);
+
+ newPointerIndex++;
+ }
+
+ // If we skipped all pointers => nothing to do.
+ if (newPointerIndex == 0) {
+ return;
+ }
+
+ // Populate and inject the event.
+ final long downTime = pointerTracker.getLastInjectedDownEventTime();
+ final int action = computeInjectionAction(prototype.getActionMasked(), actionIndex);
+ final int newPointerCount = newPointerIndex;
+ MotionEvent prunedEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action,
+ newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(),
+ prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
+ prototype.getEdgeFlags(), prototype.getSource(),prototype.getFlags());
+
+ // Add the filtered history.
+ final int historySize = prototype.getHistorySize();
+ for (int historyIndex = 0; historyIndex < historySize; historyIndex++) {
+ for (int pointerIndex = 0; pointerIndex < newPointerCount; pointerIndex++) {
+ final int oldPointerIndex = newToOldPointerIndexMap[pointerIndex];
+ prototype.getPointerCoords(oldPointerIndex, pointerCoords[pointerIndex]);
+ }
+ final long historicalTime = prototype.getHistoricalEventTime(historyIndex);
+ prunedEvent.addBatch(historicalTime, pointerCoords, 0);
+ }
+
+ sendMotionEvent(prunedEvent, policyFlags);
+ prunedEvent.recycle();
+ }
+
+ /**
+ * Sends a dragging event from a two pointer event. The two pointers are
+ * merged into one and delivered to the view hierarchy. Through the entire
+ * drag gesture the pointer id delivered to the view hierarchy is the same.
+ *
+ * @param prototype The prototype from which to create the injected event.
+ * @param action The dragging action that is to be injected.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendDragEvent(MotionEvent prototype, int action, int policyFlags) {
+ PointerCoords[] pointerCoords = mTempPointerCoords;
+ int[] pointerIds = mTempPointerIds;
+ final int pointerId = mDraggingPointerId;
+ final int pointerIndex = prototype.findPointerIndex(pointerId);
+
+ // Populate the event with the date of the dragging pointer and inject it.
+ pointerIds[0] = pointerId;
+ prototype.getPointerCoords(pointerIndex, pointerCoords[0]);
+
+ MotionEvent event = MotionEvent.obtain(prototype.getDownTime(),
+ prototype.getEventTime(), action, 1, pointerIds, pointerCoords,
+ prototype.getMetaState(), prototype.getXPrecision(), prototype.getYPrecision(),
+ prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(),
+ prototype.getFlags());
+
+ sendMotionEvent(event, policyFlags);
+ event.recycle();
+ }
+
+ /**
+ * Sends an up and down events.
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) {
+ PointerCoords[] pointerCoords = mTempPointerCoords;
+ int[] pointerIds = mTempPointerIds;
+ final int pointerId = mPointerTracker.getLastReceivedUpPointerId();
+ final int pointerIndex = prototype.findPointerIndex(pointerId);
+
+ // Send down.
+ pointerIds[0] = pointerId;
+ prototype.getPointerCoords(pointerIndex, pointerCoords[0]);
+
+ final long downTime = SystemClock.uptimeMillis();
+
+ MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,
+ 1, mTempPointerIds, mTempPointerCoords, prototype.getMetaState(),
+ prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
+ prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags());
+
+ // Clone the down event before recycling it.
+ MotionEvent upEvent = MotionEvent.obtain(downEvent);
+
+ sendMotionEvent(downEvent, policyFlags);
+ downEvent.recycle();
+
+ // Send up.
+ upEvent.setAction(MotionEvent.ACTION_UP);
+ sendMotionEvent(upEvent, policyFlags);
+ upEvent.recycle();
+ }
+
+ /**
+ * Sends a hover event.
+ *
+ * @param prototype The prototype from which to create the injected event.
+ * @param action The hover action.
+ * @param pointerIndex The action pointer index.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendHoverEvent(MotionEvent prototype, int action, int pointerIndex, int
+ policyFlags) {
+ PointerCoords[] pointerCoords = mTempPointerCoords;
+ int[] pointerIds = mTempPointerIds;
+
+ // Keep only data relevant to a hover event.
+ pointerIds[0] = prototype.getPointerId(pointerIndex);
+ pointerCoords[0].clear();
+ pointerCoords[0].x = prototype.getX(pointerIndex);
+ pointerCoords[0].y = prototype.getY(pointerIndex);
+
+ final long downTime = mPointerTracker.getLastInjectedDownEventTime();
+
+ // Populate and inject a hover event.
+ MotionEvent hoverEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action,
+ 1, pointerIds, pointerCoords, 0, 0, 0, prototype.getDeviceId(), 0,
+ prototype.getSource(), 0);
+
+ sendMotionEvent(hoverEvent, policyFlags);
+ hoverEvent.recycle();
+ }
+
+ /**
+ * Computes the action for an injected event based on a masked action
+ * and a pointer index.
+ *
+ * @param actionMasked The masked action.
+ * @param pointerIndex The index of the pointer which has changed.
+ * @return The action to be used for injection.
+ */
+ private int computeInjectionAction(int actionMasked, int pointerIndex) {
+ switch (actionMasked) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ PointerTracker pointerTracker = mPointerTracker;
+ // Compute the action based on how many down pointers are injected.
+ if (pointerTracker.getInjectedPointerDownCount() == 0) {
+ return MotionEvent.ACTION_DOWN;
+ } else {
+ return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT)
+ | MotionEvent.ACTION_POINTER_DOWN;
+ }
+ }
+ case MotionEvent.ACTION_POINTER_UP: {
+ PointerTracker pointerTracker = mPointerTracker;
+ // Compute the action based on how many down pointers are injected.
+ if (pointerTracker.getInjectedPointerDownCount() == 1) {
+ return MotionEvent.ACTION_UP;
+ } else {
+ return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT)
+ | MotionEvent.ACTION_POINTER_UP;
+ }
+ }
+ default:
+ return actionMasked;
+ }
+ }
+
+ /**
+ * Determines whether a two pointer gesture is a dragging one.
+ *
+ * @param event The event with the pointer data.
+ * @return True if the gesture is a dragging one.
+ */
+ private boolean isDraggingGesture(MotionEvent event) {
+ PointerTracker pointerTracker = mPointerTracker;
+ int[] pointerIds = mTempPointerIds;
+ pointerTracker.populateActivePointerIds(pointerIds);
+
+ final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
+ final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
+
+ final float firstPtrX = event.getX(firstPtrIndex);
+ final float firstPtrY = event.getY(firstPtrIndex);
+ final float secondPtrX = event.getX(secondPtrIndex);
+ final float secondPtrY = event.getY(secondPtrIndex);
+
+ // Check if the pointers are close enough.
+ final float deltaX = firstPtrX - secondPtrX;
+ final float deltaY = firstPtrY - secondPtrY;
+ final float deltaMove = (float) Math.hypot(deltaX, deltaY);
+ if (deltaMove > mDraggingDistance) {
+ return false;
+ }
+
+ // Check if the pointers are moving in the same direction.
+ final float firstDeltaX =
+ firstPtrX - pointerTracker.getReceivedPointerDownX(firstPtrIndex);
+ final float firstDeltaY =
+ firstPtrY - pointerTracker.getReceivedPointerDownY(firstPtrIndex);
+ final float firstMagnitude =
+ (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY);
+ final float firstXNormalized =
+ (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX;
+ final float firstYNormalized =
+ (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY;
+
+ final float secondDeltaX =
+ secondPtrX - pointerTracker.getReceivedPointerDownX(secondPtrIndex);
+ final float secondDeltaY =
+ secondPtrY - pointerTracker.getReceivedPointerDownY(secondPtrIndex);
+ final float secondMagnitude =
+ (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY);
+ final float secondXNormalized =
+ (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX;
+ final float secondYNormalized =
+ (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY;
+
+ final float angleCos =
+ firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized;
+
+ if (angleCos < MIN_ANGLE_COS) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Sends an event announcing the start/end of a touch exploration gesture.
+ *
+ * @param eventType The type of the event to send.
+ */
+ private void sendAccessibilityEvent(int eventType) {
+ AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+ event.setPackageName(mContext.getPackageName());
+ event.setClassName(getClass().getName());
+ mAccessibilityManager.sendAccessibilityEvent(event);
+ }
+
+ /**
+ * Sends a motion event to the input filter for injection.
+ *
+ * @param event The event to send.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ private void sendMotionEvent(MotionEvent event, int policyFlags) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG_INJECTED, "Injecting event: " + event + ", policyFlags=0x"
+ + Integer.toHexString(policyFlags));
+ }
+ // Make sure that the user will see the event.
+ policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
+ mPointerTracker.onInjectedMotionEvent(event);
+ mInputFilter.sendInputEvent(event, policyFlags);
+ }
+
+ /**
+ * Clears the internal state of this explorer.
+ */
+ private void clear() {
+ mSendHoverDelayed.remove();
+ mPointerTracker.clear();
+ mLastTouchExploreEvent = null;
+ mCurrentState = STATE_TOUCH_EXPLORING;
+ mTouchExploreGestureInProgress = false;
+ mDraggingPointerId = INVALID_POINTER_ID;
+ }
+
+ /**
+ * Helper class for tracking pointers and more specifically which of
+ * them are currently down, which are active, and which are delivered
+ * to the view hierarchy. The enclosing {@link TouchExplorer} uses the
+ * pointer state reported by this class to perform touch exploration.
+ * <p>
+ * The main purpose of this class is to allow the touch explorer to
+ * disregard pointers put down by accident by the user and not being
+ * involved in the interaction. For example, a blind user grabs the
+ * device with her left hand such that she touches the screen and she
+ * uses her right hand's index finger to explore the screen content.
+ * In this scenario the touches generated by the left hand are to be
+ * ignored.
+ */
+ class PointerTracker {
+ private static final String LOG_TAG = "PointerTracker";
+
+ // The coefficient by which to multiply
+ // ViewConfiguration.#getScaledTouchSlop()
+ // to compute #mThresholdActivePointer.
+ private static final int COEFFICIENT_ACTIVE_POINTER = 2;
+
+ // Pointers that moved less than mThresholdActivePointer
+ // are considered active i.e. are ignored.
+ private final double mThresholdActivePointer;
+
+ // Keep track of where and when a pointer went down.
+ private final float[] mReceivedPointerDownX = new float[MAX_POINTER_COUNT];
+ private final float[] mReceivedPointerDownY = new float[MAX_POINTER_COUNT];
+ private final long[] mReceivedPointerDownTime = new long[MAX_POINTER_COUNT];
+
+ // Which pointers are down.
+ private int mReceivedPointersDown;
+
+ // Which down pointers are active.
+ private int mActivePointers;
+
+ // Primary active pointer which is either the first that went down
+ // or if it goes up the next active that most recently went down.
+ private int mPrimaryActivePointerId;
+
+ // Flag indicating that there is at least one active pointer moving.
+ private boolean mHasMovingActivePointer;
+
+ // Keep track of which pointers sent to the system are down.
+ private int mInjectedPointersDown;
+
+ // Keep track of the last up pointer data.
+ private float mLastReceivedUpPointerDownX;
+ private float mLastReveivedUpPointerDownY;
+ private long mLastReceivedUpPointerDownTime;
+ private int mLastReceivedUpPointerId;
+ private boolean mLastReceivedUpPointerActive;
+
+ // The time of the last injected down.
+ private long mLastInjectedDownEventTime;
+
+ // The action of the last injected hover event.
+ private int mLastInjectedHoverEventAction = MotionEvent.ACTION_HOVER_EXIT;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param context Context for looking up resources.
+ */
+ public PointerTracker(Context context) {
+ mThresholdActivePointer =
+ ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER;
+ }
+
+ /**
+ * Clears the internals state.
+ */
+ public void clear() {
+ Arrays.fill(mReceivedPointerDownX, 0);
+ Arrays.fill(mReceivedPointerDownY, 0);
+ Arrays.fill(mReceivedPointerDownTime, 0);
+ mReceivedPointersDown = 0;
+ mActivePointers = 0;
+ mPrimaryActivePointerId = 0;
+ mHasMovingActivePointer = false;
+ mInjectedPointersDown = 0;
+ mLastReceivedUpPointerDownX = 0;
+ mLastReveivedUpPointerDownY = 0;
+ mLastReceivedUpPointerDownTime = 0;
+ mLastReceivedUpPointerId = 0;
+ mLastReceivedUpPointerActive = false;
+ }
+
+ /**
+ * Processes a received {@link MotionEvent} event.
+ *
+ * @param event The event to process.
+ */
+ public void onReceivedMotionEvent(MotionEvent event) {
+ final int action = event.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ // New gesture so restart tracking injected down pointers.
+ mInjectedPointersDown = 0;
+ handleReceivedPointerDown(0, event);
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ handleReceivedPointerDown(event.getActionIndex(), event);
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ handleReceivedPointerMove(event);
+ } break;
+ case MotionEvent.ACTION_UP: {
+ handleReceivedPointerUp(0, event);
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ handleReceivedPointerUp(event.getActionIndex(), event);
+ } break;
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Received pointer: " + toString());
+ }
+ }
+
+ /**
+ * Processes an injected {@link MotionEvent} event.
+ *
+ * @param event The event to process.
+ */
+ public void onInjectedMotionEvent(MotionEvent event) {
+ final int action = event.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ handleInjectedPointerDown(0, event);
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ handleInjectedPointerDown(event.getActionIndex(), event);
+ } break;
+ case MotionEvent.ACTION_UP: {
+ handleInjectedPointerUp(0, event);
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ handleInjectedPointerUp(event.getActionIndex(), event);
+ } break;
+ case MotionEvent.ACTION_HOVER_ENTER:
+ case MotionEvent.ACTION_HOVER_MOVE:
+ case MotionEvent.ACTION_HOVER_EXIT: {
+ mLastInjectedHoverEventAction = event.getActionMasked();
+ } break;
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Injected pointer: " + toString());
+ }
+ }
+
+ /**
+ * @return The number of received pointers that are down.
+ */
+ public int getReceivedPointerDownCount() {
+ return Integer.bitCount(mReceivedPointersDown);
+ }
+
+ /**
+ * @return The number of down input pointers that are active.
+ */
+ public int getActivePointerCount() {
+ return Integer.bitCount(mActivePointers);
+ }
+
+ /**
+ * Whether an received pointer is down.
+ *
+ * @param pointerId The unique pointer id.
+ * @return True if the pointer is down.
+ */
+ public boolean isReceivedPointerDown(int pointerId) {
+ final int pointerFlag = (1 << pointerId);
+ return (mReceivedPointersDown & pointerFlag) != 0;
+ }
+
+ /**
+ * Whether an injected pointer is down.
+ *
+ * @param pointerId The unique pointer id.
+ * @return True if the pointer is down.
+ */
+ public boolean isInjectedPointerDown(int pointerId) {
+ final int pointerFlag = (1 << pointerId);
+ return (mInjectedPointersDown & pointerFlag) != 0;
+ }
+
+ /**
+ * @return The number of down pointers injected to the view hierarchy.
+ */
+ public int getInjectedPointerDownCount() {
+ return Integer.bitCount(mInjectedPointersDown);
+ }
+
+ /**
+ * Whether an input pointer is active.
+ *
+ * @param pointerId The unique pointer id.
+ * @return True if the pointer is active.
+ */
+ public boolean isActivePointer(int pointerId) {
+ final int pointerFlag = (1 << pointerId);
+ return (mActivePointers & pointerFlag) != 0;
+ }
+
+ /**
+ * @param pointerId The unique pointer id.
+ * @return The X coordinate where the pointer went down.
+ */
+ public float getReceivedPointerDownX(int pointerId) {
+ return mReceivedPointerDownX[pointerId];
+ }
+
+ /**
+ * @param pointerId The unique pointer id.
+ * @return The Y coordinate where the pointer went down.
+ */
+ public float getReceivedPointerDownY(int pointerId) {
+ return mReceivedPointerDownY[pointerId];
+ }
+
+ /**
+ * @param pointerId The unique pointer id.
+ * @return The time when the pointer went down.
+ */
+ public long getReceivedPointerDownTime(int pointerId) {
+ return mReceivedPointerDownTime[pointerId];
+ }
+
+ /**
+ * @return The id of the primary pointer.
+ */
+ public int getPrimaryActivePointerId() {
+ if (mPrimaryActivePointerId == INVALID_POINTER_ID) {
+ mPrimaryActivePointerId = findPrimaryActivePointer();
+ }
+ return mPrimaryActivePointerId;
+ }
+
+ /**
+ * @return The X coordinate where the last up received pointer went down.
+ */
+ public float getLastReceivedUpPointerDownX() {
+ return mLastReceivedUpPointerDownX;
+ }
+
+ /**
+ * @return The Y coordinate where the last up received pointer went down.
+ */
+ public float getLastReceivedUpPointerDownY() {
+ return mLastReveivedUpPointerDownY;
+ }
+
+ /**
+ * @return The time when the last up received pointer went down.
+ */
+ public long getLastReceivedUpPointerDownTime() {
+ return mLastReceivedUpPointerDownTime;
+ }
+
+ /**
+ * @return The id of the last received pointer that went up.
+ */
+ public int getLastReceivedUpPointerId() {
+ return mLastReceivedUpPointerId;
+ }
+
+ /**
+ * @return Whether the last received pointer that went up was active.
+ */
+ public boolean wasLastReceivedUpPointerActive() {
+ return mLastReceivedUpPointerActive;
+ }
+
+ /**
+ * @return The time of the last injected down event.
+ */
+ public long getLastInjectedDownEventTime() {
+ return mLastInjectedDownEventTime;
+ }
+
+ /**
+ * @return The action of the last injected hover event.
+ */
+ public int getLastInjectedHoverAction() {
+ return mLastInjectedHoverEventAction;
+ }
+
+ /**
+ * Populates the active pointer IDs to the given array.
+ * <p>
+ * Note: The client is responsible for providing large enough array.
+ *
+ * @param outPointerIds The array to which to write the active pointers.
+ */
+ public void populateActivePointerIds(int[] outPointerIds) {
+ int index = 0;
+ for (int idBits = mActivePointers; idBits != 0; ) {
+ final int id = Integer.numberOfTrailingZeros(idBits);
+ idBits &= ~(1 << id);
+ outPointerIds[index] = id;
+ index++;
+ }
+ }
+
+ /**
+ * @return The number of non injected active pointers.
+ */
+ public int getNotInjectedActivePointerCount() {
+ final int pointerState = mActivePointers & ~mInjectedPointersDown;
+ return Integer.bitCount(pointerState);
+ }
+
+ /**
+ * @param pointerId The unique pointer id.
+ * @return Whether the pointer is active or was the last active than went up.
+ */
+ private boolean isActiveOrWasLastActiveUpPointer(int pointerId) {
+ return (isActivePointer(pointerId)
+ || (mLastReceivedUpPointerId == pointerId
+ && mLastReceivedUpPointerActive));
+ }
+
+ /**
+ * Handles a received pointer down event.
+ *
+ * @param pointerIndex The index of the pointer that has changed.
+ * @param event The event to be handled.
+ */
+ private void handleReceivedPointerDown(int pointerIndex, MotionEvent event) {
+ final int pointerId = event.getPointerId(pointerIndex);
+ final int pointerFlag = (1 << pointerId);
+
+ mLastReceivedUpPointerId = 0;
+ mLastReceivedUpPointerDownX = 0;
+ mLastReveivedUpPointerDownY = 0;
+ mLastReceivedUpPointerDownTime = 0;
+ mLastReceivedUpPointerActive = false;
+
+ mReceivedPointersDown |= pointerFlag;
+ mReceivedPointerDownX[pointerId] = event.getX(pointerIndex);
+ mReceivedPointerDownY[pointerId] = event.getY(pointerIndex);
+ mReceivedPointerDownTime[pointerId] = event.getEventTime();
+
+ if (!mHasMovingActivePointer) {
+ // If still no moving active pointers every
+ // down pointer is the only active one.
+ mActivePointers = pointerFlag;
+ mPrimaryActivePointerId = pointerId;
+ } else {
+ // If at least one moving active pointer every
+ // subsequent down pointer is active.
+ mActivePointers |= pointerFlag;
+ }
+ }
+
+ /**
+ * Handles a received pointer move event.
+ *
+ * @param event The event to be handled.
+ */
+ private void handleReceivedPointerMove(MotionEvent event) {
+ detectActivePointers(event);
+ }
+
+ /**
+ * Handles a received pointer up event.
+ *
+ * @param pointerIndex The index of the pointer that has changed.
+ * @param event The event to be handled.
+ */
+ private void handleReceivedPointerUp(int pointerIndex, MotionEvent event) {
+ final int pointerId = event.getPointerId(pointerIndex);
+ final int pointerFlag = (1 << pointerId);
+
+ mLastReceivedUpPointerId = pointerId;
+ mLastReceivedUpPointerDownX = getReceivedPointerDownX(pointerId);
+ mLastReveivedUpPointerDownY = getReceivedPointerDownY(pointerId);
+ mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId);
+ mLastReceivedUpPointerActive = isActivePointer(pointerId);
+
+ mReceivedPointersDown &= ~pointerFlag;
+ mActivePointers &= ~pointerFlag;
+ mReceivedPointerDownX[pointerId] = 0;
+ mReceivedPointerDownY[pointerId] = 0;
+ mReceivedPointerDownTime[pointerId] = 0;
+
+ if (mActivePointers == 0) {
+ mHasMovingActivePointer = false;
+ }
+ if (mPrimaryActivePointerId == pointerId) {
+ mPrimaryActivePointerId = INVALID_POINTER_ID;
+ }
+ }
+
+ /**
+ * Handles a injected pointer down event.
+ *
+ * @param pointerIndex The index of the pointer that has changed.
+ * @param event The event to be handled.
+ */
+ private void handleInjectedPointerDown(int pointerIndex, MotionEvent event) {
+ final int pointerId = event.getPointerId(pointerIndex);
+ final int pointerFlag = (1 << pointerId);
+ mInjectedPointersDown |= pointerFlag;
+ mLastInjectedDownEventTime = event.getEventTime();
+ }
+
+ /**
+ * Handles a injected pointer up event.
+ *
+ * @param pointerIndex The index of the pointer that has changed.
+ * @param event The event to be handled.
+ */
+ private void handleInjectedPointerUp(int pointerIndex, MotionEvent event) {
+ final int pointerId = event.getPointerId(pointerIndex);
+ final int pointerFlag = (1 << pointerId);
+ mInjectedPointersDown &= ~pointerFlag;
+ }
+
+ /**
+ * Detects the active pointers in an event.
+ *
+ * @param event The event to examine.
+ */
+ private void detectActivePointers(MotionEvent event) {
+ for (int i = 0, count = event.getPointerCount(); i < count; i++) {
+ final int pointerId = event.getPointerId(i);
+ if (mHasMovingActivePointer) {
+ // If already active => nothing to do.
+ if (isActivePointer(pointerId)) {
+ continue;
+ }
+ }
+ // Active pointers are ones that moved more than a given threshold.
+ final float pointerDeltaMove = computePointerDeltaMove(i, event);
+ if (pointerDeltaMove > mThresholdActivePointer) {
+ final int pointerFlag = (1 << pointerId);
+ mActivePointers |= pointerFlag;
+ mHasMovingActivePointer = true;
+ }
+ }
+ }
+
+ /**
+ * @return The primary active pointer.
+ */
+ private int findPrimaryActivePointer() {
+ int primaryActivePointerId = INVALID_POINTER_ID;
+ long minDownTime = Long.MAX_VALUE;
+ // Find the active pointer that went down first.
+ for (int i = 0, count = mReceivedPointerDownTime.length; i < count; i++) {
+ if (isActivePointer(i)) {
+ final long downPointerTime = mReceivedPointerDownTime[i];
+ if (downPointerTime < minDownTime) {
+ minDownTime = downPointerTime;
+ primaryActivePointerId = i;
+ }
+ }
+ }
+ return primaryActivePointerId;
+ }
+
+ /**
+ * Computes the move for a given action pointer index since the
+ * corresponding pointer went down.
+ *
+ * @param pointerIndex The action pointer index.
+ * @param event The event to examine.
+ * @return The distance the pointer has moved.
+ */
+ private float computePointerDeltaMove(int pointerIndex, MotionEvent event) {
+ final int pointerId = event.getPointerId(pointerIndex);
+ final float deltaX = event.getX(pointerIndex) - mReceivedPointerDownX[pointerId];
+ final float deltaY = event.getY(pointerIndex) - mReceivedPointerDownY[pointerId];
+ return (float) Math.hypot(deltaX, deltaY);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("=========================");
+ builder.append("\nDown pointers #");
+ builder.append(getReceivedPointerDownCount());
+ builder.append(" [ ");
+ for (int i = 0; i < MAX_POINTER_COUNT; i++) {
+ if (isReceivedPointerDown(i)) {
+ builder.append(i);
+ builder.append(" ");
+ }
+ }
+ builder.append("]");
+ builder.append("\nActive pointers #");
+ builder.append(getActivePointerCount());
+ builder.append(" [ ");
+ for (int i = 0; i < MAX_POINTER_COUNT; i++) {
+ if (isActivePointer(i)) {
+ builder.append(i);
+ builder.append(" ");
+ }
+ }
+ builder.append("]");
+ builder.append("\nPrimary active pointer id [ ");
+ builder.append(getPrimaryActivePointerId());
+ builder.append(" ]");
+ builder.append("\n=========================");
+ return builder.toString();
+ }
+ }
+
+ /**
+ * Class for delayed sending of hover events.
+ */
+ private final class SendHoverDelayed implements Runnable {
+ private static final String LOG_TAG = "SendHoverEnterOrExitDelayed";
+
+ private MotionEvent mEvent;
+ private int mAction;
+ private int mPointerIndex;
+ private int mPolicyFlags;
+
+ public void post(MotionEvent prototype, int action, int pointerIndex, int policyFlags,
+ long delay) {
+ remove();
+ mEvent = MotionEvent.obtain(prototype);
+ mAction = action;
+ mPointerIndex = pointerIndex;
+ mPolicyFlags = policyFlags;
+ mHandler.postDelayed(this, delay);
+ }
+
+ public void remove() {
+ mHandler.removeCallbacks(this);
+ clear();
+ }
+
+ private boolean isPenidng() {
+ return (mEvent != null);
+ }
+
+ private void clear() {
+ if (!isPenidng()) {
+ return;
+ }
+ mEvent.recycle();
+ mEvent = null;
+ mAction = 0;
+ mPointerIndex = -1;
+ mPolicyFlags = 0;
+ }
+
+ public void forceSendAndRemove() {
+ if (isPenidng()) {
+ run();
+ remove();
+ }
+ }
+
+ public void run() {
+ if (DEBUG) {
+ if (mAction == MotionEvent.ACTION_HOVER_ENTER) {
+ Slog.d(LOG_TAG, "Injecting: " + MotionEvent.ACTION_HOVER_ENTER);
+ } else if (mAction == MotionEvent.ACTION_HOVER_MOVE) {
+ Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_MOVE");
+ } else if (mAction == MotionEvent.ACTION_HOVER_EXIT) {
+ Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_EXIT");
+ }
+ }
+
+ sendHoverEvent(mEvent, mAction, mPointerIndex, mPolicyFlags);
+ clear();
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/InputFilter.java b/services/java/com/android/server/wm/InputFilter.java
index 7e1ab07..8f0001a 100644
--- a/services/java/com/android/server/wm/InputFilter.java
+++ b/services/java/com/android/server/wm/InputFilter.java
@@ -105,11 +105,13 @@ public abstract class InputFilter {
private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier =
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
new InputEventConsistencyVerifier(this,
- InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT) : null;
+ InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
+ "InputFilter#InboundInputEventConsistencyVerifier") : null;
private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier =
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
new InputEventConsistencyVerifier(this,
- InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT) : null;
+ InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
+ "InputFilter#OutboundInputEventConsistencyVerifier") : null;
/**
* Creates the input filter.
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 538e38c..8b739a4 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -398,6 +398,7 @@ public class WindowManagerService extends IWindowManager.Stub
int mRotation = 0;
int mRequestedRotation = 0;
int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean mAltOrientation = false;
int mLastRotationFlags;
ArrayList<IRotationWatcher> mRotationWatchers
= new ArrayList<IRotationWatcher>();
@@ -585,7 +586,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
final Configuration mTempConfiguration = new Configuration();
- int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
// The frame use to limit the size of the app running in compatibility mode.
Rect mCompatibleScreenFrame = new Rect();
@@ -4954,7 +4954,52 @@ public class WindowManagerService extends IWindowManager.Stub
rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
mRotation, mDisplayEnabled);
if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation);
+
+ int desiredRotation = rotation;
+ int lockedRotation = mPolicy.getLockedRotationLw();
+ if (lockedRotation >= 0 && rotation != lockedRotation) {
+ // We are locked in a rotation but something is requesting
+ // a different rotation... we will either keep the locked
+ // rotation if it results in the same orientation, or have to
+ // switch into an emulated orientation mode.
+
+ // First, we know that our rotation is actually going to be
+ // the locked rotation.
+ rotation = lockedRotation;
+
+ // Now the difference between the desired and lockedRotation
+ // may mean that the orientation is different... if that is
+ // not the case, we can just make the desired rotation be the
+ // same as the new locked rotation.
+ switch (lockedRotation) {
+ case Surface.ROTATION_0:
+ if (rotation == Surface.ROTATION_180) {
+ desiredRotation = lockedRotation;
+ }
+ break;
+ case Surface.ROTATION_90:
+ if (rotation == Surface.ROTATION_270) {
+ desiredRotation = lockedRotation;
+ }
+ break;
+ case Surface.ROTATION_180:
+ if (rotation == Surface.ROTATION_0) {
+ desiredRotation = lockedRotation;
+ }
+ break;
+ case Surface.ROTATION_270:
+ if (rotation == Surface.ROTATION_90) {
+ desiredRotation = lockedRotation;
+ }
+ break;
+ }
+ }
+
changed = mDisplayEnabled && mRotation != rotation;
+ if (mAltOrientation != (rotation != desiredRotation)) {
+ changed = true;
+ mAltOrientation = rotation != desiredRotation;
+ }
if (changed) {
if (DEBUG_ORIENTATION) Slog.v(TAG,
@@ -5000,6 +5045,7 @@ public class WindowManagerService extends IWindowManager.Stub
Surface.setOrientation(0, rotation, animFlags);
}
}
+
for (int i=mWindows.size()-1; i>=0; i--) {
WindowState w = mWindows.get(i);
if (w.mSurface != null) {
@@ -5440,8 +5486,32 @@ public class WindowManagerService extends IWindowManager.Stub
// Use the effective "visual" dimensions based on current rotation
final boolean rotated = (mRotation == Surface.ROTATION_90
|| mRotation == Surface.ROTATION_270);
- final int dw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
- final int dh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
+ final int realdw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
+ final int realdh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
+
+ if (mAltOrientation) {
+ mCurDisplayWidth = realdw;
+ mCurDisplayHeight = realdh;
+ if (realdw > realdh) {
+ // Turn landscape into portrait.
+ int maxw = (int)(realdh/1.3f);
+ if (maxw < realdw) {
+ mCurDisplayWidth = maxw;
+ }
+ } else {
+ // Turn portrait into landscape.
+ int maxh = (int)(realdw/1.3f);
+ if (maxh < realdh) {
+ mCurDisplayHeight = maxh;
+ }
+ }
+ } else {
+ mCurDisplayWidth = realdw;
+ mCurDisplayHeight = realdh;
+ }
+
+ final int dw = mCurDisplayWidth;
+ final int dh = mCurDisplayHeight;
int orientation = Configuration.ORIENTATION_SQUARE;
if (dw < dh) {
@@ -5452,66 +5522,69 @@ public class WindowManagerService extends IWindowManager.Stub
config.orientation = orientation;
DisplayMetrics dm = new DisplayMetrics();
- mDisplay.getMetrics(dm);
+ mDisplay.getRealMetrics(dm);
+
+ // Override display width and height with what we are computing,
+ // to be sure they remain consistent.
+ dm.widthPixels = dw;
+ dm.heightPixels = dh;
+
CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
config.screenWidthDp = (int)(dm.widthPixels / dm.density);
config.screenHeightDp = (int)(dm.heightPixels / dm.density);
- if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
- // Note we only do this once because at this point we don't
- // expect the screen to change in this way at runtime, and want
- // to avoid all of this computation for every config change.
- int longSize = dw;
- int shortSize = dh;
- if (longSize < shortSize) {
- int tmp = longSize;
- longSize = shortSize;
- shortSize = tmp;
- }
- longSize = (int)(longSize/dm.density);
- shortSize = (int)(shortSize/dm.density);
-
- // These semi-magic numbers define our compatibility modes for
- // applications with different screens. These are guarantees to
- // app developers about the space they can expect for a particular
- // configuration. DO NOT CHANGE!
- if (longSize < 470) {
- // This is shorter than an HVGA normal density screen (which
- // is 480 pixels on its long side).
- mScreenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
- | Configuration.SCREENLAYOUT_LONG_NO;
+ // Compute the screen layout size class.
+ int screenLayout;
+ int longSize = dw;
+ int shortSize = dh;
+ if (longSize < shortSize) {
+ int tmp = longSize;
+ longSize = shortSize;
+ shortSize = tmp;
+ }
+ longSize = (int)(longSize/dm.density);
+ shortSize = (int)(shortSize/dm.density);
+
+ // These semi-magic numbers define our compatibility modes for
+ // applications with different screens. These are guarantees to
+ // app developers about the space they can expect for a particular
+ // configuration. DO NOT CHANGE!
+ if (longSize < 470) {
+ // This is shorter than an HVGA normal density screen (which
+ // is 480 pixels on its long side).
+ screenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
+ | Configuration.SCREENLAYOUT_LONG_NO;
+ } else {
+ // What size is this screen screen?
+ if (longSize >= 960 && shortSize >= 720) {
+ // 1.5xVGA or larger screens at medium density are the point
+ // at which we consider it to be an extra large screen.
+ screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ } else if (longSize >= 640 && shortSize >= 480) {
+ // VGA or larger screens at medium density are the point
+ // at which we consider it to be a large screen.
+ screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
} else {
- // What size is this screen screen?
- if (longSize >= 960 && shortSize >= 720) {
- // 1.5xVGA or larger screens at medium density are the point
- // at which we consider it to be an extra large screen.
- mScreenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
- } else if (longSize >= 640 && shortSize >= 480) {
- // VGA or larger screens at medium density are the point
- // at which we consider it to be a large screen.
- mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
- } else {
- mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
- }
-
- // If this screen is wider than normal HVGA, or taller
- // than FWVGA, then for old apps we want to run in size
- // compatibility mode.
- if (shortSize > 321 || longSize > 570) {
- mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
- }
+ screenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ }
- // Is this a long screen?
- if (((longSize*3)/5) >= (shortSize-1)) {
- // Anything wider than WVGA (5:3) is considering to be long.
- mScreenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
- } else {
- mScreenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
- }
+ // If this screen is wider than normal HVGA, or taller
+ // than FWVGA, then for old apps we want to run in size
+ // compatibility mode.
+ if (shortSize > 321 || longSize > 570) {
+ screenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
+ }
+
+ // Is this a long screen?
+ if (((longSize*3)/5) >= (shortSize-1)) {
+ // Anything wider than WVGA (5:3) is considering to be long.
+ screenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
+ } else {
+ screenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
}
}
- config.screenLayout = mScreenLayout;
+ config.screenLayout = screenLayout;
// Determine whether a hard keyboard is available and enabled.
boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
@@ -6722,8 +6795,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
final long currentTime = SystemClock.uptimeMillis();
- final int dw = mCurDisplayWidth = mDisplay.getRealWidth();
- final int dh = mCurDisplayHeight = mDisplay.getRealHeight();
+ final int dw = mCurDisplayWidth;
+ final int dh = mCurDisplayHeight;
int i;
@@ -8709,8 +8782,9 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
pw.print(" mRotation="); pw.print(mRotation);
- pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
- pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
+ pw.print(" mForcedAppOrientation="); pw.print(mForcedAppOrientation);
+ pw.print(" mRequestedRotation="); pw.print(mRequestedRotation);
+ pw.print(" mAltOrientation="); pw.println(mAltOrientation);
pw.print(" mDeferredRotation="); pw.print(mDeferredRotation);
pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags);
pw.print(" mAnimationPending="); pw.print(mAnimationPending);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index 2f9b026..76031a8 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -153,7 +153,8 @@ public class BiDiTestView extends View {
float[] advances = new float[length];
float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
setPaintDir(paint, dir);
- float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, dir, advances, 0);
+ float textWidthICU = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0,
+ 1 /* use ICU */);
logAdvances(text, textWidthHB, textWidthICU, advances);
drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
diff --git a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
index 69a33bc..174cc65 100644
--- a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
+++ b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
@@ -2,10 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.rs.image">
-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk android:minSdkVersion="11" />
- <application android:label="Image Processing">
+ <application android:label="Image Processing"
+ android:hardwareAccelerated="true">
<activity android:name="ImageProcessingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg
deleted file mode 100644
index 81a87b1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable/city.png b/tests/RenderScriptTests/ImageProcessing/res/drawable/city.png
new file mode 100644
index 0000000..856eeff
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/res/drawable/city.png
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg
deleted file mode 100644
index 81a87b1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
index b271b43..08a010d 100644
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
+++ b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
@@ -17,31 +17,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:layout_height="fill_parent"
+ android:id="@+id/toplevel">
<SurfaceView
android:id="@+id/surface"
android:layout_width="1dip"
android:layout_height="1dip" />
- <ImageView
- android:id="@+id/display"
- android:layout_width="320dip"
- android:layout_height="266dip" />
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/benchmark"
- android:onClick="benchmark"/>
- <TextView
- android:id="@+id/benchmarkText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="8pt"
- android:text="@string/saturation"/>
- </LinearLayout>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
@@ -49,6 +30,26 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
+ <ImageView
+ android:id="@+id/display"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/benchmark"
+ android:onClick="benchmark"/>
+ <TextView
+ android:id="@+id/benchmarkText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="8pt"
+ android:text="@string/saturation"/>
+ </LinearLayout>
<TextView
android:id="@+id/inSaturationText"
android:layout_width="match_parent"
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 4f2f52ab..7462701 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -40,7 +40,6 @@ public class ImageProcessingActivity extends Activity
SeekBar.OnSeekBarChangeListener {
private Bitmap mBitmapIn;
private Bitmap mBitmapOut;
- private Bitmap mBitmapScratch;
private ScriptC_threshold mScript;
private ScriptC_vertical_blur mScriptVBlur;
private ScriptC_horizontal_blur mScriptHBlur;
@@ -78,9 +77,20 @@ public class ImageProcessingActivity extends Activity
private SurfaceView mSurfaceView;
private ImageView mDisplayView;
+ private boolean mIsProcessing;
+
class FilterCallback extends RenderScript.RSMessageHandler {
private Runnable mAction = new Runnable() {
public void run() {
+
+ synchronized (mDisplayView) {
+ mIsProcessing = false;
+ }
+
+ // This is a hack to work around an invalidation bug
+ mBitmapOut = Bitmap.createBitmap(mBitmapOut);
+ mOutPixelsAllocation.copyTo(mBitmapOut);
+ mDisplayView.setImageBitmap(mBitmapOut);
mDisplayView.invalidate();
}
};
@@ -99,156 +109,6 @@ public class ImageProcessingActivity extends Activity
// Store our coefficients here
float gaussian[];
- private long javaFilter() {
- final int width = mBitmapIn.getWidth();
- final int height = mBitmapIn.getHeight();
- final int count = width * height;
-
- if (in == null) {
- in = new int[count];
- interm = new int[count];
- out = new int[count];
- gaussian = new float[MAX_RADIUS * 2 + 1];
- mBitmapIn.getPixels(in, 0, width, 0, 0, width, height);
- }
-
- long t = java.lang.System.currentTimeMillis();
-
- int w, h, r;
-
- float fRadius = (float)mRadius;
- int radius = (int)mRadius;
-
- // Compute gaussian weights for the blur
- // e is the euler's number
- float e = 2.718281828459045f;
- float pi = 3.1415926535897932f;
- // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
- // x is of the form [-radius .. 0 .. radius]
- // and sigma varies with radius.
- // Based on some experimental radius values and sigma's
- // we approximately fit sigma = f(radius) as
- // sigma = radius * 0.4 + 0.6
- // The larger the radius gets, the more our gaussian blur
- // will resemble a box blur since with large sigma
- // the gaussian curve begins to lose its shape
- float sigma = 0.4f * fRadius + 0.6f;
- // Now compute the coefficints
- // We will store some redundant values to save some math during
- // the blur calculations
- // precompute some values
- float coeff1 = 1.0f / (float)(Math.sqrt( 2.0f * pi ) * sigma);
- float coeff2 = - 1.0f / (2.0f * sigma * sigma);
- float normalizeFactor = 0.0f;
- float floatR = 0.0f;
- for (r = -radius; r <= radius; r ++) {
- floatR = (float)r;
- gaussian[r + radius] = coeff1 * (float)Math.pow(e, floatR * floatR * coeff2);
- normalizeFactor += gaussian[r + radius];
- }
-
- //Now we need to normalize the weights because all our coefficients need to add up to one
- normalizeFactor = 1.0f / normalizeFactor;
- for (r = -radius; r <= radius; r ++) {
- floatR = (float)r;
- gaussian[r + radius] *= normalizeFactor;
- }
-
- float blurredPixelR = 0.0f;
- float blurredPixelG = 0.0f;
- float blurredPixelB = 0.0f;
- float blurredPixelA = 0.0f;
-
- for (h = 0; h < height; h ++) {
- for (w = 0; w < width; w ++) {
-
- blurredPixelR = 0.0f;
- blurredPixelG = 0.0f;
- blurredPixelB = 0.0f;
- blurredPixelA = 0.0f;
-
- for (r = -radius; r <= radius; r ++) {
- // Stepping left and right away from the pixel
- int validW = w + r;
- // Clamp to zero and width max() isn't exposed for ints yet
- if (validW < 0) {
- validW = 0;
- }
- if (validW > width - 1) {
- validW = width - 1;
- }
-
- int input = in[h*width + validW];
-
- int R = ((input >> 24) & 0xff);
- int G = ((input >> 16) & 0xff);
- int B = ((input >> 8) & 0xff);
- int A = (input & 0xff);
-
- float weight = gaussian[r + radius];
-
- blurredPixelR += (float)(R)*weight;
- blurredPixelG += (float)(G)*weight;
- blurredPixelB += (float)(B)*weight;
- blurredPixelA += (float)(A)*weight;
- }
-
- int R = (int)blurredPixelR;
- int G = (int)blurredPixelG;
- int B = (int)blurredPixelB;
- int A = (int)blurredPixelA;
-
- interm[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A);
- }
- }
-
- for (h = 0; h < height; h ++) {
- for (w = 0; w < width; w ++) {
-
- blurredPixelR = 0.0f;
- blurredPixelG = 0.0f;
- blurredPixelB = 0.0f;
- blurredPixelA = 0.0f;
- for (r = -radius; r <= radius; r ++) {
- int validH = h + r;
- // Clamp to zero and width
- if (validH < 0) {
- validH = 0;
- }
- if (validH > height - 1) {
- validH = height - 1;
- }
-
- int input = interm[validH*width + w];
-
- int R = ((input >> 24) & 0xff);
- int G = ((input >> 16) & 0xff);
- int B = ((input >> 8) & 0xff);
- int A = (input & 0xff);
-
- float weight = gaussian[r + radius];
-
- blurredPixelR += (float)(R)*weight;
- blurredPixelG += (float)(G)*weight;
- blurredPixelB += (float)(B)*weight;
- blurredPixelA += (float)(A)*weight;
- }
-
- int R = (int)blurredPixelR;
- int G = (int)blurredPixelG;
- int B = (int)blurredPixelB;
- int A = (int)blurredPixelA;
-
- out[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A);
- }
- }
-
- t = java.lang.System.currentTimeMillis() - t;
- android.util.Log.v("Img", "Java frame time ms " + t);
- mBitmapOut.setPixels(out, 0, width, 0, 0, width, height);
- return t;
- }
-
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
@@ -280,17 +140,14 @@ public class ImageProcessingActivity extends Activity
mScriptVBlur.invoke_setSaturation(mSaturation);
}
- long t = java.lang.System.currentTimeMillis();
- if (true) {
- mScript.invoke_filter();
- mOutPixelsAllocation.copyTo(mBitmapOut);
- } else {
- javaFilter();
- mDisplayView.invalidate();
+ synchronized (mDisplayView) {
+ if (mIsProcessing) {
+ return;
+ }
+ mIsProcessing = true;
}
- t = java.lang.System.currentTimeMillis() - t;
- android.util.Log.v("Img", "Renderscript frame time core ms " + t);
+ mScript.invoke_filter();
}
}
@@ -305,9 +162,8 @@ public class ImageProcessingActivity extends Activity
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
- mBitmapIn = loadBitmap(R.drawable.data);
- mBitmapOut = loadBitmap(R.drawable.data);
- mBitmapScratch = loadBitmap(R.drawable.data);
+ mBitmapIn = loadBitmap(R.drawable.city);
+ mBitmapOut = loadBitmap(R.drawable.city);
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
mSurfaceView.getHolder().addCallback(this);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
index 652ffd7..45eea5e 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
@@ -19,7 +19,7 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32
} else {
for (int r = -fs->radius; r <= fs->radius; r ++) {
// Stepping left and right away from the pixel
- int validW = rsClamp(x + r, (uint)0, (uint)(fs->width - 1));
+ int validW = rsClamp((int)x + r, (int)0, (int)(fs->width - 1));
blurredPixel += input[validW].xyz * gPtr[0];
gPtr++;
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index bd4ae4e..6b0cde0 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -74,7 +74,7 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32
}
} else {
for (int r = -fs->radius; r <= fs->radius; r ++) {
- int validH = rsClamp(y + r, (uint)0, (uint)(fs->height - 1));
+ int validH = rsClamp((int)y + r, (int)0, (int)(fs->height - 1));
const float4 *i = input + validH * fs->width;
blurredPixel += i->xyz * gPtr[0];
gPtr++;