diff options
111 files changed, 4285 insertions, 1476 deletions
diff --git a/Android.mk b/Android.mk index cd9ae7d07734..898d7e29d3f2 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 cbc2c409d3db..a17b80cd071b 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 c7e6ee6ceec0..8ec773241e54 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 bcab66eaa6f2..ed4036db7ff2 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 328a55bca90f..77c2d1ba2cd2 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 b541ec30c021..419288b8fe82 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 42d555cff45c..2e8d551df401 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 2f4a4bbee490..570b80138cbc 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 6e2168b21aee..831ccc556bf9 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 ff6a4cddef15..6b2d8e4e2377 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 980239b52983..8e839c09b1d2 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 b5ca2c2a8c1c..e14b97558e49 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 4a6289285d41..4bc7f39a584c 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 739758c8c79f..94eb429dad64 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 08daa280b10a..7b404b45f729 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 d7d4c3f02d0d..655df391ed4f 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 4104b070f4a1..f02dabac340d 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 8f7bb8cc43b7..3d19380d5959 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 9af19b8796a9..11c93929b23e 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 22cb0d482bf8..dd7719364a31 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 000000000000..e095f435bfd6 --- /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 7633569d5312..aaaae327cb64 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 6cb5c35339d5..d63d421fb3b5 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 f16efbdeb7be..060f1a9b2bc0 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 bf636079987a..bd595a568fc8 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 0df45cca6a65..f050d41e3c55 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 7210e219b300..30fb927cc3cc 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 d76a956b8c67..5618dbe25e06 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 8db34d91d74f..96d41a0ed0b1 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 6f76dd0d2b75..31ec7853c804 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 537709d1324d..4d3aa685cb90 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 029d69020c78..423e735c787b 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 16d5539b8cdf..96520858fe95 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 71511c62090a..16f51fd20ae0 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 42ef916c995c..c6d386d1fa48 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 74a6ae7724ac..fa8eb5141674 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 0a54e17de1d7..768b836b2438 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 7f1812164511..2ed39e47082e 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 000000000000..86580bc3e531 --- /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 000000000000..321622ef387b --- /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 c82f91d7dfd8..7f7c55cb4f68 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 4a7336852e70..5e828fae655d 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 7badbac5349e..2a4d8e0513eb 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 058daa8efbe7..8def578ef357 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 cd1847faaaf2..5355847cb223 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 000000000000..bf0a3426aff7 --- /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 000000000000..ea7eeb58c7d7 --- /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 33825c74b4bf..05a481057a21 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 000000000000..c7dcb515cd09 --- /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 da1c1577d2c1..a1511b3cb6ee 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 b9fd6a5478a6..be7b42fa61fc 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 df80546688fa..1870a4a46055 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 d8898ae3e542..7e13569183ae 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;      } -    @Override      public void onTabSelected(Tab tab, FragmentTransaction ft) {          ft.add(R.id.fragment_content, mFragment, null);      } -    @Override      public void onTabUnselected(Tab tab, FragmentTransaction ft) {          ft.remove(mFragment);      } -    @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 0949beb812e1..962f22cde441 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 c6c86b23e4d1..b7528506087c 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 e272839151c8..db81721aa287 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 df5be323c921..765c0399be30 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 c6501417713e..6b69b8a3f581 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 000000000000..64f5a481ab58 --- /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 000000000000..69847bf0eba3 --- /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 7f28959f5423..75f5a5f6e617 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 cead75bcae2c..18d98cb05e10 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 bd1fd0e896bf..093e311e5a3d 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 a7f473c4f3a4..dac5cec06acc 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 6b37e035b4a7..a75900429006 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 20fa3672c03f..0ca892d7eb68 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 477cb6166b21..d5d5ca5c9032 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 c30b8573a872..b7b85b68372a 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 57da10a65b1f..da51d95b4e27 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 2d90a98c7b09..f34af471cc8c 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 abf34a382237..d30184f602b3 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 c379b8bab48c..6d0701d18720 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 6a9010fe822a..c8af89167e1b 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 a7ac9edf7608..80cc94e758fa 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 ac326ef7bc46..b32667145840 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 a3dd1367a53c..915179915b1e 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 06708da4bae3..585cd30ceed3 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 ed63129ca3cd..3cfb6b9270c1 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 cddab601a57c..6ef688d1f2ff 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 ea73e117bafe..5696433614fe 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 b79229539eeb..c95a0c25c13a 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 339c0d168261..53e7de176ae4 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 39221f3071ef..9de720768c40 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 461bdd0ab41e..fe3734f3c839 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 2399216b49ed..8885bd5914e9 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 5ec573ee9027..4e2217588f35 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 f9db1a1bdec6..01d0a929b552 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 616836cbb545..0d0d6c20967e 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 4d9a1ae3d6a4..d7bde00a4dc7 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 1668ecf258f8..9f3037df4d68 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 37e02a3f6529..b744b5b4c84a 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 fa729a893bc0..b06eb287ba58 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 8bc2e22c31d8..d270df53c681 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 aeba213d57a4..96cde57bc185 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 57e008cafddf..535b13e185de 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 879f1a889a57..73003c855f84 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 65321b72cce0..a37ccc7d0a7e 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 ced8feb450da..8ba0a0b67ef4 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 7a483aad3757..1ad80470f717 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 000000000000..4ba6060ca47f --- /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 7e1ab079cceb..8f0001aec30b 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 538e38cc4b99..8b739a43b6c7 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 2f9b026914bc..76031a81d1ec 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 69a33bc31d3f..174cc65f4b6e 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 Binary files differdeleted file mode 100644 index 81a87b1726c2..000000000000 --- a/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable/city.png b/tests/RenderScriptTests/ImageProcessing/res/drawable/city.png Binary files differnew file mode 100644 index 000000000000..856eeff59b9d --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing/res/drawable/city.png diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg Binary files differdeleted file mode 100644 index 81a87b1726c2..000000000000 --- a/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml index b271b431a54c..08a010ddc995 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 4f2f52ab656a..74627018e405 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 652ffd76dd3d..45eea5ef2c4f 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 bd4ae4eca3b7..6b0cde0dba97 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++;  |