diff options
85 files changed, 3842 insertions, 1189 deletions
@@ -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/current.txt b/api/current.txt index c7e6ee6..fd05e48 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21174,6 +21174,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 +21586,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 +21599,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 +21686,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 +22032,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 +22071,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/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index e07495d..f987d61 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -212,7 +212,7 @@ status_t BootAnimation::readyToRun() { // create the native surface sp<SurfaceControl> control = session()->createSurface( - getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565); + 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565); session()->openTransaction(); control->setLayer(0x40000000); session()->closeTransaction(); diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp index c1d0803..289665f 100644 --- a/cmds/stagefright/sf2.cpp +++ b/cmds/stagefright/sf2.cpp @@ -543,7 +543,6 @@ int main(int argc, char **argv) { CHECK_EQ(composerClient->initCheck(), (status_t)OK); control = composerClient->createSurface( - getpid(), String8("A Surface"), 0, 1280, diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp index be443d0..f780afb 100644 --- a/cmds/stagefright/stream.cpp +++ b/cmds/stagefright/stream.cpp @@ -149,7 +149,6 @@ int main(int argc, char **argv) { sp<SurfaceControl> control = composerClient->createSurface( - getpid(), String8("A Surface"), 0, 1280, diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index ad48786..93b3429 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -303,9 +303,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("{ fnt="); + sb.append("{"); sb.append(fontScale); - sb.append(" imsi="); + sb.append("x imsi="); sb.append(mcc); sb.append("/"); sb.append(mnc); diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java index 42d555c..2e8d551 100644 --- a/core/java/android/preference/MultiSelectListPreference.java +++ b/core/java/android/preference/MultiSelectListPreference.java @@ -169,9 +169,9 @@ public class MultiSelectListPreference extends DialogPreference { new DialogInterface.OnMultiChoiceClickListener() { public void onClick(DialogInterface dialog, int which, boolean isChecked) { if (isChecked) { - mPreferenceChanged |= mNewValues.add(mEntries[which].toString()); + mPreferenceChanged |= mNewValues.add(mEntryValues[which].toString()); } else { - mPreferenceChanged |= mNewValues.remove(mEntries[which].toString()); + mPreferenceChanged |= mNewValues.remove(mEntryValues[which].toString()); } } }); @@ -180,7 +180,7 @@ public class MultiSelectListPreference extends DialogPreference { } private boolean[] getSelectedItems() { - final CharSequence[] entries = mEntries; + final CharSequence[] entries = mEntryValues; final int entryCount = entries.length; final Set<String> values = mValues; boolean[] result = new boolean[entryCount]; diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index b18570a..679e2cc 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -16,10 +16,7 @@ package android.text; -import android.util.Log; - import java.text.BreakIterator; -import java.text.CharacterIterator; /** diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index b25ba8d..d432dee 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -17,23 +17,14 @@ package android.text.method; import android.graphics.Rect; -import android.text.CharSequenceIterator; -import android.text.Editable; import android.text.Layout; import android.text.Selection; import android.text.Spannable; -import android.text.Spanned; -import android.text.TextWatcher; -import android.util.Log; -import android.util.MathUtils; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; -import java.text.BreakIterator; -import java.text.CharacterIterator; - /** * A movement method that provides cursor movement and selection. * Supports displaying the context menu on DPad Center. @@ -332,102 +323,6 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme return sInstance; } - /** - * Walks through cursor positions at word boundaries. Internally uses - * {@link BreakIterator#getWordInstance()}, and caches {@link CharSequence} - * for performance reasons. - */ - private static class WordIterator implements Selection.PositionIterator { - private CharSequence mCurrent; - private boolean mCurrentDirty = false; - - private BreakIterator mIterator; - - private TextWatcher mWatcher = new TextWatcher() { - /** {@inheritDoc} */ - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // ignored - } - - /** {@inheritDoc} */ - public void onTextChanged(CharSequence s, int start, int before, int count) { - mCurrentDirty = true; - } - - /** {@inheritDoc} */ - public void afterTextChanged(Editable s) { - // ignored - } - }; - - public void setCharSequence(CharSequence incoming) { - if (mIterator == null) { - mIterator = BreakIterator.getWordInstance(); - } - - // when incoming is different object, move listeners to new sequence - // and mark as dirty so we reload contents. - if (mCurrent != incoming) { - if (mCurrent instanceof Editable) { - ((Editable) mCurrent).removeSpan(mWatcher); - } - - if (incoming instanceof Editable) { - ((Editable) incoming).setSpan( - mWatcher, 0, incoming.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - } - - mCurrent = incoming; - mCurrentDirty = true; - } - - if (mCurrentDirty) { - final CharacterIterator charIterator = new CharSequenceIterator(mCurrent); - mIterator.setText(charIterator); - - mCurrentDirty = false; - } - } - - private boolean isValidOffset(int offset) { - return offset >= 0 && offset <= mCurrent.length(); - } - - private boolean isLetterOrDigit(int offset) { - if (isValidOffset(offset)) { - return Character.isLetterOrDigit(mCurrent.charAt(offset)); - } else { - return false; - } - } - - /** {@inheritDoc} */ - public int preceding(int offset) { - // always round cursor index into valid string index - offset = MathUtils.constrain(offset, 0, mCurrent.length()); - - do { - offset = mIterator.preceding(offset); - if (isLetterOrDigit(offset)) break; - } while (isValidOffset(offset)); - - return offset; - } - - /** {@inheritDoc} */ - public int following(int offset) { - // always round cursor index into valid string index - offset = MathUtils.constrain(offset, 0, mCurrent.length()); - - do { - offset = mIterator.following(offset); - if (isLetterOrDigit(offset - 1)) break; - } while (isValidOffset(offset)); - - return offset; - } - } - private WordIterator mWordIterator = new WordIterator(); private static final Object LAST_TAP_DOWN = new Object(); diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java new file mode 100644 index 0000000..b250414 --- /dev/null +++ b/core/java/android/text/method/WordIterator.java @@ -0,0 +1,220 @@ + +/* + * 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.text.method; + +import android.text.CharSequenceIterator; +import android.text.Editable; +import android.text.Selection; +import android.text.Spanned; +import android.text.TextWatcher; + +import java.text.BreakIterator; +import java.text.CharacterIterator; +import java.util.Locale; + +/** + * Walks through cursor positions at word boundaries. Internally uses + * {@link BreakIterator#getWordInstance()}, and caches {@link CharSequence} + * for performance reasons. + * + * Also provides methods to determine word boundaries. + * {@hide} + */ +public class WordIterator implements Selection.PositionIterator { + private CharSequence mCurrent; + private boolean mCurrentDirty = false; + + private BreakIterator mIterator; + + /** + * Constructs a WordIterator using the default locale. + */ + public WordIterator() { + this(Locale.getDefault()); + } + + /** + * Constructs a new WordIterator for the specified locale. + * @param locale The locale to be used when analysing the text. + */ + public WordIterator(Locale locale) { + mIterator = BreakIterator.getWordInstance(locale); + } + + private final TextWatcher mWatcher = new TextWatcher() { + /** {@inheritDoc} */ + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // ignored + } + + /** {@inheritDoc} */ + public void onTextChanged(CharSequence s, int start, int before, int count) { + mCurrentDirty = true; + } + + /** {@inheritDoc} */ + public void afterTextChanged(Editable s) { + // ignored + } + }; + + public void setCharSequence(CharSequence incoming) { + // When incoming is different object, move listeners to new sequence + // and mark as dirty so we reload contents. + if (mCurrent != incoming) { + if (mCurrent instanceof Editable) { + ((Editable) mCurrent).removeSpan(mWatcher); + } + + if (incoming instanceof Editable) { + ((Editable) incoming).setSpan( + mWatcher, 0, incoming.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + + mCurrent = incoming; + mCurrentDirty = true; + } + + if (mCurrentDirty) { + final CharacterIterator charIterator = new CharSequenceIterator(mCurrent); + mIterator.setText(charIterator); + + mCurrentDirty = false; + } + } + + /** {@inheritDoc} */ + public int preceding(int offset) { + do { + offset = mIterator.preceding(offset); + if (offset == BreakIterator.DONE || isOnLetterOrDigit(offset)) { + break; + } + } while (true); + + return offset; + } + + /** {@inheritDoc} */ + public int following(int offset) { + do { + offset = mIterator.following(offset); + if (offset == BreakIterator.DONE || isAfterLetterOrDigit(offset)) { + break; + } + } while (true); + + return offset; + } + + /** If <code>offset</code> is within a word, returns the index of the first character of that + * word, otherwise returns BreakIterator.DONE. + * + * The offsets that are considered to be part of a word are the indexes of its characters, + * <i>as well as</i> the index of its last character plus one. + * If offset is the index of a low surrogate character, BreakIterator.DONE will be returned. + * + * Valid range for offset is [0..textLength] (note the inclusive upper bound). + * The returned value is within [0..offset] or BreakIterator.DONE. + * + * @throws IllegalArgumentException is offset is not valid. + */ + public int getBeginning(int offset) { + checkOffsetIsValid(offset); + + if (isOnLetterOrDigit(offset)) { + if (mIterator.isBoundary(offset)) { + return offset; + } else { + return mIterator.preceding(offset); + } + } else { + if (isAfterLetterOrDigit(offset)) { + return mIterator.preceding(offset); + } + } + return BreakIterator.DONE; + } + + /** If <code>offset</code> is within a word, returns the index of the last character of that + * word plus one, otherwise returns BreakIterator.DONE. + * + * The offsets that are considered to be part of a word are the indexes of its characters, + * <i>as well as</i> the index of its last character plus one. + * If offset is the index of a low surrogate character, BreakIterator.DONE will be returned. + * + * Valid range for offset is [0..textLength] (note the inclusive upper bound). + * The returned value is within [offset..textLength] or BreakIterator.DONE. + * + * @throws IllegalArgumentException is offset is not valid. + */ + public int getEnd(int offset) { + checkOffsetIsValid(offset); + + if (isAfterLetterOrDigit(offset)) { + if (mIterator.isBoundary(offset)) { + return offset; + } else { + return mIterator.following(offset); + } + } else { + if (isOnLetterOrDigit(offset)) { + return mIterator.following(offset); + } + } + return BreakIterator.DONE; + } + + private boolean isAfterLetterOrDigit(int offset) { + if (offset - 1 >= 0) { + final char previousChar = mCurrent.charAt(offset - 1); + if (Character.isLetterOrDigit(previousChar)) return true; + if (offset - 2 >= 0) { + final char previousPreviousChar = mCurrent.charAt(offset - 2); + if (Character.isSurrogatePair(previousPreviousChar, previousChar)) { + final int codePoint = Character.toCodePoint(previousPreviousChar, previousChar); + return Character.isLetterOrDigit(codePoint); + } + } + } + return false; + } + + private boolean isOnLetterOrDigit(int offset) { + final int length = mCurrent.length(); + if (offset < length) { + final char currentChar = mCurrent.charAt(offset); + if (Character.isLetterOrDigit(currentChar)) return true; + if (offset + 1 < length) { + final char nextChar = mCurrent.charAt(offset + 1); + if (Character.isSurrogatePair(currentChar, nextChar)) { + final int codePoint = Character.toCodePoint(currentChar, nextChar); + return Character.isLetterOrDigit(codePoint); + } + } + } + return false; + } + + private void checkOffsetIsValid(int offset) { + if (offset < 0 || offset > mCurrent.length()) { + final String message = "Valid range is [0, " + mCurrent.length() + "]"; + throw new IllegalArgumentException(message); + } + } +} diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 980239b..8e839c0 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -200,8 +200,27 @@ public class Display { * @param outMetrics */ public void getMetrics(DisplayMetrics outMetrics) { - outMetrics.widthPixels = getWidth(); - outMetrics.heightPixels = getHeight(); + synchronized (mTmpPoint) { + getSize(mTmpPoint); + outMetrics.widthPixels = mTmpPoint.x; + outMetrics.heightPixels = mTmpPoint.y; + } + getNonSizeMetrics(outMetrics); + } + + /** + * Initialize a DisplayMetrics object from this display's data. + * + * @param outMetrics + * @hide + */ + public void getRealMetrics(DisplayMetrics outMetrics) { + outMetrics.widthPixels = getRealWidth(); + outMetrics.heightPixels = getRealHeight(); + getNonSizeMetrics(outMetrics); + } + + private void getNonSizeMetrics(DisplayMetrics outMetrics) { outMetrics.density = mDensity; outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f); outMetrics.scaledDensity= outMetrics.density; diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java index b5ca2c2..e14b975 100644 --- a/core/java/android/view/InputEventConsistencyVerifier.java +++ b/core/java/android/view/InputEventConsistencyVerifier.java @@ -30,7 +30,6 @@ import android.util.Log; * @hide */ public final class InputEventConsistencyVerifier { - private static final String TAG = "InputEventConsistencyVerifier"; private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE); // The number of recent events to log when a problem is detected. @@ -44,6 +43,11 @@ public final class InputEventConsistencyVerifier { // Consistency verifier flags. private final int mFlags; + // Tag for logging which a client can set to help distinguish the output + // from different verifiers since several can be active at the same time. + // If not provided defaults to the simple class name. + private final String mLogTag; + // The most recently checked event and the nesting level at which it was checked. // This is only set when the verifier is called from a nesting level greater than 0 // so that the verifier can detect when it has been asked to verify the same event twice. @@ -103,8 +107,19 @@ public final class InputEventConsistencyVerifier { * @param flags Flags to the verifier, or 0 if none. */ public InputEventConsistencyVerifier(Object caller, int flags) { + this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName()); + } + + /** + * Creates an input consistency verifier. + * @param caller The object to which the verifier is attached. + * @param flags Flags to the verifier, or 0 if none. + * @param logTag Tag for logging. If null defaults to the short class name. + */ + public InputEventConsistencyVerifier(Object caller, int flags, String logTag) { this.mCaller = caller; this.mFlags = flags; + this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier"; } /** @@ -596,7 +611,7 @@ public final class InputEventConsistencyVerifier { } } - Log.d(TAG, mViolationMessage.toString()); + Log.d(mLogTag, mViolationMessage.toString()); mViolationMessage.setLength(0); tainted = true; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4a62892..4bc7f39 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3455,6 +3455,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if (!isShown()) { return; } + + // Populate these here since they are related to the View that + // sends the event and should not be modified while dispatching + // to descendants. event.setClassName(getClass().getName()); event.setPackageName(getContext().getPackageName()); event.setEnabled(isEnabled()); @@ -3470,22 +3474,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility dispatchPopulateAccessibilityEvent(event); - AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event); + // In the beginning we called #isShown(), so we know that getParent() is not null. + getParent().requestSendAccessibilityEvent(this, event); } /** - * Dispatches an {@link AccessibilityEvent} to the {@link View} children - * to be populated. + * Dispatches an {@link AccessibilityEvent} to the {@link View} children to be populated. + * This method first calls {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} + * on this view allowing it to populate information about itself and also decide + * whether to intercept the population i.e. to prevent its children from populating + * the event. * * @param event The event. * * @return True if the event population was completed. */ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); return false; } /** + * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} + * giving a chance to this View to populate the accessibility evnet with + * information about itself. + * + * @param event The accessibility event which to populate. + */ + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + + } + + /** * Gets the {@link View} description. It briefly describes the view and is * primarily used for accessibility support. Set this property to enable * better accessibility support for your application. This is especially @@ -5390,20 +5410,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * to receive the hover event. */ public boolean onHoverEvent(MotionEvent event) { - final int viewFlags = mViewFlags; - - if (((viewFlags & CLICKABLE) != CLICKABLE && - (viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) { - // Nothing to do if the view is not clickable. - return false; - } - - if ((viewFlags & ENABLED_MASK) == DISABLED) { - // A disabled view that is clickable still consumes the hover events, it just doesn't - // respond to them. - return true; - } - switch (event.getAction()) { case MotionEvent.ACTION_HOVER_ENTER: setHovered(true); @@ -5414,7 +5420,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility break; } - return true; + return false; } /** @@ -5436,11 +5442,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if ((mPrivateFlags & HOVERED) == 0) { mPrivateFlags |= HOVERED; refreshDrawableState(); + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); } } else { if ((mPrivateFlags & HOVERED) != 0) { mPrivateFlags &= ~HOVERED; refreshDrawableState(); + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); } } } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 739758c..94eb429 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -19,7 +19,6 @@ package android.view; import android.app.AppGlobals; import android.content.Context; import android.content.res.Configuration; -import android.os.Bundle; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.SparseArray; @@ -156,6 +155,13 @@ public class ViewConfiguration { private static final int MAXIMUM_FLING_VELOCITY = 8000; /** + * Distance between a touch up event denoting the end of a touch exploration + * gesture and the touch up event of a subsequent tap for the latter tap to be + * considered as a tap i.e. to perform a click. + */ + private static final int TOUCH_EXPLORATION_TAP_SLOP = 80; + + /** * The maximum size of View's drawing cache, expressed in bytes. This size * should be at least equal to the size of the screen in ARGB888 format. */ @@ -185,6 +191,7 @@ public class ViewConfiguration { private final int mTouchSlop; private final int mPagingTouchSlop; private final int mDoubleTapSlop; + private final int mScaledTouchExplorationTapSlop; private final int mWindowTouchSlop; private final int mMaximumDrawingCacheSize; private final int mOverscrollDistance; @@ -206,6 +213,7 @@ public class ViewConfiguration { mTouchSlop = TOUCH_SLOP; mPagingTouchSlop = PAGING_TOUCH_SLOP; mDoubleTapSlop = DOUBLE_TAP_SLOP; + mScaledTouchExplorationTapSlop = TOUCH_EXPLORATION_TAP_SLOP; mWindowTouchSlop = WINDOW_TOUCH_SLOP; //noinspection deprecation mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE; @@ -242,6 +250,7 @@ public class ViewConfiguration { mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f); mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f); mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f); + mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f); mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f); // Size of the screen in bytes, in ARGB_8888 format @@ -444,6 +453,17 @@ public class ViewConfiguration { } /** + * @return Distance between a touch up event denoting the end of a touch exploration + * gesture and the touch up event of a subsequent tap for the latter tap to be + * considered as a tap i.e. to perform a click. + * + * @hide + */ + public int getScaledTouchExplorationTapSlop() { + return mScaledTouchExplorationTapSlop; + } + + /** * @return Distance a touch must be outside the bounds of a window for it * to be counted as outside the window for purposes of dismissing that * window. diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 08daa28..7b404b4 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -586,6 +586,35 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * {@inheritDoc} */ + public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { + ViewParent parent = getParent(); + if (parent == null) { + return false; + } + final boolean propagate = onRequestSendAccessibilityEvent(child, event); + if (!propagate) { + return false; + } + return parent.requestSendAccessibilityEvent(this, event); + } + + /** + * Called when a child has requested sending an {@link AccessibilityEvent} and + * gives an opportunity to its parent to augment the event. + * + * @param child The child which requests sending the event. + * @param event The event to be sent. + * @return True if the event should be sent. + * + * @see #requestSendAccessibilityEvent(View, AccessibilityEvent) + */ + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + return true; + } + + /** + * {@inheritDoc} + */ @Override public boolean dispatchUnhandledMove(View focused, int direction) { return mFocused != null && @@ -1216,9 +1245,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild); eventNoHistory.setAction(action); - mHoveredChild = null; - } else if (action == MotionEvent.ACTION_HOVER_MOVE) { + } else { // Pointer is still within the child. handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild); } @@ -1278,6 +1306,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return handled; } + @Override + public boolean onHoverEvent(MotionEvent event) { + // Handle the event only if leaf. This guarantees that + // the leafs (or any custom class that returns true from + // this method) will get a change to process the hover. + if (getChildCount() == 0) { + return super.onHoverEvent(event); + } + return false; + } + private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) { if (event.getHistorySize() == 0) { return event; @@ -2091,11 +2130,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - boolean populated = false; + // We first get a chance to populate the event. + onPopulateAccessibilityEvent(event); + // Let our children have a shot in populating the event. for (int i = 0, count = getChildCount(); i < count; i++) { - populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event); + boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event); + if (handled) { + return handled; + } } - return populated; + return false; } /** diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index d7d4c3f..655df39 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -17,6 +17,7 @@ package android.view; import android.graphics.Rect; +import android.view.accessibility.AccessibilityEvent; /** * Defines the responsibilities for a class that will be a parent of a View. @@ -222,4 +223,22 @@ public interface ViewParent { */ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate); + + /** + * Called by a child to request from its parent to send an {@link AccessibilityEvent}. + * The child has already populated a record for itself in the event and is delegating + * to its parent to send the event. The parent can optionally add a record for itself. + * <p> + * Note: An accessibility event is fired by an individual view which populates the + * event with a record for its state and requests from its parent to perform + * the sending. The parent can optionally add a record for itself before + * dispatching the request to its parent. A parent can also choose not to + * respect the request for sending the event. The accessibility event is sent + * by the topmost view in the view tree. + * + * @param child The child which requests sending the event. + * @param event The event to be sent. + * @return True if the event was sent. + */ + public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event); } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 4104b07..f02daba 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -3530,6 +3530,14 @@ public final class ViewRoot extends Handler implements ViewParent, public void childDrawableStateChanged(View child) { } + public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (mView == null) { + return false; + } + AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event); + return true; + } + void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 9d00d02..3d19380 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -396,6 +396,12 @@ public interface WindowManagerPolicy { LocalPowerManager powerManager); /** + * Called by window manager once it has the initial, default native + * display dimensions. + */ + public void setInitialDisplaySize(int width, int height); + + /** * Check permissions when adding a window. * * @param attrs The window's LayoutParams. @@ -810,6 +816,13 @@ public interface WindowManagerPolicy { boolean displayEnabled); /** + * Return the currently locked screen rotation, if any. Return + * Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, or + * Surface.ROTATION_270 if locked; return -1 if not locked. + */ + public int getLockedRotationLw(); + + /** * Called when the system is mostly done booting to determine whether * the system should go into safe mode. */ diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 9af19b8..11c9392 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -21,13 +21,26 @@ import android.os.Parcelable; import android.text.TextUtils; import java.util.ArrayList; -import java.util.List; /** * This class represents accessibility events that are sent by the system when * something notable happens in the user interface. For example, when a * {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc. * <p> + * An accessibility event is fired by an individual view which populates the event with + * a record for its state and requests from its parent to send the event to interested + * parties. The parent can optionally add a record for itself before dispatching a similar + * request to its parent. A parent can also choose not to respect the request for sending + * an event. The accessibility event is sent by the topmost view in the view tree. + * Therefore, an {@link android.accessibilityservice.AccessibilityService} can explore + * all records in an accessibility event to obtain more information about the context + * in which the event was fired. + * <p> + * A client can add, remove, and modify records. The getters and setters for individual + * properties operate on the current record which can be explicitly set by the client. By + * default current is the first record. Thus, querying a record would require setting + * it as the current one and interacting with the property getters and setters. + * <p> * This class represents various semantically different accessibility event * types. Each event type has associated a set of related properties. In other * words, each event type is characterized via a subset of the properties exposed @@ -145,7 +158,7 @@ import java.util.List; * @see android.view.accessibility.AccessibilityManager * @see android.accessibilityservice.AccessibilityService */ -public final class AccessibilityEvent implements Parcelable { +public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable { /** * Invalid selection/focus position. @@ -207,6 +220,26 @@ public final class AccessibilityEvent implements Parcelable { public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040; /** + * Represents the event of a hover enter over a {@link android.view.View}. + */ + public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080; + + /** + * Represents the event of a hover exit over a {@link android.view.View}. + */ + public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100; + + /** + * Represents the event of starting a touch exploration gesture. + */ + public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200; + + /** + * Represents the event of ending a touch exploration gesture. + */ + public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400; + + /** * Mask for {@link AccessibilityEvent} all types. * * @see #TYPE_VIEW_CLICKED @@ -219,116 +252,53 @@ public final class AccessibilityEvent implements Parcelable { */ public static final int TYPES_ALL_MASK = 0xFFFFFFFF; - private static final int MAX_POOL_SIZE = 2; + private static final int MAX_POOL_SIZE = 10; private static final Object mPoolLock = new Object(); private static AccessibilityEvent sPool; private static int sPoolSize; - private static final int CHECKED = 0x00000001; - private static final int ENABLED = 0x00000002; - private static final int PASSWORD = 0x00000004; - private static final int FULL_SCREEN = 0x00000080; - private AccessibilityEvent mNext; + private boolean mIsInPool; private int mEventType; - private int mBooleanProperties; - private int mCurrentItemIndex; - private int mItemCount; - private int mFromIndex; - private int mAddedCount; - private int mRemovedCount; - - private long mEventTime; - - private CharSequence mClassName; private CharSequence mPackageName; - private CharSequence mContentDescription; - private CharSequence mBeforeText; - - private Parcelable mParcelableData; - - private final List<CharSequence> mText = new ArrayList<CharSequence>(); + private long mEventTime; - private boolean mIsInPool; + private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>(); /* * Hide constructor from clients. */ private AccessibilityEvent() { - mCurrentItemIndex = INVALID_POSITION; - } - - /** - * Gets if the source is checked. - * - * @return True if the view is checked, false otherwise. - */ - public boolean isChecked() { - return getBooleanProperty(CHECKED); - } - - /** - * Sets if the source is checked. - * - * @param isChecked True if the view is checked, false otherwise. - */ - public void setChecked(boolean isChecked) { - setBooleanProperty(CHECKED, isChecked); - } - /** - * Gets if the source is enabled. - * - * @return True if the view is enabled, false otherwise. - */ - public boolean isEnabled() { - return getBooleanProperty(ENABLED); - } - - /** - * Sets if the source is enabled. - * - * @param isEnabled True if the view is enabled, false otherwise. - */ - public void setEnabled(boolean isEnabled) { - setBooleanProperty(ENABLED, isEnabled); - } - - /** - * Gets if the source is a password field. - * - * @return True if the view is a password field, false otherwise. - */ - public boolean isPassword() { - return getBooleanProperty(PASSWORD); } /** - * Sets if the source is a password field. + * Gets the number of records contained in the event. * - * @param isPassword True if the view is a password field, false otherwise. + * @return The number of records. */ - public void setPassword(boolean isPassword) { - setBooleanProperty(PASSWORD, isPassword); + public int getRecordCount() { + return mRecords.size(); } /** - * Sets if the source is taking the entire screen. + * Appends an {@link AccessibilityRecord} to the end of event records. * - * @param isFullScreen True if the source is full screen, false otherwise. + * @param record The record to append. */ - public void setFullScreen(boolean isFullScreen) { - setBooleanProperty(FULL_SCREEN, isFullScreen); + public void appendRecord(AccessibilityRecord record) { + mRecords.add(record); } /** - * Gets if the source is taking the entire screen. + * Gets the records at a given index. * - * @return True if the source is full screen, false otherwise. + * @param index The index. + * @return The records at the specified index. */ - public boolean isFullScreen() { - return getBooleanProperty(FULL_SCREEN); + public AccessibilityRecord getRecord(int index) { + return mRecords.get(index); } /** @@ -350,96 +320,6 @@ public final class AccessibilityEvent implements Parcelable { } /** - * Gets the number of items that can be visited. - * - * @return The number of items. - */ - public int getItemCount() { - return mItemCount; - } - - /** - * Sets the number of items that can be visited. - * - * @param itemCount The number of items. - */ - public void setItemCount(int itemCount) { - mItemCount = itemCount; - } - - /** - * Gets the index of the source in the list of items the can be visited. - * - * @return The current item index. - */ - public int getCurrentItemIndex() { - return mCurrentItemIndex; - } - - /** - * Sets the index of the source in the list of items that can be visited. - * - * @param currentItemIndex The current item index. - */ - public void setCurrentItemIndex(int currentItemIndex) { - mCurrentItemIndex = currentItemIndex; - } - - /** - * Gets the index of the first character of the changed sequence. - * - * @return The index of the first character. - */ - public int getFromIndex() { - return mFromIndex; - } - - /** - * Sets the index of the first character of the changed sequence. - * - * @param fromIndex The index of the first character. - */ - public void setFromIndex(int fromIndex) { - mFromIndex = fromIndex; - } - - /** - * Gets the number of added characters. - * - * @return The number of added characters. - */ - public int getAddedCount() { - return mAddedCount; - } - - /** - * Sets the number of added characters. - * - * @param addedCount The number of added characters. - */ - public void setAddedCount(int addedCount) { - mAddedCount = addedCount; - } - - /** - * Gets the number of removed characters. - * - * @return The number of removed characters. - */ - public int getRemovedCount() { - return mRemovedCount; - } - - /** - * Sets the number of removed characters. - * - * @param removedCount The number of removed characters. - */ - public void setRemovedCount(int removedCount) { - mRemovedCount = removedCount; - } - - /** * Gets the time in which this event was sent. * * @return The event time. @@ -458,24 +338,6 @@ public final class AccessibilityEvent implements Parcelable { } /** - * Gets the class name of the source. - * - * @return The class name. - */ - public CharSequence getClassName() { - return mClassName; - } - - /** - * Sets the class name of the source. - * - * @param className The lass name. - */ - public void setClassName(CharSequence className) { - mClassName = className; - } - - /** * Gets the package name of the source. * * @return The package name. @@ -494,70 +356,6 @@ public final class AccessibilityEvent implements Parcelable { } /** - * Gets the text of the event. The index in the list represents the priority - * of the text. Specifically, the lower the index the higher the priority. - * - * @return The text. - */ - public List<CharSequence> getText() { - return mText; - } - - /** - * Sets the text before a change. - * - * @return The text before the change. - */ - public CharSequence getBeforeText() { - return mBeforeText; - } - - /** - * Sets the text before a change. - * - * @param beforeText The text before the change. - */ - public void setBeforeText(CharSequence beforeText) { - mBeforeText = beforeText; - } - - /** - * Gets the description of the source. - * - * @return The description. - */ - public CharSequence getContentDescription() { - return mContentDescription; - } - - /** - * Sets the description of the source. - * - * @param contentDescription The description. - */ - public void setContentDescription(CharSequence contentDescription) { - mContentDescription = contentDescription; - } - - /** - * Gets the {@link Parcelable} data. - * - * @return The parcelable data. - */ - public Parcelable getParcelableData() { - return mParcelableData; - } - - /** - * Sets the {@link Parcelable} data of the event. - * - * @param parcelableData The parcelable data. - */ - public void setParcelableData(Parcelable parcelableData) { - mParcelableData = parcelableData; - } - - /** * Returns a cached instance if such is available or a new one is * instantiated with type property set. * @@ -595,11 +393,11 @@ public final class AccessibilityEvent implements Parcelable { * <p> * <b>Note: You must not touch the object after calling this function.</b> */ + @Override public void recycle() { if (mIsInPool) { return; } - clear(); synchronized (mPoolLock) { if (sPoolSize <= MAX_POOL_SIZE) { @@ -614,44 +412,15 @@ public final class AccessibilityEvent implements Parcelable { /** * Clears the state of this instance. */ - private void clear() { + @Override + protected void clear() { + super.clear(); mEventType = 0; - mBooleanProperties = 0; - mCurrentItemIndex = INVALID_POSITION; - mItemCount = 0; - mFromIndex = 0; - mAddedCount = 0; - mRemovedCount = 0; - mEventTime = 0; - mClassName = null; mPackageName = null; - mContentDescription = null; - mBeforeText = null; - mParcelableData = null; - mText.clear(); - } - - /** - * Gets the value of a boolean property. - * - * @param property The property. - * @return The value. - */ - private boolean getBooleanProperty(int property) { - return (mBooleanProperties & property) == property; - } - - /** - * Sets a boolean property. - * - * @param property The property. - * @param value The value. - */ - private void setBooleanProperty(int property, boolean value) { - if (value) { - mBooleanProperties |= property; - } else { - mBooleanProperties &= ~property; + mEventTime = 0; + while (!mRecords.isEmpty()) { + AccessibilityRecord record = mRecords.remove(0); + record.recycle(); } } @@ -662,38 +431,82 @@ public final class AccessibilityEvent implements Parcelable { */ public void initFromParcel(Parcel parcel) { mEventType = parcel.readInt(); - mBooleanProperties = parcel.readInt(); - mCurrentItemIndex = parcel.readInt(); - mItemCount = parcel.readInt(); - mFromIndex = parcel.readInt(); - mAddedCount = parcel.readInt(); - mRemovedCount = parcel.readInt(); - mEventTime = parcel.readLong(); - mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - mParcelableData = parcel.readParcelable(null); - parcel.readList(mText, null); + mEventTime = parcel.readLong(); + readAccessibilityRecordFromParcel(this, parcel); + + // Read the records. + final int recordCount = parcel.readInt(); + for (int i = 0; i < recordCount; i++) { + AccessibilityRecord record = AccessibilityRecord.obtain(); + readAccessibilityRecordFromParcel(record, parcel); + mRecords.add(record); + } } + /** + * Reads an {@link AccessibilityRecord} from a parcel. + * + * @param record The record to initialize. + * @param parcel The parcel to read from. + */ + private void readAccessibilityRecordFromParcel(AccessibilityRecord record, + Parcel parcel) { + record.mBooleanProperties = parcel.readInt(); + record.mCurrentItemIndex = parcel.readInt(); + record.mItemCount = parcel.readInt(); + record.mFromIndex = parcel.readInt(); + record.mAddedCount = parcel.readInt(); + record.mRemovedCount = parcel.readInt(); + record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + record.mParcelableData = parcel.readParcelable(null); + parcel.readList(record.mText, null); + } + + /** + * {@inheritDoc} + */ public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mEventType); - parcel.writeInt(mBooleanProperties); - parcel.writeInt(mCurrentItemIndex); - parcel.writeInt(mItemCount); - parcel.writeInt(mFromIndex); - parcel.writeInt(mAddedCount); - parcel.writeInt(mRemovedCount); - parcel.writeLong(mEventTime); - TextUtils.writeToParcel(mClassName, parcel, 0); TextUtils.writeToParcel(mPackageName, parcel, 0); - TextUtils.writeToParcel(mContentDescription, parcel, 0); - TextUtils.writeToParcel(mBeforeText, parcel, 0); - parcel.writeParcelable(mParcelableData, flags); - parcel.writeList(mText); + parcel.writeLong(mEventTime); + writeAccessibilityRecordToParcel(this, parcel, flags); + + // Write the records. + final int recordCount = getRecordCount(); + parcel.writeInt(recordCount); + for (int i = 0; i < recordCount; i++) { + AccessibilityRecord record = mRecords.get(i); + writeAccessibilityRecordToParcel(record, parcel, flags); + } + } + + /** + * Writes an {@link AccessibilityRecord} to a parcel. + * + * @param record The record to write. + * @param parcel The parcel to which to write. + */ + private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel, + int flags) { + parcel.writeInt(record.mBooleanProperties); + parcel.writeInt(record.mCurrentItemIndex); + parcel.writeInt(record.mItemCount); + parcel.writeInt(record.mFromIndex); + parcel.writeInt(record.mAddedCount); + parcel.writeInt(record.mRemovedCount); + TextUtils.writeToParcel(record.mClassName, parcel, flags); + TextUtils.writeToParcel(record.mContentDescription, parcel, flags); + TextUtils.writeToParcel(record.mBeforeText, parcel, flags); + parcel.writeParcelable(record.mParcelableData, flags); + parcel.writeList(record.mText); } + /** + * {@inheritDoc} + */ public int describeContents() { return 0; } @@ -701,24 +514,21 @@ public final class AccessibilityEvent implements Parcelable { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append(super.toString()); builder.append("; EventType: " + mEventType); builder.append("; EventTime: " + mEventTime); - builder.append("; ClassName: " + mClassName); builder.append("; PackageName: " + mPackageName); - builder.append("; Text: " + mText); - builder.append("; ContentDescription: " + mContentDescription); - builder.append("; ItemCount: " + mItemCount); - builder.append("; CurrentItemIndex: " + mCurrentItemIndex); - builder.append("; IsEnabled: " + isEnabled()); - builder.append("; IsPassword: " + isPassword()); - builder.append("; IsChecked: " + isChecked()); - builder.append("; IsFullScreen: " + isFullScreen()); - builder.append("; BeforeText: " + mBeforeText); - builder.append("; FromIndex: " + mFromIndex); - builder.append("; AddedCount: " + mAddedCount); - builder.append("; RemovedCount: " + mRemovedCount); - builder.append("; ParcelableData: " + mParcelableData); + builder.append(" \n{\n"); + builder.append(super.toString()); + builder.append("\n"); + for (int i = 0; i < mRecords.size(); i++) { + AccessibilityRecord record = mRecords.get(i); + builder.append(" Record "); + builder.append(i); + builder.append(":"); + builder.append(record.toString()); + builder.append("\n"); + } + builder.append("}\n"); return builder.toString(); } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 22cb0d4..dd77193 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -16,6 +16,8 @@ package android.view.accessibility; +import android.accessibilityservice.AccessibilityService; +import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.pm.ServiceInfo; import android.os.Binder; @@ -44,6 +46,8 @@ import java.util.List; * @see android.content.Context#getSystemService */ public final class AccessibilityManager { + private static final boolean DEBUG = false; + private static final String LOG_TAG = "AccessibilityManager"; static final Object sInstanceSync = new Object(); @@ -164,7 +168,7 @@ public final class AccessibilityManager { long identityToken = Binder.clearCallingIdentity(); doRecycle = mService.sendAccessibilityEvent(event); Binder.restoreCallingIdentity(identityToken); - if (false) { + if (DEBUG) { Log.i(LOG_TAG, event + " sent"); } } catch (RemoteException re) { @@ -185,7 +189,7 @@ public final class AccessibilityManager { } try { mService.interrupt(); - if (false) { + if (DEBUG) { Log.i(LOG_TAG, "Requested interrupt from all services"); } } catch (RemoteException re) { @@ -202,7 +206,33 @@ public final class AccessibilityManager { List<ServiceInfo> services = null; try { services = mService.getAccessibilityServiceList(); - if (false) { + if (DEBUG) { + Log.i(LOG_TAG, "Installed AccessibilityServices " + services); + } + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); + } + return Collections.unmodifiableList(services); + } + + /** + * Returns the {@link ServiceInfo}s of the enabled accessibility services + * for a given feedback type. + * + * @param feedbackType The type of feedback. + * @return An unmodifiable list with {@link ServiceInfo}s. + * + * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE + * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC + * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN + * @see AccessibilityServiceInfo#FEEDBACK_VISUAL + * @see AccessibilityServiceInfo#FEEDBACK_GENERIC + */ + public List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) { + List<ServiceInfo> services = null; + try { + services = mService.getEnabledAccessibilityServiceList(feedbackType); + if (DEBUG) { Log.i(LOG_TAG, "Installed AccessibilityServices " + services); } } catch (RemoteException re) { diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java new file mode 100644 index 0000000..e095f43 --- /dev/null +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.accessibility; + +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a record in an accessibility event. This class encapsulates + * the information for a {@link android.view.View}. Note that not all properties + * are applicable to all view types. For detailed information please refer to + * {@link AccessibilityEvent}. + * + * @see AccessibilityEvent + */ +public class AccessibilityRecord { + + private static final int INVALID_POSITION = -1; + + private static final int PROPERTY_CHECKED = 0x00000001; + private static final int PROPERTY_ENABLED = 0x00000002; + private static final int PROPERTY_PASSWORD = 0x00000004; + private static final int PROPERTY_FULL_SCREEN = 0x00000080; + + private static final int MAX_POOL_SIZE = 10; + private static final Object mPoolLock = new Object(); + private static AccessibilityRecord sPool; + private static int sPoolSize; + + private AccessibilityRecord mNext; + private boolean mIsInPool; + + protected int mBooleanProperties; + protected int mCurrentItemIndex; + protected int mItemCount; + protected int mFromIndex; + protected int mAddedCount; + protected int mRemovedCount; + + protected CharSequence mClassName; + protected CharSequence mContentDescription; + protected CharSequence mBeforeText; + protected Parcelable mParcelableData; + + protected final List<CharSequence> mText = new ArrayList<CharSequence>(); + + /* + * Hide constructor. + */ + protected AccessibilityRecord() { + + } + + /** + * Gets if the source is checked. + * + * @return True if the view is checked, false otherwise. + */ + public boolean isChecked() { + return getBooleanProperty(PROPERTY_CHECKED); + } + + /** + * Sets if the source is checked. + * + * @param isChecked True if the view is checked, false otherwise. + */ + public void setChecked(boolean isChecked) { + setBooleanProperty(PROPERTY_CHECKED, isChecked); + } + + /** + * Gets if the source is enabled. + * + * @return True if the view is enabled, false otherwise. + */ + public boolean isEnabled() { + return getBooleanProperty(PROPERTY_ENABLED); + } + + /** + * Sets if the source is enabled. + * + * @param isEnabled True if the view is enabled, false otherwise. + */ + public void setEnabled(boolean isEnabled) { + setBooleanProperty(PROPERTY_ENABLED, isEnabled); + } + + /** + * Gets if the source is a password field. + * + * @return True if the view is a password field, false otherwise. + */ + public boolean isPassword() { + return getBooleanProperty(PROPERTY_PASSWORD); + } + + /** + * Sets if the source is a password field. + * + * @param isPassword True if the view is a password field, false otherwise. + */ + public void setPassword(boolean isPassword) { + setBooleanProperty(PROPERTY_PASSWORD, isPassword); + } + + /** + * Sets if the source is taking the entire screen. + * + * @param isFullScreen True if the source is full screen, false otherwise. + */ + public void setFullScreen(boolean isFullScreen) { + setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen); + } + + /** + * Gets if the source is taking the entire screen. + * + * @return True if the source is full screen, false otherwise. + */ + public boolean isFullScreen() { + return getBooleanProperty(PROPERTY_FULL_SCREEN); + } + + /** + * Gets the number of items that can be visited. + * + * @return The number of items. + */ + public int getItemCount() { + return mItemCount; + } + + /** + * Sets the number of items that can be visited. + * + * @param itemCount The number of items. + */ + public void setItemCount(int itemCount) { + mItemCount = itemCount; + } + + /** + * Gets the index of the source in the list of items the can be visited. + * + * @return The current item index. + */ + public int getCurrentItemIndex() { + return mCurrentItemIndex; + } + + /** + * Sets the index of the source in the list of items that can be visited. + * + * @param currentItemIndex The current item index. + */ + public void setCurrentItemIndex(int currentItemIndex) { + mCurrentItemIndex = currentItemIndex; + } + + /** + * Gets the index of the first character of the changed sequence. + * + * @return The index of the first character. + */ + public int getFromIndex() { + return mFromIndex; + } + + /** + * Sets the index of the first character of the changed sequence. + * + * @param fromIndex The index of the first character. + */ + public void setFromIndex(int fromIndex) { + mFromIndex = fromIndex; + } + + /** + * Gets the number of added characters. + * + * @return The number of added characters. + */ + public int getAddedCount() { + return mAddedCount; + } + + /** + * Sets the number of added characters. + * + * @param addedCount The number of added characters. + */ + public void setAddedCount(int addedCount) { + mAddedCount = addedCount; + } + + /** + * Gets the number of removed characters. + * + * @return The number of removed characters. + */ + public int getRemovedCount() { + return mRemovedCount; + } + + /** + * Sets the number of removed characters. + * + * @param removedCount The number of removed characters. + */ + public void setRemovedCount(int removedCount) { + mRemovedCount = removedCount; + } + + /** + * Gets the class name of the source. + * + * @return The class name. + */ + public CharSequence getClassName() { + return mClassName; + } + + /** + * Sets the class name of the source. + * + * @param className The lass name. + */ + public void setClassName(CharSequence className) { + mClassName = className; + } + + /** + * Gets the text of the event. The index in the list represents the priority + * of the text. Specifically, the lower the index the higher the priority. + * + * @return The text. + */ + public List<CharSequence> getText() { + return mText; + } + + /** + * Sets the text before a change. + * + * @return The text before the change. + */ + public CharSequence getBeforeText() { + return mBeforeText; + } + + /** + * Sets the text before a change. + * + * @param beforeText The text before the change. + */ + public void setBeforeText(CharSequence beforeText) { + mBeforeText = beforeText; + } + + /** + * Gets the description of the source. + * + * @return The description. + */ + public CharSequence getContentDescription() { + return mContentDescription; + } + + /** + * Sets the description of the source. + * + * @param contentDescription The description. + */ + public void setContentDescription(CharSequence contentDescription) { + mContentDescription = contentDescription; + } + + /** + * Gets the {@link Parcelable} data. + * + * @return The parcelable data. + */ + public Parcelable getParcelableData() { + return mParcelableData; + } + + /** + * Sets the {@link Parcelable} data of the event. + * + * @param parcelableData The parcelable data. + */ + public void setParcelableData(Parcelable parcelableData) { + mParcelableData = parcelableData; + } + + /** + * Gets the value of a boolean property. + * + * @param property The property. + * @return The value. + */ + public boolean getBooleanProperty(int property) { + return (mBooleanProperties & property) == property; + } + + /** + * Sets a boolean property. + * + * @param property The property. + * @param value The value. + */ + private void setBooleanProperty(int property, boolean value) { + if (value) { + mBooleanProperties |= property; + } else { + mBooleanProperties &= ~property; + } + } + + /** + * Returns a cached instance if such is available or a new one is + * instantiated. + * + * @return An instance. + */ + protected static AccessibilityRecord obtain() { + synchronized (mPoolLock) { + if (sPool != null) { + AccessibilityRecord record = sPool; + sPool = sPool.mNext; + sPoolSize--; + record.mNext = null; + record.mIsInPool = false; + return record; + } + return new AccessibilityRecord(); + } + } + + /** + * Return an instance back to be reused. + * <p> + * <b>Note: You must not touch the object after calling this function.</b> + */ + public void recycle() { + if (mIsInPool) { + return; + } + clear(); + synchronized (mPoolLock) { + if (sPoolSize <= MAX_POOL_SIZE) { + mNext = sPool; + sPool = this; + mIsInPool = true; + sPoolSize++; + } + } + } + + /** + * Clears the state of this instance. + */ + protected void clear() { + mBooleanProperties = 0; + mCurrentItemIndex = INVALID_POSITION; + mItemCount = 0; + mFromIndex = 0; + mAddedCount = 0; + mRemovedCount = 0; + mClassName = null; + mContentDescription = null; + mBeforeText = null; + mParcelableData = null; + mText.clear(); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(" [ ClassName: " + mClassName); + builder.append("; Text: " + mText); + builder.append("; ContentDescription: " + mContentDescription); + builder.append("; ItemCount: " + mItemCount); + builder.append("; CurrentItemIndex: " + mCurrentItemIndex); + builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED)); + builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD)); + builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED)); + builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN)); + builder.append("; BeforeText: " + mBeforeText); + builder.append("; FromIndex: " + mFromIndex); + builder.append("; AddedCount: " + mAddedCount); + builder.append("; RemovedCount: " + mRemovedCount); + builder.append("; ParcelableData: " + mParcelableData); + builder.append(" ]"); + return builder.toString(); + } +} diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 7633569..aaaae32 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -35,5 +35,7 @@ interface IAccessibilityManager { List<ServiceInfo> getAccessibilityServiceList(); + List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType); + void interrupt(); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 6cb5c35..d63d421 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -55,6 +55,7 @@ import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; @@ -2556,6 +2557,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + // Add a record for ourselves as well. + AccessibilityEvent record = AccessibilityEvent.obtain(); + // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent + record.setClassName(getClass().getName()); + child.dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return false; } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index f16efbd..060f1a9 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -876,7 +876,6 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - boolean populated = false; // This is an exceptional case which occurs when a window gets the // focus and sends a focus event via its focused child to announce // current focus/selection. AdapterView fires selection but not focus @@ -885,22 +884,27 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED); } - // we send selection events only from AdapterView to avoid - // generation of such event for each child + // We first get a chance to populate the event. + onPopulateAccessibilityEvent(event); + + // We send selection events only from AdapterView to avoid + // generation of such event for each child. View selectedView = getSelectedView(); if (selectedView != null) { - populated = selectedView.dispatchPopulateAccessibilityEvent(event); + return selectedView.dispatchPopulateAccessibilityEvent(event); } - if (!populated) { - if (selectedView != null) { - event.setEnabled(selectedView.isEnabled()); - } - event.setItemCount(getCount()); - event.setCurrentItemIndex(getSelectedItemPosition()); - } + return false; + } - return populated; + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + View selectedView = getSelectedView(); + if (selectedView != null) { + event.setEnabled(selectedView.isEnabled()); + } + event.setItemCount(getCount()); + event.setCurrentItemIndex(getSelectedItemPosition()); } @Override diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index bf63607..bd595a5 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -199,11 +199,8 @@ public class CheckedTextView extends TextView implements Checkable { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - boolean populated = super.dispatchPopulateAccessibilityEvent(event); - if (!populated) { - event.setChecked(mChecked); - } - return populated; + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + event.setChecked(mChecked); } } diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index 0df45cc..f050d41 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -208,22 +208,18 @@ public abstract class CompoundButton extends Button implements Checkable { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - boolean populated = super.dispatchPopulateAccessibilityEvent(event); - - if (!populated) { - int resourceId = 0; - if (mChecked) { - resourceId = R.string.accessibility_compound_button_selected; - } else { - resourceId = R.string.accessibility_compound_button_unselected; - } - String state = getResources().getString(resourceId); - event.getText().add(state); - event.setChecked(mChecked); + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + + int resourceId = 0; + if (mChecked) { + resourceId = R.string.accessibility_compound_button_selected; + } else { + resourceId = R.string.accessibility_compound_button_unselected; } - - return populated; + String state = getResources().getString(resourceId); + event.getText().add(state); + event.setChecked(mChecked); } @Override diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 7210e21..30fb927 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -353,13 +353,14 @@ public class DatePicker extends FrameLayout { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + + final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR; String selectedDateUtterance = DateUtils.formatDateTime(mContext, mCurrentDate.getTimeInMillis(), flags); event.getText().add(selectedDateUtterance); - return true; } /** diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index d76a956..5618dbe 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1998,36 +1998,32 @@ public class ListView extends AbsListView { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - boolean populated = super.dispatchPopulateAccessibilityEvent(event); + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); // If the item count is less than 15 then subtract disabled items from the count and // position. Otherwise ignore disabled items. - if (!populated) { - int itemCount = 0; - int currentItemIndex = getSelectedItemPosition(); - - ListAdapter adapter = getAdapter(); - if (adapter != null) { - final int count = adapter.getCount(); - if (count < 15) { - for (int i = 0; i < count; i++) { - if (adapter.isEnabled(i)) { - itemCount++; - } else if (i <= currentItemIndex) { - currentItemIndex--; - } + int itemCount = 0; + int currentItemIndex = getSelectedItemPosition(); + + ListAdapter adapter = getAdapter(); + if (adapter != null) { + final int count = adapter.getCount(); + if (count < 15) { + for (int i = 0; i < count; i++) { + if (adapter.isEnabled(i)) { + itemCount++; + } else if (i <= currentItemIndex) { + currentItemIndex--; } - } else { - itemCount = count; } + } else { + itemCount = count; } - - event.setItemCount(itemCount); - event.setCurrentItemIndex(currentItemIndex); } - return populated; + event.setItemCount(itemCount); + event.setCurrentItemIndex(currentItemIndex); } /** diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 8db34d9..96d41a0 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -1027,12 +1027,10 @@ public class ProgressBar extends View { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - if (!super.dispatchPopulateAccessibilityEvent(event)) { - event.setItemCount(mMax); - event.setCurrentItemIndex(mProgress); - } - return true; + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + event.setItemCount(mMax); + event.setCurrentItemIndex(mProgress); } /** diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 6f76dd0..31ec785 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -427,12 +427,19 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - event.setItemCount(getTabCount()); - event.setCurrentItemIndex(mSelectedTab); + onPopulateAccessibilityEvent(event); + // Dispatch only to the selected tab. if (mSelectedTab != -1) { - getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event); + return getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event); } - return true; + return false; + } + + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + event.setItemCount(getTabCount()); + event.setCurrentItemIndex(mSelectedTab); } /** diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 4a99e47..4d3aa68 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -81,8 +81,8 @@ import android.text.method.TextKeyListener; import android.text.method.TimeKeyListener; import android.text.method.TransformationMethod; import android.text.style.ClickableSpan; -import android.text.style.SuggestionSpan; import android.text.style.ParagraphStyle; +import android.text.style.SuggestionSpan; import android.text.style.URLSpan; import android.text.style.UpdateAppearance; import android.text.util.Linkify; @@ -7896,9 +7896,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { if (!isShown()) { - return false; + return; } final boolean isPassword = hasPasswordTransformationMethod(); @@ -7914,7 +7914,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { event.setPassword(isPassword); } - return false; } void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, @@ -8038,7 +8037,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case ID_SELECTION_MODE: if (mSelectionActionMode != null) { // Selection mode is already started, simply change selected part. - updateSelectedRegion(); + selectCurrentWord(); } else { startSelectionActionMode(); } @@ -8188,8 +8187,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0); stopSelectionActionMode(); } else { - // New selection at touch position - updateSelectedRegion(); + selectCurrentWord(); } handled = true; } @@ -8205,17 +8203,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return handled; } - /** - * When selection mode is already started, this method simply updates the selected part of text - * to the text under the finger. - */ - private void updateSelectedRegion() { - // Start a new selection at current position, keep selectionAction mode on - selectCurrentWord(); - // Updates handles' positions - getSelectionController().show(); - } - private boolean touchPositionIsInSelection() { int selectionStart = getSelectionStart(); int selectionEnd = getSelectionEnd(); @@ -8783,7 +8770,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private float mTouchOffsetY; // Where the touch position should be on the handle to ensure a maximum cursor visibility private float mIdealVerticalOffset; - // Parent's (TextView) position in window + // Parent's (TextView) previous position in window private int mLastParentX, mLastParentY; // PopupWindow container absolute position with respect to the enclosing window private int mContainerPositionX, mContainerPositionY; @@ -8857,12 +8844,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void show() { - updateContainerPosition(); if (isShowing()) { mContainer.update(mContainerPositionX, mContainerPositionY, mRight - mLeft, mBottom - mTop); - - hideAssociatedPopupWindow(); } else { mContainer.showAtLocation(TextView.this, 0, mContainerPositionX, mContainerPositionY); @@ -8877,7 +8861,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener protected void dismiss() { mIsDragging = false; mContainer.dismiss(); - hideAssociatedPopupWindow(); } public void hide() { @@ -8908,22 +8891,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int compoundPaddingLeft = getCompoundPaddingLeft(); final int compoundPaddingRight = getCompoundPaddingRight(); - final TextView hostView = TextView.this; + final TextView textView = TextView.this; if (mTempRect == null) mTempRect = new Rect(); final Rect clip = mTempRect; clip.left = compoundPaddingLeft; clip.top = extendedPaddingTop; - clip.right = hostView.getWidth() - compoundPaddingRight; - clip.bottom = hostView.getHeight() - extendedPaddingBottom; + clip.right = textView.getWidth() - compoundPaddingRight; + clip.bottom = textView.getHeight() - extendedPaddingBottom; - final ViewParent parent = hostView.getParent(); - if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) { + final ViewParent parent = textView.getParent(); + if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) { return false; } final int[] coords = mTempCoords; - hostView.getLocationInWindow(coords); + textView.getLocationInWindow(coords); final int posX = coords[0] + mPositionX + (int) mHotspotX; final int posY = coords[1] + mPositionY; @@ -8932,23 +8915,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener posY >= clip.top && posY <= clip.bottom; } - private void moveTo(int x, int y) { - mPositionX = x - TextView.this.mScrollX; - mPositionY = y - TextView.this.mScrollY; - - if (mIsDragging) { - TextView.this.getLocationInWindow(mTempCoords); - if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) { - mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX; - mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY; - mLastParentX = mTempCoords[0]; - mLastParentY = mTempCoords[1]; - } - - hideAssociatedPopupWindow(); - } - } - public abstract int getCurrentCursorOffset(); public abstract void updateOffset(int offset); @@ -8957,44 +8923,44 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener protected void positionAtCursorOffset(int offset) { addPositionToTouchUpFilter(offset); - final int width = mDrawable.getIntrinsicWidth(); - final int height = mDrawable.getIntrinsicHeight(); final int line = mLayout.getLineForOffset(offset); final int lineBottom = mLayout.getLineBottom(line); - final Rect bounds = sCursorControllerTempRect; - bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) + - TextView.this.mScrollX; - bounds.top = lineBottom + TextView.this.mScrollY; - - bounds.right = bounds.left + width; - bounds.bottom = bounds.top + height; + mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX); + mPositionY = lineBottom; - convertFromViewportToContentCoordinates(bounds); - moveTo(bounds.left, bounds.top); + // Take TextView's padding into account. + mPositionX += viewportToContentHorizontalOffset(); + mPositionY += viewportToContentVerticalOffset(); } - /** - * Updates the global container's position. - * @return whether or not the position has actually changed - */ - private boolean updateContainerPosition() { + protected boolean updateContainerPosition() { positionAtCursorOffset(getCurrentCursorOffset()); + + final int previousContainerPositionX = mContainerPositionX; + final int previousContainerPositionY = mContainerPositionY; + TextView.this.getLocationInWindow(mTempCoords); - final int containerPositionX = mTempCoords[0] + mPositionX; - final int containerPositionY = mTempCoords[1] + mPositionY; + mContainerPositionX = mTempCoords[0] + mPositionX; + mContainerPositionY = mTempCoords[1] + mPositionY; - if (containerPositionX != mContainerPositionX || - containerPositionY != mContainerPositionY) { - mContainerPositionX = containerPositionX; - mContainerPositionY = containerPositionY; - return true; - } - return false; + return (previousContainerPositionX != mContainerPositionX || + previousContainerPositionY != mContainerPositionY); } public boolean onPreDraw() { if (updateContainerPosition()) { + if (mIsDragging) { + if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) { + mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX; + mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY; + mLastParentX = mTempCoords[0]; + mLastParentY = mTempCoords[1]; + } + } + + onHandleMoved(); + if (isPositionVisible()) { mContainer.update(mContainerPositionX, mContainerPositionY, mRight - mLeft, mBottom - mTop); @@ -9007,9 +8973,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener dismiss(); } } - - // Hide paste popup as soon as the view is scrolled or moved - hideAssociatedPopupWindow(); } return true; } @@ -9076,8 +9039,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mIsDragging; } - void hideAssociatedPopupWindow() { - // No associated popup window by default + void onHandleMoved() { + // Does nothing by default } public void onDetached() { @@ -9096,15 +9059,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Runnable mHider; private Runnable mPastePopupShower; - public InsertionHandleView() { - super(); - } - @Override public void show() { super.show(); hideDelayed(); - removePastePopupCallback(); + hidePastePopupWindow(); } public void show(int delayBeforePaste) { @@ -9118,11 +9077,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mPastePopupShower == null) { mPastePopupShower = new Runnable() { public void run() { - showAssociatedPopupWindow(); + showPastePopupWindow(); } }; } - postDelayed(mPastePopupShower, delayBeforePaste); + TextView.this.postDelayed(mPastePopupShower, delayBeforePaste); } } @@ -9132,11 +9091,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener onDetached(); } - @Override - public void hide() { - super.hide(); - } - private void hideDelayed() { removeHiderCallback(); if (mHider == null) { @@ -9146,18 +9100,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } }; } - postDelayed(mHider, DELAY_BEFORE_FADE_OUT); - } - - private void removePastePopupCallback() { - if (mPastePopupShower != null) { - removeCallbacks(mPastePopupShower); - } + TextView.this.postDelayed(mHider, DELAY_BEFORE_FADE_OUT); } private void removeHiderCallback() { if (mHider != null) { - removeCallbacks(mHider); + TextView.this.removeCallbacks(mHider); } } @@ -9197,6 +9145,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } } + hideDelayed(); + break; + + case MotionEvent.ACTION_CANCEL: + hideDelayed(); break; default: @@ -9214,31 +9167,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void updateOffset(int offset) { Selection.setSelection((Spannable) mText, offset); - positionAtCursorOffset(offset); } @Override public void updatePosition(int x, int y) { - final int previousOffset = getCurrentCursorOffset(); - final int newOffset = getOffset(x, y); - - if (newOffset != previousOffset) { - updateOffset(newOffset); - removePastePopupCallback(); - } - hideDelayed(); + updateOffset(getOffset(x, y)); } - void showAssociatedPopupWindow() { + void showPastePopupWindow() { if (mPastePopupWindow == null) { - // Lazy initialisation: create when actually shown only. mPastePopupWindow = new PastePopupWindow(); } mPastePopupWindow.show(); } @Override - void hideAssociatedPopupWindow() { + void onHandleMoved() { + removeHiderCallback(); + hidePastePopupWindow(); + } + + void hidePastePopupWindow() { + if (mPastePopupShower != null) { + TextView.this.removeCallbacks(mPastePopupShower); + } if (mPastePopupWindow != null) { mPastePopupWindow.hide(); } @@ -9247,15 +9199,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void onDetached() { removeHiderCallback(); - removePastePopupCallback(); + hidePastePopupWindow(); } } private class SelectionStartHandleView extends HandleView { - public SelectionStartHandleView() { - super(); - } - @Override protected void initDrawable() { if (mSelectHandleLeft == null) { @@ -9274,7 +9222,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void updateOffset(int offset) { Selection.setSelection((Spannable) mText, offset, getSelectionEnd()); - positionAtCursorOffset(offset); } @Override @@ -9290,15 +9237,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (offset >= selectionEnd) offset = selectionEnd - 1; Selection.setSelection((Spannable) mText, offset, selectionEnd); - positionAtCursorOffset(offset); } } private class SelectionEndHandleView extends HandleView { - public SelectionEndHandleView() { - super(); - } - @Override protected void initDrawable() { if (mSelectHandleRight == null) { @@ -9317,7 +9259,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void updateOffset(int offset) { Selection.setSelection((Spannable) mText, getSelectionStart(), offset); - positionAtCursorOffset(offset); } @Override @@ -9333,7 +9274,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (offset <= selectionStart) offset = selectionStart + 1; Selection.setSelection((Spannable) mText, selectionStart, offset); - positionAtCursorOffset(offset); } } diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 029d690..423e735 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -409,7 +409,9 @@ public class TimePicker extends FrameLayout { } @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + int flags = DateUtils.FORMAT_SHOW_TIME; if (mIs24HourView) { flags |= DateUtils.FORMAT_24HOUR; @@ -421,7 +423,6 @@ public class TimePicker extends FrameLayout { String selectedDateUtterance = DateUtils.formatDateTime(mContext, mTempCalendar.getTimeInMillis(), flags); event.getText().add(selectedDateUtterance); - return true; } private void updateHourControl() { diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 16d5539..9652085 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -861,7 +861,7 @@ public class ActionBarImpl extends ActionBar { @Override public void setIcon(int resId) { - mActionView.setIcon(mContext.getResources().getDrawable(resId)); + mActionView.setIcon(resId); } @Override @@ -871,7 +871,7 @@ public class ActionBarImpl extends ActionBar { @Override public void setLogo(int resId) { - mActionView.setLogo(mContext.getResources().getDrawable(resId)); + mActionView.setLogo(resId); } @Override diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java index 71511c6..16f51fd 100644 --- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java @@ -104,6 +104,10 @@ public abstract class BaseMenuPresenter implements MenuPresenter { * @param childIndex Index within the parent to insert at */ protected void addItemView(View itemView, int childIndex) { + final ViewGroup currentParent = (ViewGroup) itemView.getParent(); + if (currentParent != null) { + currentParent.removeView(itemView); + } ((ViewGroup) mMenuView).addView(itemView, childIndex); } diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 42ef916..c6d386d 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -523,7 +523,9 @@ public final class MenuItemImpl implements MenuItem { } public boolean showsTextAsAction() { - return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT; + return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT && + mMenu.getContext().getResources().getBoolean( + com.android.internal.R.bool.allow_action_menu_item_text_with_icon); } public void setShowAsAction(int actionEnum) { diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 74a6ae7..fa8eb51 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -30,11 +30,13 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.Log; import android.view.ActionMode; import android.view.Gravity; @@ -85,7 +87,6 @@ public class ActionBarView extends ViewGroup { private CharSequence mSubtitle; private Drawable mIcon; private Drawable mLogo; - private Drawable mDivider; private View mHomeLayout; private View mHomeAsUpView; @@ -211,8 +212,6 @@ public class ActionBarView extends ViewGroup { mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0); - mDivider = a.getDrawable(R.styleable.ActionBar_divider); - a.recycle(); mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle); @@ -434,6 +433,10 @@ public class ActionBarView extends ViewGroup { } } + public void setIcon(int resId) { + setIcon(mContext.getResources().getDrawableForDensity(resId, getPreferredIconDensity())); + } + public void setLogo(Drawable logo) { mLogo = logo; if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) { @@ -441,6 +444,29 @@ public class ActionBarView extends ViewGroup { } } + public void setLogo(int resId) { + mContext.getResources().getDrawable(resId); + } + + /** + * @return Drawable density to load that will best fit the available height. + */ + private int getPreferredIconDensity() { + final Resources res = mContext.getResources(); + final int availableHeight = getLayoutParams().height - + mIconView.getPaddingTop() - mIconView.getPaddingBottom(); + int iconSize = res.getDimensionPixelSize(android.R.dimen.app_icon_size); + + if (iconSize * DisplayMetrics.DENSITY_LOW >= availableHeight) { + return DisplayMetrics.DENSITY_LOW; + } else if (iconSize * DisplayMetrics.DENSITY_MEDIUM >= availableHeight) { + return DisplayMetrics.DENSITY_MEDIUM; + } else if (iconSize * DisplayMetrics.DENSITY_HIGH >= availableHeight) { + return DisplayMetrics.DENSITY_HIGH; + } + return DisplayMetrics.DENSITY_XHIGH; + } + public void setNavigationMode(int mode) { final int oldMode = mNavigationMode; if (mode != oldMode) { diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index f172913..ec8b6e0 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -204,7 +204,7 @@ static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface) static void Surface_init( JNIEnv* env, jobject clazz, jobject session, - jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags) + jint, jstring jname, jint dpy, jint w, jint h, jint format, jint flags) { if (session == NULL) { doThrowNPE(env); @@ -216,12 +216,12 @@ static void Surface_init( sp<SurfaceControl> surface; if (jname == NULL) { - surface = client->createSurface(pid, dpy, w, h, format, flags); + surface = client->createSurface(dpy, w, h, format, flags); } else { const jchar* str = env->GetStringCritical(jname, 0); const String8 name(str, env->GetStringLength(jname)); env->ReleaseStringCritical(jname, str); - surface = client->createSurface(pid, name, dpy, w, h, format, flags); + surface = client->createSurface(name, dpy, w, h, format, flags); } if (surface == 0) { diff --git a/core/res/res/layout-large/action_bar_home.xml b/core/res/res/layout-large/action_bar_home.xml new file mode 100644 index 0000000..86580bc --- /dev/null +++ b/core/res/res/layout-large/action_bar_home.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<view xmlns:android="http://schemas.android.com/apk/res/android" + class="com.android.internal.widget.ActionBarView$HomeView" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" > + <ImageView android:id="@android:id/up" + android:src="?android:attr/homeAsUpIndicator" + android:layout_gravity="center_vertical|left" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="-12dip" /> + <ImageView android:id="@android:id/home" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="16dip" + android:paddingRight="16dip" + android:paddingTop="4dip" + android:paddingBottom="4dip" + android:adjustViewBounds="true" + android:layout_gravity="center" + android:scaleType="fitCenter" /> +</view> diff --git a/core/res/res/layout-large/action_mode_close_item.xml b/core/res/res/layout-large/action_mode_close_item.xml new file mode 100644 index 0000000..321622e --- /dev/null +++ b/core/res/res/layout-large/action_mode_close_item.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/action_mode_close_button" + android:background="@drawable/btn_cab_done" + android:focusable="true" + android:clickable="true" + android:paddingLeft="16dip" + android:layout_width="wrap_content" + android:layout_height="match_parent"> + <ImageView android:layout_width="48dip" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:scaleType="center" + android:src="@drawable/ic_cab_close_holo" /> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginLeft="8dip" + android:layout_marginRight="16dip" + android:textAppearance="@android:style/TextAppearance.Holo.Medium" + android:textColor="@android:color/white" + android:text="@string/action_mode_done" /> +</LinearLayout> diff --git a/core/res/res/layout/action_bar_home.xml b/core/res/res/layout/action_bar_home.xml index c82f91d..7f7c55c 100644 --- a/core/res/res/layout/action_bar_home.xml +++ b/core/res/res/layout/action_bar_home.xml @@ -25,12 +25,15 @@ android:visibility="gone" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="-12dip" /> + android:layout_marginRight="-4dip" /> <ImageView android:id="@android:id/home" android:layout_width="wrap_content" - android:layout_height="match_parent" - android:paddingLeft="16dip" - android:paddingRight="16dip" + android:layout_height="wrap_content" + android:paddingLeft="8dip" + android:paddingRight="8dip" + android:paddingTop="@dimen/action_bar_icon_vertical_padding" + android:paddingBottom="@dimen/action_bar_icon_vertical_padding" android:layout_gravity="center" - android:scaleType="center" /> + android:adjustViewBounds="true" + android:scaleType="fitCenter" /> </view> diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml index 4a73368..5e828fa 100644 --- a/core/res/res/layout/action_menu_item_layout.xml +++ b/core/res/res/layout/action_menu_item_layout.xml @@ -31,10 +31,9 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" - android:paddingLeft="4dip" - android:paddingRight="4dip" - android:minHeight="56dip" - android:scaleType="center" + android:padding="@dimen/action_bar_icon_vertical_padding" + android:scaleType="fitCenter" + android:adjustViewBounds="true" android:background="@null" android:focusable="false" /> <Button android:id="@+id/textButton" @@ -46,7 +45,6 @@ style="?attr/buttonStyleSmall" android:textColor="?attr/actionMenuTextColor" android:background="@null" - android:paddingLeft="4dip" - android:paddingRight="4dip" + android:padding="4dip" android:focusable="false" /> </com.android.internal.view.menu.ActionMenuItemView> diff --git a/core/res/res/layout/action_mode_close_item.xml b/core/res/res/layout/action_mode_close_item.xml index 7badbac..2a4d8e0 100644 --- a/core/res/res/layout/action_mode_close_item.xml +++ b/core/res/res/layout/action_mode_close_item.xml @@ -19,20 +19,12 @@ android:background="@drawable/btn_cab_done" android:focusable="true" android:clickable="true" - android:paddingLeft="16dip" + android:paddingLeft="8dip" android:layout_width="wrap_content" android:layout_height="match_parent"> - <ImageView android:layout_width="48dip" + <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:scaleType="center" + android:scaleType="fitCenter" android:src="@drawable/ic_cab_close_holo" /> - <TextView android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:layout_marginLeft="8dip" - android:layout_marginRight="16dip" - android:textAppearance="@android:style/TextAppearance.Holo.Medium" - android:textColor="@android:color/white" - android:text="@string/action_mode_done" /> </LinearLayout> diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml index 058daa8..8def578e 100644 --- a/core/res/res/values-land/dimens.xml +++ b/core/res/res/values-land/dimens.xml @@ -28,4 +28,8 @@ <dimen name="preference_screen_side_margin">96dp</dimen> <dimen name="preference_screen_side_margin_negative">-100dp</dimen> <dimen name="preference_widget_width">72dp</dimen> + + <!-- Default height of an action bar. --> + <dimen name="action_bar_default_height">40dip</dimen> + </resources> diff --git a/core/res/res/values-large/dimens.xml b/core/res/res/values-large/dimens.xml index cd1847f..5355847 100644 --- a/core/res/res/values-large/dimens.xml +++ b/core/res/res/values-large/dimens.xml @@ -22,4 +22,10 @@ <!-- Preference UI dimensions for larger screens. --> <dimen name="preference_widget_width">56dp</dimen> + <!-- The maximum number of action buttons that should be permitted within + an action bar/action mode. This will be used to determine how many + showAsAction="ifRoom" items can fit. "always" items can override this. --> + <integer name="max_action_buttons">5</integer> + <!-- Default height of an action bar. --> + <dimen name="action_bar_default_height">56dip</dimen> </resources> diff --git a/core/res/res/values-port/dimens.xml b/core/res/res/values-port/dimens.xml new file mode 100644 index 0000000..bf0a342 --- /dev/null +++ b/core/res/res/values-port/dimens.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources> + <!-- The maximum number of action buttons that should be permitted within + an action bar/action mode. This will be used to determine how many + showAsAction="ifRoom" items can fit. "always" items can override this. --> + <integer name="max_action_buttons">2</integer> +</resources> diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml new file mode 100644 index 0000000..ea7eeb5 --- /dev/null +++ b/core/res/res/values-w480dp/bools.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources> + <bool name="allow_action_menu_item_text_with_icon">true</bool> +</resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 33825c7..05a4810 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -68,7 +68,7 @@ <string name="serviceNotProvisioned" msgid="8614830180508686666">"無法提供此服務。"</string> <string name="CLIRPermanent" msgid="5460892159398802465">"本機號碼顯示設定無法變更。"</string> <string name="RestrictedChangedTitle" msgid="5592189398956187498">"受限存取已變更"</string> - <string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖資料傳輸服務。"</string> + <string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖數據傳輸服務。"</string> <string name="RestrictedOnEmergency" msgid="6581163779072833665">"已封鎖緊急服務。"</string> <string name="RestrictedOnNormal" msgid="4953867011389750673">"已封鎖語音服務。"</string> <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"已封鎖所有語音服務。"</string> @@ -700,15 +700,15 @@ <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string> <plurals name="num_seconds_ago"> <item quantity="one" msgid="4869870056547896011">"1 秒以前"</item> - <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item> + <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item> </plurals> <plurals name="num_minutes_ago"> <item quantity="one" msgid="3306787433088810191">"1 分鐘以前"</item> - <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item> + <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item> </plurals> <plurals name="num_hours_ago"> <item quantity="one" msgid="9150797944610821849">"1 小時以前"</item> - <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item> + <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item> </plurals> <plurals name="last_num_days"> <item quantity="other" msgid="3069992808164318268">"最近 <xliff:g id="COUNT">%d</xliff:g> 天"</item> @@ -717,7 +717,7 @@ <string name="older" msgid="5211975022815554840">"較舊"</string> <plurals name="num_days_ago"> <item quantity="one" msgid="861358534398115820">"昨天"</item> - <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item> + <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item> </plurals> <plurals name="in_num_seconds"> <item quantity="one" msgid="2729745560954905102">"1 秒內"</item> @@ -745,11 +745,11 @@ </plurals> <plurals name="abbrev_num_hours_ago"> <item quantity="one" msgid="4796212039724722116">"1 小時以前"</item> - <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item> + <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item> </plurals> <plurals name="abbrev_num_days_ago"> <item quantity="one" msgid="8463161711492680309">"昨天"</item> - <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item> + <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item> </plurals> <plurals name="abbrev_in_num_seconds"> <item quantity="one" msgid="5842225370795066299">"1 秒內"</item> @@ -922,14 +922,14 @@ <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"USB 儲存裝置已毀損"</string> <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"SD 卡已損壞"</string> <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB 儲存裝置已損壞,您可能必須重新格式化。"</string> - <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD 卡已毀損,您可能必須予以重新格式化。"</string> - <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB 儲存裝置已意外移除"</string> + <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD 卡已毀損,您可能必須重新格式化。"</string> + <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB 儲存裝置未正常移除"</string> <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD 卡未正常移除"</string> <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"請先卸載 USB 儲存裝置,再將其移除,以免資料遺失。"</string> <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"請先卸載 SD 卡,再將其移除,以免資料遺失。"</string> <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB 儲存裝置已可安全移除"</string> <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"可安全移除 SD 卡"</string> - <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"您可安全移除 USB 儲存裝置了。"</string> + <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"您現在可以安全地移除 USB 儲存裝置。"</string> <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"您現在可以安全地移除 SD 卡。"</string> <string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"USB 儲存裝置已移除"</string> <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"已移除 SD 卡"</string> diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml new file mode 100644 index 0000000..c7dcb51 --- /dev/null +++ b/core/res/res/values/bools.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources> + <bool name="allow_action_menu_item_text_with_icon">false</bool> +</resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index da1c157..a1511b3 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -28,7 +28,7 @@ <!-- The maximum number of action buttons that should be permitted within an action bar/action mode. This will be used to determine how many showAsAction="ifRoom" items can fit. "always" items can override this. --> - <integer name="max_action_buttons">5</integer> + <integer name="max_action_buttons">3</integer> <dimen name="toast_y_offset">64dip</dimen> <!-- Height of the status bar --> <dimen name="status_bar_height">25dip</dimen> @@ -79,4 +79,9 @@ <!-- Minimum width of the search view text entry area. --> <dimen name="search_view_text_min_width">160dip</dimen> + + <!-- Default height of an action bar. --> + <dimen name="action_bar_default_height">48dip</dimen> + <!-- Vertical padding around action bar icons. --> + <dimen name="action_bar_icon_vertical_padding">4dip</dimen> </resources> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index b9fd6a5..be7b42f 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -276,7 +276,7 @@ <item name="actionModeStyle">@style/Widget.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.ActionBar</item> - <item name="actionBarSize">56dip</item> + <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">?android:attr/popupWindowStyle</item> <item name="actionMenuTextAppearance">?android:attr/textAppearanceMedium</item> <item name="actionMenuTextColor">?android:attr/textColorPrimary</item> @@ -1009,7 +1009,7 @@ <item name="actionModeStyle">@style/Widget.Holo.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.Holo.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.Holo.ActionBar</item> - <item name="actionBarSize">56dip</item> + <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.PopupWindow.ActionMode</item> <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item> @@ -1294,7 +1294,7 @@ <item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.Holo.Light.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.Holo.Light.ActionBar</item> - <item name="actionBarSize">56dip</item> + <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item> <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item> diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd index f88c3a6..a81be20 100644 --- a/docs/html/sdk/android-3.0.jd +++ b/docs/html/sdk/android-3.0.jd @@ -311,7 +311,7 @@ app widget looks like and is shown to the user from the widget picker. If this f supplied, the app widget's icon is used for the preview.</p> <p>To help create a preview image for your app widget (to specify in the {@link -android.appwidget.AppWidgetProviderInfo#autoAdvanceViewId} field), the Android emulator includes an +android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android emulator includes an application called "Widget Preview." To create a preview image, launch this application, select the app widget for your application and set it up how you'd like your preview image to appear, then save it and place it in your application's drawable resources.</p> diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h index a1e9e04..46b1bb7 100644 --- a/include/surfaceflinger/ISurfaceComposerClient.h +++ b/include/surfaceflinger/ISurfaceComposerClient.h @@ -64,7 +64,6 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual sp<ISurface> createSurface( surface_data_t* data, - int pid, const String8& name, DisplayID display, uint32_t w, diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 25b2ebf..c61a5bf 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -79,7 +79,6 @@ public: //! Create a surface sp<SurfaceControl> createSurface( - int pid, // pid of the process the surface is for const String8& name,// name of the surface DisplayID display, // Display to create this surface on uint32_t w, // width in pixel @@ -89,7 +88,6 @@ public: ); sp<SurfaceControl> createSurface( - int pid, // pid of the process the surface is for DisplayID display, // Display to create this surface on uint32_t w, // width in pixel uint32_t h, // height in pixel diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl new file mode 100644 index 0000000..64f5a48 --- /dev/null +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.security; + +import android.os.Bundle; + +/** + * Caller is required to ensure that {@link KeyStore#unlock + * KeyStore.unlock} was successful. + * + * @hide + */ +interface IKeyChainService { + byte[] getPrivate(String alias, String authToken); + byte[] getCertificate(String alias, String authToken); + byte[] getCaCertificate(String alias, String authToken); + String findIssuer(in Bundle cert); +} diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java new file mode 100644 index 0000000..69847bf --- /dev/null +++ b/keystore/java/android/security/KeyChain.java @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.security; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; +import dalvik.system.CloseGuard; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.CertPathValidatorException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters; +import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl; + +/** + * @hide + */ +public final class KeyChain { + + private static final String TAG = "KeyChain"; + + /** + * @hide Also used by KeyChainService implementation + */ + public static final String ACCOUNT_TYPE = "com.android.keychain"; + + /** + * @hide Also used by KeyChainService implementation + */ + // TODO This non-localized CA string to be removed when CAs moved out of keystore + public static final String CA_SUFFIX = " CA"; + + public static final String KEY_INTENT = "intent"; + + /** + * Intentionally not public to leave open the future possibility + * of hardware based keys. Callers should use {@link #toPrivateKey + * toPrivateKey} in order to convert a bundle to a {@code + * PrivateKey} + */ + private static final String KEY_PKCS8 = "pkcs8"; + + /** + * Intentionally not public to leave open the future possibility + * of hardware based certs. Callers should use {@link + * #toCertificate toCertificate} in order to convert a bundle to a + * {@code PrivateKey} + */ + private static final String KEY_X509 = "x509"; + + /** + * Returns an {@code Intent} for use with {@link + * android.app.Activity#startActivityForResult + * startActivityForResult}. The result will be returned via {@link + * android.app.Activity#onActivityResult onActivityResult} with + * {@link android.app.Activity#RESULT_OK RESULT_OK} and the alias + * in the returned {@code Intent}'s extra data with key {@link + * android.content.Intent#EXTRA_TEXT Intent.EXTRA_TEXT}. + */ + public static Intent chooseAlias() { + return new Intent("com.android.keychain.CHOOSER"); + } + + /** + * Returns a new {@code KeyChain} instance. When the caller is + * done using the {@code KeyChain}, it must be closed with {@link + * #close()} or resource leaks will occur. + */ + public static KeyChain getInstance(Context context) throws InterruptedException { + return new KeyChain(context); + } + + private final AccountManager mAccountManager; + + private final Object mServiceLock = new Object(); + private IKeyChainService mService; + private boolean mIsBound; + + private Account mAccount; + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @Override public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mServiceLock) { + mService = IKeyChainService.Stub.asInterface(service); + mServiceLock.notifyAll(); + + // Account is created if necessary during binding of the IKeyChainService + mAccount = mAccountManager.getAccountsByType(ACCOUNT_TYPE)[0]; + } + } + + @Override public void onServiceDisconnected(ComponentName name) { + synchronized (mServiceLock) { + mService = null; + } + } + }; + + private final Context mContext; + + private final CloseGuard mGuard = CloseGuard.get(); + + private KeyChain(Context context) throws InterruptedException { + if (context == null) { + throw new NullPointerException("context == null"); + } + mContext = context; + ensureNotOnMainThread(); + mAccountManager = AccountManager.get(mContext); + mIsBound = mContext.bindService(new Intent(IKeyChainService.class.getName()), + mServiceConnection, + Context.BIND_AUTO_CREATE); + if (!mIsBound) { + throw new AssertionError(); + } + synchronized (mServiceLock) { + // there is a race between binding on this thread and the + // callback on the main thread. wait until binding is done + // to be sure we have the mAccount initialized. + if (mService == null) { + mServiceLock.wait(); + } + } + mGuard.open("close"); + } + + /** + * {@code Bundle} will contain {@link #KEY_INTENT} if user needs + * to confirm application access to requested key. In the alias + * does not exist or there is an error, null is + * returned. Otherwise the {@code Bundle} contains information + * representing the private key which can be interpreted with + * {@link #toPrivateKey toPrivateKey}. + * + * non-null alias + */ + public Bundle getPrivate(String alias) { + return get(alias, Credentials.USER_PRIVATE_KEY); + } + + public Bundle getCertificate(String alias) { + return get(alias, Credentials.USER_CERTIFICATE); + } + + public Bundle getCaCertificate(String alias) { + return get(alias, Credentials.CA_CERTIFICATE); + } + + private Bundle get(String alias, String type) { + if (alias == null) { + throw new NullPointerException("alias == null"); + } + ensureNotOnMainThread(); + + String authAlias = (type.equals(Credentials.CA_CERTIFICATE)) ? (alias + CA_SUFFIX) : alias; + AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount, + authAlias, + false, + null, + null); + Bundle bundle; + try { + bundle = future.getResult(); + } catch (OperationCanceledException e) { + throw new AssertionError(e); + } catch (IOException e) { + throw new AssertionError(e); + } catch (AuthenticatorException e) { + throw new AssertionError(e); + } + Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT); + if (intent != null) { + Bundle result = new Bundle(); + // we don't want this Eclair compatability flag, + // it will prevent onActivityResult from being called + intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); + result.putParcelable(KEY_INTENT, intent); + return result; + } + String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN); + if (authToken == null) { + throw new AssertionError("Invalid authtoken"); + } + + byte[] bytes; + try { + if (type.equals(Credentials.USER_PRIVATE_KEY)) { + bytes = mService.getPrivate(alias, authToken); + } else if (type.equals(Credentials.USER_CERTIFICATE)) { + bytes = mService.getCertificate(alias, authToken); + } else if (type.equals(Credentials.CA_CERTIFICATE)) { + bytes = mService.getCaCertificate(alias, authToken); + } else { + throw new AssertionError(); + } + } catch (RemoteException e) { + throw new AssertionError(e); + } + if (bytes == null) { + throw new AssertionError(); + } + Bundle result = new Bundle(); + if (type.equals(Credentials.USER_PRIVATE_KEY)) { + result.putByteArray(KEY_PKCS8, bytes); + } else if (type.equals(Credentials.USER_CERTIFICATE)) { + result.putByteArray(KEY_X509, bytes); + } else if (type.equals(Credentials.CA_CERTIFICATE)) { + result.putByteArray(KEY_X509, bytes); + } else { + throw new AssertionError(); + } + return result; + } + + public static PrivateKey toPrivateKey(Bundle bundle) { + byte[] bytes = bundle.getByteArray(KEY_PKCS8); + if (bytes == null) { + throw new IllegalArgumentException("not a private key bundle"); + } + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes)); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } catch (InvalidKeySpecException e) { + throw new AssertionError(e); + } + } + + public static Bundle fromPrivateKey(PrivateKey privateKey) { + Bundle bundle = new Bundle(); + String format = privateKey.getFormat(); + if (!format.equals("PKCS#8")) { + throw new IllegalArgumentException("Unsupported private key format " + format); + } + bundle.putByteArray(KEY_PKCS8, privateKey.getEncoded()); + return bundle; + } + + public static X509Certificate toCertificate(Bundle bundle) { + byte[] bytes = bundle.getByteArray(KEY_X509); + if (bytes == null) { + throw new IllegalArgumentException("not a certificate bundle"); + } + try { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes)); + return (X509Certificate) cert; + } catch (CertificateException e) { + throw new AssertionError(e); + } + } + + public static Bundle fromCertificate(Certificate cert) { + Bundle bundle = new Bundle(); + String type = cert.getType(); + if (!type.equals("X.509")) { + throw new IllegalArgumentException("Unsupported certificate type " + type); + } + try { + bundle.putByteArray(KEY_X509, cert.getEncoded()); + } catch (CertificateEncodingException e) { + throw new AssertionError(e); + } + return bundle; + } + + private void ensureNotOnMainThread() { + Looper looper = Looper.myLooper(); + if (looper != null && looper == mContext.getMainLooper()) { + throw new IllegalStateException( + "calling this from your main thread can lead to deadlock"); + } + } + + public Bundle findIssuer(X509Certificate cert) { + if (cert == null) { + throw new NullPointerException("cert == null"); + } + ensureNotOnMainThread(); + + // check and see if the issuer is already known to the default IndexedPKIXParameters + IndexedPKIXParameters index = SSLParametersImpl.getDefaultIndexedPKIXParameters(); + try { + TrustAnchor anchor = index.findTrustAnchor(cert); + if (anchor != null && anchor.getTrustedCert() != null) { + X509Certificate ca = anchor.getTrustedCert(); + return fromCertificate(ca); + } + } catch (CertPathValidatorException ignored) { + } + + // otherwise, it might be a user installed CA in the keystore + String alias; + try { + alias = mService.findIssuer(fromCertificate(cert)); + } catch (RemoteException e) { + throw new AssertionError(e); + } + if (alias == null) { + Log.w(TAG, "Lookup failed for issuer"); + return null; + } + + Bundle bundle = get(alias, Credentials.CA_CERTIFICATE); + Intent intent = bundle.getParcelable(KEY_INTENT); + if (intent != null) { + // permission still required + return bundle; + } + // add the found CA to the index for next time + X509Certificate ca = toCertificate(bundle); + index.index(new TrustAnchor(ca, null)); + return bundle; + } + + public void close() { + if (mIsBound) { + mContext.unbindService(mServiceConnection); + mIsBound = false; + mGuard.close(); + } + } + + protected void finalize() throws Throwable { + // note we don't close, we just warn. + // shouldn't be doing I/O in a finalizer, + // which the unbind would cause. + try { + if (mGuard != null) { + mGuard.warnIfOpen(); + } + } finally { + super.finalize(); + } + } +} diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 7730eb1..ea38e08 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -83,7 +83,6 @@ public: } virtual sp<ISurface> createSurface( surface_data_t* params, - int pid, const String8& name, DisplayID display, uint32_t w, @@ -93,7 +92,6 @@ public: { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeInt32(pid); data.writeString8(name); data.writeInt32(display); data.writeInt32(w); @@ -172,14 +170,13 @@ status_t BnSurfaceComposerClient::onTransact( case CREATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); surface_data_t params; - int32_t pid = data.readInt32(); String8 name = data.readString8(); DisplayID display = data.readInt32(); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t flags = data.readInt32(); - sp<ISurface> s = createSurface(¶ms, pid, name, display, w, h, + sp<ISurface> s = createSurface(¶ms, name, display, w, h, format, flags); params.writeToParcel(reply); reply->writeStrongBinder(s->asBinder()); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d336724..a1ff2c1 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -273,7 +273,6 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays() } sp<SurfaceControl> SurfaceComposerClient::createSurface( - int pid, DisplayID display, uint32_t w, uint32_t h, @@ -286,12 +285,11 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( snprintf(buffer, SIZE, "<pid_%d>", getpid()); name.append(buffer); - return SurfaceComposerClient::createSurface(pid, name, display, + return SurfaceComposerClient::createSurface(name, display, w, h, format, flags); } sp<SurfaceControl> SurfaceComposerClient::createSurface( - int pid, const String8& name, DisplayID display, uint32_t w, @@ -302,7 +300,7 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( sp<SurfaceControl> result; if (mStatus == NO_ERROR) { ISurfaceComposerClient::surface_data_t data; - sp<ISurface> surface = mClient->createSurface(&data, pid, name, + sp<ISurface> surface = mClient->createSurface(&data, name, display, w, h, format, flags); if (surface != 0) { result = new SurfaceControl(this, surface, data, w, h, format, flags); diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp index bd1fd0e..093e311 100644 --- a/libs/rs/driver/rsdRuntimeMath.cpp +++ b/libs/rs/driver/rsdRuntimeMath.cpp @@ -243,13 +243,15 @@ static void SC_MatrixTranspose_2x2(Matrix2x2 *m) { static float SC_randf(float max) { float r = (float)rand(); r *= max; - return r / RAND_MAX; + r /= RAND_MAX; + return r; } static float SC_randf2(float min, float max) { float r = (float)rand(); + r /= RAND_MAX; r = r * (max - min) + min; - return r / RAND_MAX; + return r; } static int SC_randi(int max) { diff --git a/media/jni/mediaeditor/VideoBrowserInternal.h b/media/jni/mediaeditor/VideoBrowserInternal.h index ed63129..3cfb6b9 100755 --- a/media/jni/mediaeditor/VideoBrowserInternal.h +++ b/media/jni/mediaeditor/VideoBrowserInternal.h @@ -67,7 +67,7 @@ { \ if (M4OSA_NULL != p) \ { \ - M4OSA_free((M4OSA_MemAddr32)p) ; \ + free(p) ; \ p = M4OSA_NULL ; \ } \ } diff --git a/media/jni/mediaeditor/VideoBrowserMain.c b/media/jni/mediaeditor/VideoBrowserMain.c index cddab60..6ef688d 100755 --- a/media/jni/mediaeditor/VideoBrowserMain.c +++ b/media/jni/mediaeditor/VideoBrowserMain.c @@ -73,7 +73,7 @@ M4OSA_ERR videoBrowserSetWindow( if (pC->m_frameColorType == VideoBrowser_kGB565) { pC->m_outputPlane[0].u_stride = pC->m_outputPlane[0].u_width << 1; - pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)M4OSA_malloc( + pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( pC->m_outputPlane[0].u_stride * pC->m_outputPlane[0].u_height, VIDEOBROWSER, (M4OSA_Char *)"output plane"); @@ -154,7 +154,7 @@ M4OSA_ERR videoBrowserCreate( CHECK_PTR(videoBrowserCreate, pURL, err, M4ERR_PARAMETER); /*--- Create context ---*/ - pContext = (VideoBrowserContext*)M4OSA_malloc( + pContext = (VideoBrowserContext*)M4OSA_32bitAlignedMalloc( sizeof(VideoBrowserContext), VIDEOBROWSER, (M4OSA_Char*)"Video browser context"); diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp index ea73e11..5696433 100755 --- a/media/jni/mediaeditor/VideoEditorClasses.cpp +++ b/media/jni/mediaeditor/VideoEditorClasses.cpp @@ -28,7 +28,6 @@ extern "C" { #include <M4OSA_FileWriter.h> #include <M4OSA_Memory.h> #include <M4OSA_Debug.h> -#include <M4OSA_String.h> #include <M4OSA_Thread.h> #include <M4VSS3GPP_API.h> #include <M4xVSS_API.h> @@ -2465,7 +2464,7 @@ videoEditClasses_getEffectSettings( if (pSettings->xVSS.pFramingFilePath != M4OSA_NULL) { pSettings->xVSS.pFramingBuffer = - (M4VIFI_ImagePlane *)M4OSA_malloc(sizeof(M4VIFI_ImagePlane), + (M4VIFI_ImagePlane *)M4OSA_32bitAlignedMalloc(sizeof(M4VIFI_ImagePlane), 0x00,(M4OSA_Char *)"framing buffer"); } diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp index b792295..c95a0c2 100755 --- a/media/jni/mediaeditor/VideoEditorMain.cpp +++ b/media/jni/mediaeditor/VideoEditorMain.cpp @@ -41,15 +41,12 @@ extern "C" { #include <M4OSA_FileCommon.h> #include <M4OSA_FileReader.h> #include <M4OSA_FileWriter.h> -#include <M4OSA_FileExtra.h> #include <M4OSA_Memory.h> -#include <M4OSA_String.h> #include <M4OSA_Thread.h> #include <M4xVSS_API.h> #include <M4VSS3GPP_ErrorCodes.h> #include <M4MCS_API.h> #include <M4MCS_ErrorCodes.h> -#include <M4MDP_API.h> #include <M4READER_Common.h> #include <M4WRITER_common.h> }; @@ -416,7 +413,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType, LOGV("MSG_TYPE_OVERLAY_UPDATE"); if (pContext->mOverlayFileName != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName); + free(pContext->mOverlayFileName); pContext->mOverlayFileName = NULL; } @@ -424,7 +421,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType, strlen((const char*)pContext->pEditSettings->Effects[overlayEffectIndex].xVSS.pFramingFilePath); pContext->mOverlayFileName = - (char*)M4OSA_malloc(overlayFileNameLen+1, + (char*)M4OSA_32bitAlignedMalloc(overlayFileNameLen+1, M4VS, (M4OSA_Char*)"videoEdito JNI overlayFile"); if (pContext->mOverlayFileName != NULL) { strncpy (pContext->mOverlayFileName, @@ -454,7 +451,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType, case MSG_TYPE_OVERLAY_CLEAR: isSendProgress = false; if (pContext->mOverlayFileName != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName); + free(pContext->mOverlayFileName); pContext->mOverlayFileName = NULL; } @@ -504,7 +501,7 @@ static int videoEditor_stopPreview(JNIEnv* pEnv, lastProgressTimeMs = pContext->mPreviewController->stopPreview(); if (pContext->mOverlayFileName != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName); + free(pContext->mOverlayFileName); pContext->mOverlayFileName = NULL; } @@ -750,7 +747,7 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv, framesizeYuv = width * height * 1.5; - pixelArray = (M4VIFI_UInt8 *)M4OSA_malloc(framesizeYuv, M4VS, + pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS, (M4OSA_Char*)"videoEditor pixelArray"); if (pixelArray == M4OSA_NULL) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", @@ -768,7 +765,7 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv, ClipProperties.uiVideoHeight, &tnTimeMs); if (result != M4NO_ERROR) { - M4OSA_free((M4OSA_MemAddr32)pixelArray); + free(pixelArray); ThumbnailClose(tnContext); return -1; } @@ -792,12 +789,12 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv, /** * Allocate output YUV planes */ - yuvPlane = (M4VIFI_ImagePlane*)M4OSA_malloc(3*sizeof(M4VIFI_ImagePlane), M4VS, + yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"videoEditor_renderPreviewFrame Output plane YUV"); if (yuvPlane == M4OSA_NULL) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() malloc error for yuv plane"); - M4OSA_free((M4OSA_MemAddr32)pixelArray); + free(pixelArray); pMessage = videoEditJava_getErrorName(M4ERR_ALLOC); jniThrowException(pEnv, "java/lang/RuntimeException", pMessage); return -1; @@ -902,10 +899,10 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv, if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==\ /*M4VIDEOEDITING_kFileType_JPG */ M4VIDEOEDITING_kFileType_ARGB8888) { - M4OSA_free((M4OSA_MemAddr32)frameStr.pBuffer); + free(frameStr.pBuffer); } else { - M4OSA_free((M4OSA_MemAddr32)yuvPlane[0].pac_data); - M4OSA_free((M4OSA_MemAddr32)yuvPlane); + free(yuvPlane[0].pac_data); + free(yuvPlane); } return tnTimeMs; } @@ -981,7 +978,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv, framesizeYuv = ((frameWidth)*(frameHeight)*1.5); - pixelArray = (M4VIFI_UInt8 *)M4OSA_malloc(framesizeYuv, M4VS,\ + pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,\ (M4OSA_Char*)"videoEditor pixelArray"); if (pixelArray == M4OSA_NULL) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", @@ -996,7 +993,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv, frameWidth, frameHeight, &timeMs); if (result != M4NO_ERROR) { - M4OSA_free((M4OSA_MemAddr32)pixelArray); + free(pixelArray); ThumbnailClose(tnContext); return fromMs; } @@ -1066,7 +1063,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv, (M4NO_ERROR != result), result); /* free the pixelArray and yuvPlane[0].pac_data */ - M4OSA_free((M4OSA_MemAddr32)yuvPlane[0].pac_data); + free(yuvPlane[0].pac_data); ThumbnailClose(tnContext); @@ -1148,7 +1145,7 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_init()"); - pOutputParams = (M4MCS_OutputParams *)M4OSA_malloc( + pOutputParams = (M4MCS_OutputParams *)M4OSA_32bitAlignedMalloc( sizeof(M4MCS_OutputParams),0x00, (M4OSA_Char *)"M4MCS_OutputParams"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, @@ -1158,14 +1155,14 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, return M4ERR_ALLOC; } - pEncodingParams = (M4MCS_EncodingParams *)M4OSA_malloc( + pEncodingParams = (M4MCS_EncodingParams *)M4OSA_32bitAlignedMalloc( sizeof(M4MCS_EncodingParams),0x00, (M4OSA_Char *)"M4MCS_EncodingParams"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pEncodingParams), "not initialized"); if (needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return M4ERR_ALLOC; } @@ -1179,15 +1176,15 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, (M4OSA_NULL == mcsContext), "not initialized"); if(needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } // generate the path for temp 3gp output file - pTemp3gpFilePath = (M4OSA_Char*) M4OSA_malloc ( + pTemp3gpFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc ( (strlen((const char*)pContext->initParams.pTempPath) + strlen((const char*)TEMP_MCS_OUT_FILE_PATH)) + 1 /* for null termination */ , 0x0, (M4OSA_Char*)"Malloc for temp 3gp file"); @@ -1204,9 +1201,9 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, } else { M4MCS_abort(mcsContext); - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return M4ERR_ALLOC; } @@ -1231,12 +1228,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if(needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath); + free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } @@ -1281,12 +1278,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath); + free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } @@ -1311,12 +1308,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath); + free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } @@ -1327,12 +1324,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath); + free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } @@ -1379,12 +1376,12 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4MCS_WAR_TRANSCODING_DONE != result), result); if (needToBeLoaded == false) { - M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath); + free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); pOutputParams = M4OSA_NULL; - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } @@ -1399,13 +1396,13 @@ M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio() EXIT "); if (pTemp3gpFilePath != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pTemp3gpFilePath); + free(pTemp3gpFilePath); } if (pOutputParams != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pOutputParams); + free(pOutputParams); } if(pEncodingParams != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pEncodingParams); + free(pEncodingParams); } return result; } @@ -1420,7 +1417,7 @@ static int removeAlphafromRGB8888 ( LOGV("removeAlphafromRGB8888: width %d", pFramingCtx->width); - M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_malloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data"); + M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data"); if (pTmpData == M4OSA_NULL) { LOGE("Failed to allocate memory for Image clip"); return M4ERR_ALLOC; @@ -1433,7 +1430,7 @@ static int removeAlphafromRGB8888 ( if ((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL)) { LOGE("removeAlphafromRGB8888: Can not open the file "); - M4OSA_free((M4OSA_MemAddr32)pTmpData); + free(pTmpData); return M4ERR_FILE_NOT_FOUND; } @@ -1443,22 +1440,22 @@ static int removeAlphafromRGB8888 ( { LOGE("removeAlphafromRGB8888: can not read the data "); M4OSA_fileReadClose(lImageFileFp); - M4OSA_free((M4OSA_MemAddr32)pTmpData); + free(pTmpData); return lerr; } M4OSA_fileReadClose(lImageFileFp); M4OSA_UInt32 frameSize = (pFramingCtx->width * pFramingCtx->height * 3); //Size of RGB 888 data. - pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_malloc( + pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc( sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"Image clip RGB888 data"); - pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_malloc( + pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc( frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data"); if (pFramingCtx->FramingRgb == M4OSA_NULL) { LOGE("Failed to allocate memory for Image clip"); - M4OSA_free((M4OSA_MemAddr32)pTmpData); + free(pTmpData); return M4ERR_ALLOC; } @@ -1468,7 +1465,7 @@ static int removeAlphafromRGB8888 ( pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i]; j++; } - M4OSA_free((M4OSA_MemAddr32)pTmpData); + free(pTmpData); return M4NO_ERROR; } @@ -1566,7 +1563,7 @@ videoEditor_populateSettings( { if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\ + free(pContext->pEditSettings->\ Effects[j].xVSS.pFramingBuffer); pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL; } @@ -1613,7 +1610,7 @@ videoEditor_populateSettings( if (pContext->pEditSettings->nbEffects > 0) { pOverlayIndex - = (int*) M4OSA_malloc(pContext->pEditSettings->nbEffects * sizeof(int), 0, + = (int*) M4OSA_32bitAlignedMalloc(pContext->pEditSettings->nbEffects * sizeof(int), 0, (M4OSA_Char*)"pOverlayIndex"); if (pOverlayIndex == M4OSA_NULL) { videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, @@ -1633,7 +1630,7 @@ videoEditor_populateSettings( M4xVSS_FramingStruct *aFramingCtx = M4OSA_NULL; aFramingCtx - = (M4xVSS_FramingStruct*)M4OSA_malloc(sizeof(M4xVSS_FramingStruct), M4VS, + = (M4xVSS_FramingStruct*)M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_FramingStruct), M4VS, (M4OSA_Char*)"M4xVSS_internalDecodeGIF: Context of the framing effect"); if (aFramingCtx == M4OSA_NULL) { @@ -1671,7 +1668,7 @@ videoEditor_populateSettings( if (needToBeLoaded == false) { M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect returned 0x%x", result); if (aFramingCtx != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx); + free(aFramingCtx); aFramingCtx = M4OSA_NULL; } goto videoEditor_populateSettings_cleanup; @@ -1699,7 +1696,7 @@ videoEditor_populateSettings( //for RGB565 pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0; pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data = - (M4VIFI_UInt8 *)M4OSA_malloc(width*height*2, + (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(width*height*2, 0x00,(M4OSA_Char *)"pac_data buffer"); if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data == M4OSA_NULL) { @@ -1720,31 +1717,31 @@ videoEditor_populateSettings( if (aFramingCtx->FramingYuv != M4OSA_NULL ) { if (aFramingCtx->FramingYuv[0].pac_data != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv[0].pac_data); + free(aFramingCtx->FramingYuv[0].pac_data); aFramingCtx->FramingYuv[0].pac_data = M4OSA_NULL; } if (aFramingCtx->FramingYuv[1].pac_data != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv[1].pac_data); + free(aFramingCtx->FramingYuv[1].pac_data); aFramingCtx->FramingYuv[1].pac_data = M4OSA_NULL; } if (aFramingCtx->FramingYuv[2].pac_data != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv[2].pac_data); + free(aFramingCtx->FramingYuv[2].pac_data); aFramingCtx->FramingYuv[2].pac_data = M4OSA_NULL; } - M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingYuv); + free(aFramingCtx->FramingYuv); aFramingCtx->FramingYuv = M4OSA_NULL; } if (aFramingCtx->FramingRgb->pac_data != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingRgb->pac_data); + free(aFramingCtx->FramingRgb->pac_data); aFramingCtx->FramingRgb->pac_data = M4OSA_NULL; } if (aFramingCtx->FramingRgb != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx->FramingRgb); + free(aFramingCtx->FramingRgb); aFramingCtx->FramingRgb = M4OSA_NULL; } if (aFramingCtx != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)aFramingCtx); + free(aFramingCtx); aFramingCtx = M4OSA_NULL; } nbOverlays++; @@ -1775,11 +1772,11 @@ videoEditor_populateSettings( /* free previous allocations , if any */ if (pContext->mAudioSettings != M4OSA_NULL) { if (pContext->mAudioSettings->pFile != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pFile); + free(pContext->mAudioSettings->pFile); pContext->mAudioSettings->pFile = M4OSA_NULL; } if (pContext->mAudioSettings->pPCMFilePath != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pPCMFilePath); + free(pContext->mAudioSettings->pPCMFilePath); pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL; } } @@ -1850,7 +1847,7 @@ videoEditor_populateSettings( strPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid); pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPath, M4OSA_NULL); if (pTempChar != NULL) { - pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_malloc( + pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_32bitAlignedMalloc( (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0, (M4OSA_Char*)"strPath allocation " ); if (pContext->mAudioSettings->pFile != M4OSA_NULL) { @@ -1875,7 +1872,7 @@ videoEditor_populateSettings( strPCMPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid); pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPCMPath, M4OSA_NULL); if (pTempChar != NULL) { - pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_malloc( + pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc( (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0, (M4OSA_Char*)"strPCMPath allocation " ); if (pContext->mAudioSettings->pPCMFilePath != M4OSA_NULL) { @@ -1986,7 +1983,7 @@ videoEditor_populateSettings_cleanup: { if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data != \ M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\ + free(pContext->pEditSettings->\ Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data); pContext->pEditSettings->\ Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data = M4OSA_NULL; @@ -1999,7 +1996,7 @@ videoEditor_populateSettings_cleanup: { if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->pEditSettings->\ + free(pContext->pEditSettings->\ Effects[j].xVSS.pFramingBuffer); pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL; } @@ -2009,7 +2006,7 @@ videoEditor_populateSettings_cleanup: if (pOverlayIndex != M4OSA_NULL) { - M4OSA_free((M4OSA_MemAddr32)pOverlayIndex); + free(pOverlayIndex); pOverlayIndex = M4OSA_NULL; } return; @@ -2498,7 +2495,7 @@ videoEditor_init( (M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath, NULL, M4OSA_NULL); pContext->initParams.pTempPath = (M4OSA_Char *) - M4OSA_malloc(strlen((const char *)tmpString) + 1, 0x0, + M4OSA_32bitAlignedMalloc(strlen((const char *)tmpString) + 1, 0x0, (M4OSA_Char *)"tempPath"); //initialize the first char. so that strcat works. M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath; @@ -2506,7 +2503,7 @@ videoEditor_init( strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString, (size_t)strlen((const char *)tmpString)); strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1); - M4OSA_free((M4OSA_MemAddr32)tmpString); + free(tmpString); pContext->mIsUpdateOverlay = false; pContext->mOverlayFileName = NULL; } @@ -2564,7 +2561,7 @@ videoEditor_init( "not initialized"); pContext->mAudioSettings = (M4xVSS_AudioMixingSettings *) - M4OSA_malloc(sizeof(M4xVSS_AudioMixingSettings),0x0, + M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_AudioMixingSettings),0x0, (M4OSA_Char *)"mAudioSettings"); videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv, (M4OSA_NULL == pContext->mAudioSettings), @@ -3066,15 +3063,15 @@ videoEditor_release( if(pContext->mAudioSettings != M4OSA_NULL) { if (pContext->mAudioSettings->pFile != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pFile); + free(pContext->mAudioSettings->pFile); pContext->mAudioSettings->pFile = M4OSA_NULL; } if (pContext->mAudioSettings->pPCMFilePath != NULL) { - M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings->pPCMFilePath); + free(pContext->mAudioSettings->pPCMFilePath); pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL; } - M4OSA_free((M4OSA_MemAddr32)pContext->mAudioSettings); + free(pContext->mAudioSettings); pContext->mAudioSettings = M4OSA_NULL; } videoEditor_freeContext(pEnv, &pContext); @@ -3252,7 +3249,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, *******************************************************************************/ samplesCountInBytes = (samplesPerValue * sizeof(M4OSA_UInt16) * channels); - bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_malloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0, + bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0, (M4OSA_Char*)"AudioGraph" ); if ( bufferIn.m_dataAddress != M4OSA_NULL) { bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16); @@ -3380,7 +3377,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, /****************************************************************************** CLOSE AND FREE ALLOCATIONS *******************************************************************************/ - M4OSA_free((M4OSA_MemAddr32)bufferIn.m_dataAddress); + free(bufferIn.m_dataAddress); M4OSA_fileReadClose(inputFileHandle); M4OSA_fileWriteClose(outFileHandle); /* final finish callback */ diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp index 339c0d1..53e7de1 100755 --- a/media/jni/mediaeditor/VideoEditorOsal.cpp +++ b/media/jni/mediaeditor/VideoEditorOsal.cpp @@ -25,7 +25,6 @@ extern "C" { #include <M4OSA_FileReader.h> #include <M4OSA_FileWriter.h> #include <M4OSA_Memory.h> -#include <M4OSA_String.h> #include <M4OSA_Thread.h> #include <M4xVSS_API.h> #include <M4VSS3GPP_ErrorCodes.h> @@ -82,14 +81,6 @@ static const VideoEdit_Osal_Result gkRESULTS[] = VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_BAD_MODE_ACCESS ), VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_INVALID_POSITION ), - // M4OSA_String.h - VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_BAD_STRING ), - VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_CONV_FAILED ), - VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_OVERFLOW ), - VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STR_BAD_ARGS ), - VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_STR_OVERFLOW ), - VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_STR_NOT_FOUND ), - // M4OSA_Thread.h VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_THREAD_NOT_STARTED ), @@ -276,7 +267,7 @@ videoEditOsal_alloc( if (*pResult) { // Allocate memory for the settings. - pData = (M4VSS3GPP_EditSettings*)M4OSA_malloc(size, 0, (M4OSA_Char*)pDescription); + pData = (M4VSS3GPP_EditSettings*)M4OSA_32bitAlignedMalloc(size, 0, (M4OSA_Char*)pDescription); if (M4OSA_NULL != pData) { // Reset the allocated memory. @@ -314,10 +305,10 @@ videoEditOsal_free( VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "videoEditOsal_free()"); // Log the API call. - VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "M4OSA_free()"); + VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "free"); // Free the memory. - M4OSA_free((M4OSA_MemAddr32)pData); + free(pData); #ifdef OSAL_MEM_LEAK_DEBUG // Update the allocated block count. gAllocatedBlockCount--; diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp index 39221f3..9de7207 100755 --- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp +++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp @@ -34,13 +34,11 @@ extern "C" { #include <M4OSA_FileReader.h> #include <M4OSA_FileWriter.h> #include <M4OSA_Memory.h> -#include <M4OSA_String.h> #include <M4OSA_Thread.h> #include <M4VSS3GPP_API.h> #include <M4VSS3GPP_ErrorCodes.h> #include <M4MCS_API.h> #include <M4MCS_ErrorCodes.h> -#include <M4MDP_API.h> #include <M4READER_Common.h> #include <M4WRITER_common.h> #include <M4DECODER_Common.h> diff --git a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp index 461bdd0..fe3734f 100755 --- a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp +++ b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp @@ -165,7 +165,7 @@ M4OSA_ERR ThumbnailOpen(M4OSA_Context *pPContext, CHECK_PTR(ThumbnailOpen, pString, err, M4ERR_BAD_CONTEXT); /*--- Create context ---*/ - pContext = (ThumbnailContext*)M4OSA_malloc(sizeof(ThumbnailContext), VIDEOBROWSER, + pContext = (ThumbnailContext*)M4OSA_32bitAlignedMalloc(sizeof(ThumbnailContext), VIDEOBROWSER, (M4OSA_Char*)"Thumbnail context") ; M4OSA_TRACE3_1("context value is = %d",pContext); CHECK_PTR(ThumbnailOpen, pContext, err, M4ERR_ALLOC); @@ -211,7 +211,7 @@ ThumbnailOpen_cleanUp: { videoBrowserCleanUp(pContext->m_pVideoBrowser) ; } - M4OSA_free((M4OSA_MemAddr32)pContext) ; + free(pContext) ; } return err; } @@ -320,7 +320,7 @@ void ThumbnailClose(const M4OSA_Context pContext) { videoBrowserCleanUp(pC->m_pVideoBrowser); } - M4OSA_free((M4OSA_MemAddr32)pC); + free(pC); } ThumbnailClose_cleanUp: diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index f9db1a1..01d0a92 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2028,14 +2028,18 @@ status_t MPEG4Source::read( size_t dstOffset = 0; while (srcOffset < size) { - CHECK(srcOffset + mNALLengthSize <= size); - size_t nalLength = parseNALSize(&mSrcBuffer[srcOffset]); - srcOffset += mNALLengthSize; + bool isMalFormed = (srcOffset + mNALLengthSize > size); + size_t nalLength = 0; + if (!isMalFormed) { + nalLength = parseNALSize(&mSrcBuffer[srcOffset]); + srcOffset += mNALLengthSize; + isMalFormed = srcOffset + nalLength > size; + } - if (srcOffset + nalLength > size) { + if (isMalFormed) { + LOGE("Video is malformed"); mBuffer->release(); mBuffer = NULL; - return ERROR_MALFORMED; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 879f1a8..73003c8 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -511,7 +511,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } // This will populate st.shownPanelView - if (!initializePanelContent(st) || (st.shownPanelView == null)) { + if (!initializePanelContent(st) || !st.hasPanelItems()) { return; } @@ -2976,6 +2976,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { refreshDecorView = false; } + public boolean hasPanelItems() { + if (shownPanelView == null) return false; + + if (isInExpandedMode) { + return expandedMenuPresenter.getAdapter().getCount() > 0; + } else { + return ((ViewGroup) shownPanelView).getChildCount() > 0; + } + } + /** * Unregister and free attached MenuPresenters. They will be recreated as needed. */ diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 1969945..a37ccc7 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -35,7 +35,6 @@ import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Binder; -import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.LocalPowerManager; @@ -56,11 +55,9 @@ import com.android.internal.telephony.ITelephony; import com.android.internal.view.BaseInputHandler; import com.android.internal.widget.PointerLocationView; -import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; import android.util.Slog; -import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.IWindowManager; @@ -348,10 +345,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.) int mIncallPowerBehavior; - int mLandscapeRotation = -1; // default landscape rotation - int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation - int mPortraitRotation = -1; // default portrait rotation - int mUpsideDownRotation = -1; // "other" portrait rotation + int mLandscapeRotation = 0; // default landscape rotation + int mSeascapeRotation = 0; // "other" landscape rotation, 180 degrees from mLandscapeRotation + int mPortraitRotation = 0; // default portrait rotation + int mUpsideDownRotation = 0; // "other" portrait rotation // Nothing to see here, move along... int mFancyRotationAnimation; @@ -742,6 +739,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { initializeHdmiState(); } + public void setInitialDisplaySize(int width, int height) { + if (width > height) { + mLandscapeRotation = Surface.ROTATION_0; + mSeascapeRotation = Surface.ROTATION_180; + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_reverseDefaultRotation)) { + mPortraitRotation = Surface.ROTATION_90; + mUpsideDownRotation = Surface.ROTATION_270; + } else { + mPortraitRotation = Surface.ROTATION_270; + mUpsideDownRotation = Surface.ROTATION_90; + } + } else { + mPortraitRotation = Surface.ROTATION_0; + mUpsideDownRotation = Surface.ROTATION_180; + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_reverseDefaultRotation)) { + mLandscapeRotation = Surface.ROTATION_270; + mSeascapeRotation = Surface.ROTATION_90; + } else { + mLandscapeRotation = Surface.ROTATION_90; + mSeascapeRotation = Surface.ROTATION_270; + } + } + } + public void updateSettings() { ContentResolver resolver = mContext.getContentResolver(); boolean updateRotation = false; @@ -2528,7 +2551,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - + public int rotationForOrientationLw(int orientation, int lastRotation, boolean displayEnabled) { @@ -2541,35 +2564,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { ); } - if (mPortraitRotation < 0) { - // Initialize the rotation angles for each orientation once. - Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) - .getDefaultDisplay(); - if (d.getWidth() > d.getHeight()) { - mLandscapeRotation = Surface.ROTATION_0; - mSeascapeRotation = Surface.ROTATION_180; - if (mContext.getResources().getBoolean( - com.android.internal.R.bool.config_reverseDefaultRotation)) { - mPortraitRotation = Surface.ROTATION_90; - mUpsideDownRotation = Surface.ROTATION_270; - } else { - mPortraitRotation = Surface.ROTATION_270; - mUpsideDownRotation = Surface.ROTATION_90; - } - } else { - mPortraitRotation = Surface.ROTATION_0; - mUpsideDownRotation = Surface.ROTATION_180; - if (mContext.getResources().getBoolean( - com.android.internal.R.bool.config_reverseDefaultRotation)) { - mLandscapeRotation = Surface.ROTATION_270; - mSeascapeRotation = Surface.ROTATION_90; - } else { - mLandscapeRotation = Surface.ROTATION_90; - mSeascapeRotation = Surface.ROTATION_270; - } - } - } - synchronized (mLock) { switch (orientation) { case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: @@ -2621,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/input/SpriteController.cpp b/services/input/SpriteController.cpp index 2fd1f0a..08cc75e 100644 --- a/services/input/SpriteController.cpp +++ b/services/input/SpriteController.cpp @@ -376,7 +376,7 @@ sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height ensureSurfaceComposerClient(); sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface( - getpid(), String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888); + String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888); if (surfaceControl == NULL || !surfaceControl->isValid() || !surfaceControl->getSurface()->isValid()) { LOGE("Error creating sprite surface."); diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java index ced8feb..8ba0a0b 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -20,8 +20,8 @@ import com.android.server.wm.InputFilter; import android.content.Context; import android.util.Slog; +import android.view.InputDevice; import android.view.InputEvent; -import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowManagerPolicy; @@ -32,10 +32,35 @@ import android.view.WindowManagerPolicy; */ public class AccessibilityInputFilter extends InputFilter { private static final String TAG = "AccessibilityInputFilter"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private final Context mContext; + /** + * This is an interface for explorers that take a {@link MotionEvent} + * stream and perform touch exploration of the screen content. + */ + public interface Explorer { + /** + * Handles a {@link MotionEvent}. + * + * @param event The event to handle. + * @param policyFlags The policy flags associated with the event. + */ + public void onMotionEvent(MotionEvent event, int policyFlags); + + /** + * Requests that the explorer clears its internal state. + * + * @param event The last received event. + * @param policyFlags The policy flags associated with the event. + */ + public void clear(MotionEvent event, int policyFlags); + } + + private TouchExplorer mTouchExplorer; + private int mTouchscreenSourceDeviceId; + public AccessibilityInputFilter(Context context) { super(context.getMainLooper()); mContext = context; @@ -60,27 +85,27 @@ public class AccessibilityInputFilter extends InputFilter { @Override public void onInputEvent(InputEvent event, int policyFlags) { if (DEBUG) { - Slog.d(TAG, "Accessibility input filter received input event: " - + event + ", policyFlags=0x" + Integer.toHexString(policyFlags)); + Slog.d(TAG, "Received event: " + event + ", policyFlags=0x" + + Integer.toHexString(policyFlags)); } - - // To prove that this is working as intended, we will silently transform - // Q key presses into non-repeating Z's as part of this stub implementation. - // TODO: Replace with the real thing. - if (event instanceof KeyEvent) { - final KeyEvent keyEvent = (KeyEvent)event; - if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_Q) { - if (keyEvent.getRepeatCount() == 0) { - sendInputEvent(new KeyEvent(keyEvent.getDownTime(), keyEvent.getEventTime(), - keyEvent.getAction(), KeyEvent.KEYCODE_Z, keyEvent.getRepeatCount(), - keyEvent.getMetaState(), keyEvent.getDeviceId(), keyEvent.getScanCode(), - keyEvent.getFlags(), keyEvent.getSource()), - policyFlags | WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); + if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { + MotionEvent motionEvent = (MotionEvent) event; + int deviceId = event.getDeviceId(); + if (mTouchscreenSourceDeviceId != deviceId) { + mTouchscreenSourceDeviceId = deviceId; + if (mTouchExplorer != null) { + mTouchExplorer.clear(motionEvent, policyFlags); + } else { + mTouchExplorer = new TouchExplorer(this, mContext); } - return; } + if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) != 0) { + mTouchExplorer.onMotionEvent(motionEvent, policyFlags); + } else { + mTouchExplorer.clear(motionEvent, policyFlags); + } + } else { + super.onInputEvent(event, policyFlags); } - - super.onInputEvent(event, policyFlags); } } diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 7a483aa..1ad8047 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -56,6 +56,7 @@ import android.view.accessibility.IAccessibilityManagerClient; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -74,6 +75,8 @@ import java.util.Set; public class AccessibilityManagerService extends IAccessibilityManager.Stub implements HandlerCaller.Callback { + private static final boolean DEBUG = false; + private static final String LOG_TAG = "AccessibilityManagerService"; private static int sIdCounter = 0; @@ -102,6 +105,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':'); + private final SparseArray<List<ServiceInfo>> mFeedbackTypeToEnabledServicesMap = + new SparseArray<List<ServiceInfo>>(); + private PackageManager mPackageManager; private int mHandledFeedbackTypes = 0; @@ -211,7 +217,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } manageServicesLocked(); - updateInputFilterLocked(); } return; @@ -252,7 +257,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub unbindAllServicesLocked(); } updateClientsLocked(); - updateInputFilterLocked(); } } }); @@ -300,6 +304,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + public List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) { + synchronized (mLock) { + List<ServiceInfo> enabledServices = mFeedbackTypeToEnabledServicesMap.get(feedbackType); + if (enabledServices == null) { + return Collections.emptyList(); + } + return enabledServices; + } + } + public void interrupt() { synchronized (mLock) { for (int i = 0, count = mServices.size(); i < count; i++) { @@ -339,6 +353,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } service.mNotificationTimeout = info.notificationTimeout; service.mIsDefault = (info.flags & AccessibilityServiceInfo.DEFAULT) != 0; + + updateStateOnEnabledService(service); } return; default: @@ -449,7 +465,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub try { listener.onAccessibilityEvent(event); - if (false) { + if (DEBUG) { Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); } } catch (RemoteException re) { @@ -469,10 +485,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * @return True if the service was removed, false otherwise. */ private boolean removeDeadServiceLocked(Service service) { - if (false) { + if (DEBUG) { Slog.i(LOG_TAG, "Dead service " + service.mService + " removed"); } mHandler.removeMessages(service.mId); + updateStateOnDisabledService(service); return mServices.remove(service); } @@ -593,7 +610,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (isEnabled) { if (enabledServices.contains(componentName)) { if (service == null) { - service = new Service(componentName); + service = new Service(componentName, intalledService); } service.bind(); } else if (!enabledServices.contains(componentName)) { @@ -644,6 +661,47 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** + * Updates the set of enabled services for a given feedback type and + * if more than one of them provides spoken feedback enables touch + * exploration. + * + * @param service An enable service. + */ + private void updateStateOnEnabledService(Service service) { + int feedbackType = service.mFeedbackType; + List<ServiceInfo> enabledServices = mFeedbackTypeToEnabledServicesMap.get(feedbackType); + if (enabledServices == null) { + enabledServices = new ArrayList<ServiceInfo>(); + mFeedbackTypeToEnabledServicesMap.put(feedbackType, enabledServices); + } + enabledServices.add(service.mServiceInfo); + + // We enable touch exploration if at least one + // enabled service provides spoken feedback. + if (enabledServices.size() > 0 + && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) { + updateClientsLocked(); + updateInputFilterLocked(); + } + } + + private void updateStateOnDisabledService(Service service) { + List<ServiceInfo> enabledServices = + mFeedbackTypeToEnabledServicesMap.get(service.mFeedbackType); + if (enabledServices == null) { + return; + } + enabledServices.remove(service.mServiceInfo); + // We disable touch exploration if no + // enabled service provides spoken feedback. + if (enabledServices.isEmpty() + && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) { + updateClientsLocked(); + updateInputFilterLocked(); + } + } + + /** * This class represents an accessibility service. It stores all per service * data required for the service management, provides API for starting/stopping the * service and is responsible for adding/removing the service in the data structures @@ -654,6 +712,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub class Service extends IAccessibilityServiceConnection.Stub implements ServiceConnection { int mId = 0; + ServiceInfo mServiceInfo; + IBinder mService; IEventListener mServiceInterface; @@ -678,9 +738,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<AccessibilityEvent>(); - Service(ComponentName componentName) { + Service(ComponentName componentName, ServiceInfo serviceInfo) { mId = sIdCounter++; mComponentName = componentName; + mServiceInfo = serviceInfo; mIntent = new Intent().setComponent(mComponentName); mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, com.android.internal.R.string.accessibility_binding_label); @@ -712,6 +773,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mContext.unbindService(this); mComponentNameToServiceMap.remove(mComponentName); mServices.remove(this); + updateStateOnDisabledService(this); return true; } return false; diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java new file mode 100644 index 0000000..4ba6060 --- /dev/null +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -0,0 +1,1540 @@ +/* + ** Copyright 2011, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +package com.android.server.accessibility; + +import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END; +import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START; + +import com.android.server.accessibility.AccessibilityInputFilter.Explorer; +import com.android.server.wm.InputFilter; + +import android.content.Context; +import android.os.Handler; +import android.os.SystemClock; +import android.util.Slog; +import android.util.SparseArray; +import android.view.MotionEvent; +import android.view.ViewConfiguration; +import android.view.WindowManagerPolicy; +import android.view.MotionEvent.PointerCoords; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; + +import java.util.Arrays; + +/** + * This class is a strategy for performing touch exploration. It + * transforms the motion event stream by modifying, adding, replacing, + * and consuming certain events. The interaction model is: + * + * <ol> + * <li>1. One finger moving around performs touch exploration.</li> + * <li>2. Two close fingers moving in the same direction perform a drag.</li> + * <li>3. Multi-finger gestures are delivered to view hierarchy.</li> + * <li>4. Pointers that have not moved more than a specified distance after they + * went down are considered inactive.</li> + * <li>5. Two fingers moving too far from each other or in different directions + * are considered a multi-finger gesture.</li> + * <li>6. Tapping on the last touch explored location within given time and + * distance slop performs a click.</li> + * <li>7. Tapping and holding for a while on the last touch explored location within + * given time and distance slop performs a long press.</li> + * <ol> + * + * @hide + */ +public class TouchExplorer implements Explorer { + private static final boolean DEBUG = false; + + // Tag for logging received events. + private static final String LOG_TAG_RECEIVED = "TouchExplorer-RECEIVED"; + // Tag for logging injected events. + private static final String LOG_TAG_INJECTED = "TouchExplorer-INJECTED"; + // Tag for logging the current state. + private static final String LOG_TAG_STATE = "TouchExplorer-STATE"; + + // States this explorer can be in. + private static final int STATE_TOUCH_EXPLORING = 0x00000001; + private static final int STATE_DRAGGING = 0x00000002; + private static final int STATE_DELEGATING = 0x00000004; + + // Human readable symbolic names for the states of the explorer. + private static final SparseArray<String> sStateSymbolicNames = new SparseArray<String>(); + static { + SparseArray<String> symbolicNames = sStateSymbolicNames; + symbolicNames.append(STATE_TOUCH_EXPLORING, "STATE_TOUCH_EXPLORING"); + symbolicNames.append(STATE_DRAGGING, "STATE_DRAGING"); + symbolicNames.append(STATE_DELEGATING, "STATE_DELEGATING"); + } + + // Invalid pointer ID. + private static final int INVALID_POINTER_ID = -1; + + // The coefficient by which to multiply + // ViewConfiguration.#getScaledTouchExplorationTapSlop() + // to compute #mDraggingDistance. + private static final int COEFFICIENT_DRAGGING_DISTANCE = 2; + + // The time slop in milliseconds for activating an item after it has + // been touch explored. Tapping on an item within this slop will perform + // a click and tapping and holding down a long press. + private static final long ACTIVATION_TIME_SLOP = 2000; + + // This constant captures the current implementation detail that + // pointer IDs are between 0 and 31 inclusive (subject to change). + // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h) + private static final int MAX_POINTER_COUNT = 32; + + // The minimum of the cosine between the vectors of two moving + // pointers so they can be considered moving in the same direction. + private static final float MIN_ANGLE_COS = 0.866025404f; // cos(pi/6) + + // The delay for sending a hover enter event. + private static final long DELAY_SEND_HOVER_MOVE = 200; + + // Temporary array for storing pointer IDs. + private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT]; + + // Temporary array for mapping new to old pointer IDs while filtering inactive pointers. + private final int [] mTempNewToOldPointerIndexMap = new int[MAX_POINTER_COUNT]; + + // Temporary array for storing PointerCoords + private final PointerCoords[] mTempPointerCoords= new PointerCoords[MAX_POINTER_COUNT]; + + // The maximal distance between two pointers so they are + // considered to be performing a drag operation. + private final float mDraggingDistance; + + // The distance from the last touch explored location tapping within + // which would perform a click and tapping and holding a long press. + private final int mTouchExplorationTapSlop; + + // Context handle for accessing resources. + private final Context mContext; + + // The InputFilter this tracker is associated with i.e. the filter + // which delegates event processing to this touch explorer. + private final InputFilter mInputFilter; + + // Helper class for tracking pointers on the screen, for example which + // pointers are down, which are active, etc. + private final PointerTracker mPointerTracker; + + // Handle to the accessibility manager for firing accessibility events + // announcing touch exploration gesture start and end. + private final AccessibilityManager mAccessibilityManager; + + // The last event that was received while performing touch exploration. + private MotionEvent mLastTouchExploreEvent; + + // The current state of the touch explorer. + private int mCurrentState = STATE_TOUCH_EXPLORING; + + // Flag whether a touch exploration gesture is in progress. + private boolean mTouchExploreGestureInProgress; + + // The ID of the pointer used for dragging. + private int mDraggingPointerId; + + // Handler for performing asynchronous operations. + private final Handler mHandler; + + // Command for delayed sending of a hover event. + private final SendHoverDelayed mSendHoverDelayed; + + /** + * Creates a new instance. + * + * @param inputFilter The input filter associated with this explorer. + * @param context A context handle for accessing resources. + */ + public TouchExplorer(InputFilter inputFilter, Context context) { + mInputFilter = inputFilter; + mTouchExplorationTapSlop = + ViewConfiguration.get(context).getScaledTouchExplorationTapSlop(); + mDraggingDistance = mTouchExplorationTapSlop * COEFFICIENT_DRAGGING_DISTANCE; + mPointerTracker = new PointerTracker(context); + mContext = context; + mHandler = new Handler(context.getMainLooper()); + mSendHoverDelayed = new SendHoverDelayed(); + mAccessibilityManager = AccessibilityManager.getInstance(context); + + // Populate the temporary array with PointerCorrds to be reused. + for (int i = 0, count = mTempPointerCoords.length; i < count; i++) { + mTempPointerCoords[i] = new PointerCoords(); + } + } + + public void clear(MotionEvent event, int policyFlags) { + sendUpForInjectedDownPointers(event, policyFlags); + clear(); + } + + /** + * {@inheritDoc} + */ + public void onMotionEvent(MotionEvent event, int policyFlags) { + if (DEBUG) { + Slog.d(LOG_TAG_RECEIVED, "Received event: " + event + ", policyFlags=0x" + + Integer.toHexString(policyFlags)); + Slog.d(LOG_TAG_STATE, sStateSymbolicNames.get(mCurrentState)); + } + + // Keep track of the pointers's state. + mPointerTracker.onReceivedMotionEvent(event); + + switch(mCurrentState) { + case STATE_TOUCH_EXPLORING: { + handleMotionEventStateTouchExploring(event, policyFlags); + } break; + case STATE_DRAGGING: { + handleMotionEventStateDragging(event, policyFlags); + } break; + case STATE_DELEGATING: { + handleMotionEventStateDelegating(event, policyFlags); + } break; + default: { + throw new IllegalStateException("Illegal state: " + mCurrentState); + } + } + } + + /** + * Handles a motion event in touch exploring state. + * + * @param event The event to be handled. + * @param policyFlags The policy flags associated with the event. + */ + private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) { + PointerTracker pointerTracker = mPointerTracker; + final int activePointerCount = pointerTracker.getActivePointerCount(); + + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + // Send a hover for every finger down so the user gets feedback + // where she is currently touching. + mSendHoverDelayed.forceSendAndRemove(); + mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, 0, policyFlags, + DELAY_SEND_HOVER_MOVE); + } break; + case MotionEvent.ACTION_POINTER_DOWN: { + switch (activePointerCount) { + case 0: { + throw new IllegalStateException("The must always be one active pointer in" + + "touch exploring state!"); + } + case 1: { + // Schedule a hover event which will lead to firing an + // accessibility event from the hovered view. + mSendHoverDelayed.remove(); + final int pointerId = pointerTracker.getPrimaryActivePointerId(); + final int pointerIndex = event.findPointerIndex(pointerId); + final int lastAction = pointerTracker.getLastInjectedHoverAction(); + // If a schedules hover enter for another pointer is delivered we send move. + final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER) + ? MotionEvent.ACTION_HOVER_MOVE + : MotionEvent.ACTION_HOVER_ENTER; + mSendHoverDelayed.post(event, action, pointerIndex, policyFlags, + DELAY_SEND_HOVER_MOVE); + + if (mLastTouchExploreEvent == null) { + break; + } + + // If more pointers down on the screen since the last touch + // exploration we discard the last cached touch explore event. + if (event.getPointerCount() != mLastTouchExploreEvent.getPointerCount()) { + mLastTouchExploreEvent = null; + } + } break; + default: { + /* do nothing - let the code for ACTION_MOVE decide what to do */ + } break; + } + } break; + case MotionEvent.ACTION_MOVE: { + switch (activePointerCount) { + case 0: { + /* do nothing - no active pointers so we swallow the event */ + } break; + case 1: { + final int pointerId = pointerTracker.getPrimaryActivePointerId(); + final int pointerIndex = event.findPointerIndex(pointerId); + + // Detect touch exploration gesture start by having one active pointer + // that moved more than a given distance. + if (!mTouchExploreGestureInProgress) { + final float deltaX = pointerTracker.getReceivedPointerDownX(pointerId) + - event.getX(pointerIndex); + final float deltaY = pointerTracker.getReceivedPointerDownY(pointerId) + - event.getY(pointerIndex); + final double moveDelta = Math.hypot(deltaX, deltaY); + + if (moveDelta > mTouchExplorationTapSlop) { + mTouchExploreGestureInProgress = true; + sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START); + // Make sure the scheduled down/move event is sent. + mSendHoverDelayed.forceSendAndRemove(); + sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex, + policyFlags); + } + } else { + // Touch exploration gesture in progress so send a hover event. + sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex, + policyFlags); + } + + // Detect long press on the last touch explored position. + if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null) { + + // If the down was not in the time slop => nothing else to do. + final long pointerDownTime = + pointerTracker.getReceivedPointerDownTime(pointerId); + final long lastExploreTime = mLastTouchExploreEvent.getEventTime(); + final long deltaTimeExplore = pointerDownTime - lastExploreTime; + if (deltaTimeExplore > ACTIVATION_TIME_SLOP) { + mLastTouchExploreEvent = null; + break; + } + + // If the pointer moved more than the tap slop => nothing else to do. + final float deltaX = mLastTouchExploreEvent.getX(pointerIndex) + - event.getX(pointerIndex); + final float deltaY = mLastTouchExploreEvent.getY(pointerIndex) + - event.getY(pointerIndex); + final float moveDelta = (float) Math.hypot(deltaX, deltaY); + if (moveDelta > mTouchExplorationTapSlop) { + mLastTouchExploreEvent = null; + break; + } + + // If down for long enough we get a long press. + final long deltaTimeMove = event.getEventTime() - pointerDownTime; + if (deltaTimeMove > ViewConfiguration.getLongPressTimeout()) { + mCurrentState = STATE_DELEGATING; + // Make sure the scheduled hover exit is delivered. + mSendHoverDelayed.forceSendAndRemove(); + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + sendMotionEvent(event, policyFlags); + mTouchExploreGestureInProgress = false; + mLastTouchExploreEvent = null; + } + } + } break; + case 2: { + // Make sure the scheduled hover enter is delivered. + mSendHoverDelayed.forceSendAndRemove(); + // We want to no longer hover over the location so subsequent + // touch at the same spot will generate a hover enter. + final int pointerId = pointerTracker.getPrimaryActivePointerId(); + final int pointerIndex = event.findPointerIndex(pointerId); + sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex, + policyFlags); + + if (isDraggingGesture(event)) { + // Two pointers moving in the same direction within + // a given distance perform a drag. + mCurrentState = STATE_DRAGGING; + if (mTouchExploreGestureInProgress) { + sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); + mTouchExploreGestureInProgress = false; + } + mDraggingPointerId = pointerTracker.getPrimaryActivePointerId(); + sendDragEvent(event, MotionEvent.ACTION_DOWN, policyFlags); + } else { + // Two pointers moving arbitrary are delegated to the view hierarchy. + mCurrentState = STATE_DELEGATING; + if (mTouchExploreGestureInProgress) { + sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); + mTouchExploreGestureInProgress = false; + } + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + } + } break; + default: { + // Make sure the scheduled hover enter is delivered. + mSendHoverDelayed.forceSendAndRemove(); + // We want to no longer hover over the location so subsequent + // touch at the same spot will generate a hover enter. + final int pointerId = pointerTracker.getPrimaryActivePointerId(); + final int pointerIndex = event.findPointerIndex(pointerId); + sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex, + policyFlags); + + // More than two pointers are delegated to the view hierarchy. + mCurrentState = STATE_DELEGATING; + mSendHoverDelayed.remove(); + if (mTouchExploreGestureInProgress) { + sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); + mTouchExploreGestureInProgress = false; + } + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + } + } + } break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: { + switch (activePointerCount) { + case 0: { + // If the pointer that went up was not active we have nothing to do. + if (!pointerTracker.wasLastReceivedUpPointerActive()) { + break; + } + + // If touch exploring announce the end of the gesture. + if (mTouchExploreGestureInProgress) { + sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); + mTouchExploreGestureInProgress = false; + } + + // Detect whether to activate i.e. click on the last explored location. + if (mLastTouchExploreEvent != null) { + final int pointerId = pointerTracker.getLastReceivedUpPointerId(); + + // If the down was not in the time slop => nothing else to do. + final long eventTime = + pointerTracker.getLastReceivedUpPointerDownTime(); + final long exploreTime = mLastTouchExploreEvent.getEventTime(); + final long deltaTime = eventTime - exploreTime; + if (deltaTime > ACTIVATION_TIME_SLOP) { + mSendHoverDelayed.forceSendAndRemove(); + scheduleHoverExit(event, policyFlags); + mLastTouchExploreEvent = MotionEvent.obtain(event); + break; + } + + // If the pointer moved more than the tap slop => nothing else to do. + final int pointerIndex = event.findPointerIndex(pointerId); + final float deltaX = pointerTracker.getLastReceivedUpPointerDownX() + - event.getX(pointerIndex); + final float deltaY = pointerTracker.getLastReceivedUpPointerDownY() + - event.getY(pointerIndex); + final float deltaMove = (float) Math.hypot(deltaX, deltaY); + if (deltaMove > mTouchExplorationTapSlop) { + mSendHoverDelayed.forceSendAndRemove(); + scheduleHoverExit(event, policyFlags); + mLastTouchExploreEvent = MotionEvent.obtain(event); + break; + } + + // All preconditions are met, so click the last explored location. + mSendHoverDelayed.forceSendAndRemove(); + sendActionDownAndUp(mLastTouchExploreEvent, policyFlags); + mLastTouchExploreEvent = null; + } else { + mSendHoverDelayed.forceSendAndRemove(); + scheduleHoverExit(event, policyFlags); + mLastTouchExploreEvent = MotionEvent.obtain(event); + } + } break; + } + } break; + case MotionEvent.ACTION_CANCEL: { + final int lastAction = pointerTracker.getLastInjectedHoverAction(); + if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { + final int pointerId = pointerTracker.getPrimaryActivePointerId(); + final int pointerIndex = event.findPointerIndex(pointerId); + sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex, + policyFlags); + } + clear(); + } break; + } + } + + /** + * Handles a motion event in dragging state. + * + * @param event The event to be handled. + * @param policyFlags The policy flags associated with the event. + */ + private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + throw new IllegalStateException("Dragging state can be reached only if two " + + "pointers are already down"); + } + case MotionEvent.ACTION_POINTER_DOWN: { + // We are in dragging state so we have two pointers and another one + // goes down => delegate the three pointers to the view hierarchy + mCurrentState = STATE_DELEGATING; + sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + } break; + case MotionEvent.ACTION_MOVE: { + final int activePointerCount = mPointerTracker.getActivePointerCount(); + switch (activePointerCount) { + case 2: { + if (isDraggingGesture(event)) { + // If still dragging send a drag event. + sendDragEvent(event, MotionEvent.ACTION_MOVE, policyFlags); + } else { + // The two pointers are moving either in different directions or + // no close enough => delegate the gesture to the view hierarchy. + mCurrentState = STATE_DELEGATING; + // Send an event to the end of the drag gesture. + sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); + // Deliver all active pointers to the view hierarchy. + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + } + } break; + default: { + mCurrentState = STATE_DELEGATING; + // Send an event to the end of the drag gesture. + sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); + // Deliver all active pointers to the view hierarchy. + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + } + } + } break; + case MotionEvent.ACTION_POINTER_UP: { + mCurrentState = STATE_TOUCH_EXPLORING; + // Send an event to the end of the drag gesture. + sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); + } break; + case MotionEvent.ACTION_CANCEL: { + clear(); + } break; + } + } + + /** + * Handles a motion event in delegating state. + * + * @param event The event to be handled. + * @param policyFlags The policy flags associated with the event. + */ + public void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + throw new IllegalStateException("Delegating state can only be reached if " + + "there is at least one pointer down!"); + } + case MotionEvent.ACTION_UP: { + mCurrentState = STATE_TOUCH_EXPLORING; + } break; + case MotionEvent.ACTION_MOVE: { + // Check whether some other pointer became active because they have moved + // a given distance and if such exist send them to the view hierarchy + final int notInjectedCount = mPointerTracker.getNotInjectedActivePointerCount(); + if (notInjectedCount > 0) { + sendDownForAllActiveNotInjectedPointers(event, policyFlags); + } + } break; + case MotionEvent.ACTION_POINTER_UP: { + // No active pointers => go to initial state. + if (mPointerTracker.getActivePointerCount() == 0) { + mCurrentState = STATE_TOUCH_EXPLORING; + } + } break; + case MotionEvent.ACTION_CANCEL: { + clear(); + } break; + } + // Deliver the event striping out inactive pointers. + sendMotionEventStripInactivePointers(event, policyFlags); + } + + /** + * Schedules a hover up event so subsequent poking on the same location after + * the scheduled delay will perform exploration. + * + * @param prototype The prototype from which to create the injected events. + * @param policyFlags The policy flags associated with the event. + */ + private void scheduleHoverExit(MotionEvent prototype, + int policyFlags) { + final int pointerId = mPointerTracker.getLastReceivedUpPointerId(); + final int pointerIndex = prototype.findPointerIndex(pointerId); + // We want to no longer hover over the location so subsequent + // touch at the same spot will generate a hover enter. + mSendHoverDelayed.post(prototype, MotionEvent.ACTION_HOVER_EXIT, + pointerIndex, policyFlags, ACTIVATION_TIME_SLOP); + } + + /** + * Sends down events to the view hierarchy for all active pointers which are + * not already being delivered i.e. pointers that are not yet injected. + * + * @param prototype The prototype from which to create the injected events. + * @param policyFlags The policy flags associated with the event. + */ + private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) { + PointerCoords[] pointerCoords = mTempPointerCoords; + PointerTracker pointerTracker = mPointerTracker; + int[] pointerIds = mTempPointerIds; + int pointerDataIndex = 0; + + final int pinterCount = prototype.getPointerCount(); + for (int i = 0; i < pinterCount; i++) { + final int pointerId = prototype.getPointerId(i); + + // Skip inactive pointers. + if (!pointerTracker.isActivePointer(pointerId)) { + continue; + } + // Skip already delivered pointers. + if (pointerTracker.isInjectedPointerDown(pointerId)) { + continue; + } + + // Populate and inject an event for the current pointer. + pointerIds[pointerDataIndex] = pointerId; + prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); + + final long downTime = pointerTracker.getLastInjectedDownEventTime(); + final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, pointerDataIndex); + final int pointerCount = pointerDataIndex + 1; + final long pointerDownTime = SystemClock.uptimeMillis(); + + MotionEvent event = MotionEvent.obtain(downTime, pointerDownTime, + action, pointerCount, pointerIds, pointerCoords, prototype.getMetaState(), + prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), + prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); + sendMotionEvent(event, policyFlags); + event.recycle(); + + pointerDataIndex++; + } + } + + /** + * Sends up events to the view hierarchy for all active pointers which are + * already being delivered i.e. pointers that are injected. + * + * @param prototype The prototype from which to create the injected events. + * @param policyFlags The policy flags associated with the event. + */ + private void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) { + PointerTracker pointerTracker = mPointerTracker; + PointerCoords[] pointerCoords = mTempPointerCoords; + int[] pointerIds = mTempPointerIds; + int pointerDataIndex = 0; + + final int pointerCount = prototype.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = prototype.getPointerId(i); + + // Skip non injected down pointers. + if (!pointerTracker.isInjectedPointerDown(pointerId)) { + continue; + } + + // Populate and inject event. + pointerIds[pointerDataIndex] = pointerId; + prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); + + final long downTime = pointerTracker.getLastInjectedDownEventTime(); + final int action = computeInjectionAction(MotionEvent.ACTION_UP, pointerDataIndex); + final int newPointerCount = pointerDataIndex + 1; + final long eventTime = SystemClock.uptimeMillis(); + + MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, + newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(), + prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), + prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); + + sendMotionEvent(event, policyFlags); + event.recycle(); + + pointerDataIndex++; + } + } + + /** + * Sends a motion event by first stripping the inactive pointers. + * + * @param prototype The prototype from which to create the injected event. + * @param policyFlags The policy flags associated with the event. + */ + private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) { + PointerTracker pointerTracker = mPointerTracker; + + // All pointers active therefore we just inject the event as is. + if (prototype.getPointerCount() == pointerTracker.getActivePointerCount()) { + sendMotionEvent(prototype, policyFlags); + return; + } + + // No active pointers and the one that just went up was not + // active, therefore we have nothing to do. + if (pointerTracker.getActivePointerCount() == 0 + && !pointerTracker.wasLastReceivedUpPointerActive()) { + return; + } + + // Filter out inactive pointers from the event and inject it. + PointerCoords[] pointerCoords = mTempPointerCoords; + int[] pointerIds = mTempPointerIds; + int [] newToOldPointerIndexMap = mTempNewToOldPointerIndexMap; + int newPointerIndex = 0; + int actionIndex = prototype.getActionIndex(); + + final int oldPointerCount = prototype.getPointerCount(); + for (int oldPointerIndex = 0; oldPointerIndex < oldPointerCount; oldPointerIndex++) { + final int pointerId = prototype.getPointerId(oldPointerIndex); + + // If the pointer is inactive or the pointer that just went up + // was inactive we strip the pointer data from the event. + if (!pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) { + if (oldPointerIndex <= prototype.getActionIndex()) { + actionIndex--; + } + continue; + } + + newToOldPointerIndexMap[newPointerIndex] = oldPointerIndex; + pointerIds[newPointerIndex] = pointerId; + prototype.getPointerCoords(oldPointerIndex, pointerCoords[newPointerIndex]); + + newPointerIndex++; + } + + // If we skipped all pointers => nothing to do. + if (newPointerIndex == 0) { + return; + } + + // Populate and inject the event. + final long downTime = pointerTracker.getLastInjectedDownEventTime(); + final int action = computeInjectionAction(prototype.getActionMasked(), actionIndex); + final int newPointerCount = newPointerIndex; + MotionEvent prunedEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action, + newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(), + prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), + prototype.getEdgeFlags(), prototype.getSource(),prototype.getFlags()); + + // Add the filtered history. + final int historySize = prototype.getHistorySize(); + for (int historyIndex = 0; historyIndex < historySize; historyIndex++) { + for (int pointerIndex = 0; pointerIndex < newPointerCount; pointerIndex++) { + final int oldPointerIndex = newToOldPointerIndexMap[pointerIndex]; + prototype.getPointerCoords(oldPointerIndex, pointerCoords[pointerIndex]); + } + final long historicalTime = prototype.getHistoricalEventTime(historyIndex); + prunedEvent.addBatch(historicalTime, pointerCoords, 0); + } + + sendMotionEvent(prunedEvent, policyFlags); + prunedEvent.recycle(); + } + + /** + * Sends a dragging event from a two pointer event. The two pointers are + * merged into one and delivered to the view hierarchy. Through the entire + * drag gesture the pointer id delivered to the view hierarchy is the same. + * + * @param prototype The prototype from which to create the injected event. + * @param action The dragging action that is to be injected. + * @param policyFlags The policy flags associated with the event. + */ + private void sendDragEvent(MotionEvent prototype, int action, int policyFlags) { + PointerCoords[] pointerCoords = mTempPointerCoords; + int[] pointerIds = mTempPointerIds; + final int pointerId = mDraggingPointerId; + final int pointerIndex = prototype.findPointerIndex(pointerId); + + // Populate the event with the date of the dragging pointer and inject it. + pointerIds[0] = pointerId; + prototype.getPointerCoords(pointerIndex, pointerCoords[0]); + + MotionEvent event = MotionEvent.obtain(prototype.getDownTime(), + prototype.getEventTime(), action, 1, pointerIds, pointerCoords, + prototype.getMetaState(), prototype.getXPrecision(), prototype.getYPrecision(), + prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(), + prototype.getFlags()); + + sendMotionEvent(event, policyFlags); + event.recycle(); + } + + /** + * Sends an up and down events. + * + * @param prototype The prototype from which to create the injected events. + * @param policyFlags The policy flags associated with the event. + */ + private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) { + PointerCoords[] pointerCoords = mTempPointerCoords; + int[] pointerIds = mTempPointerIds; + final int pointerId = mPointerTracker.getLastReceivedUpPointerId(); + final int pointerIndex = prototype.findPointerIndex(pointerId); + + // Send down. + pointerIds[0] = pointerId; + prototype.getPointerCoords(pointerIndex, pointerCoords[0]); + + final long downTime = SystemClock.uptimeMillis(); + + MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, + 1, mTempPointerIds, mTempPointerCoords, prototype.getMetaState(), + prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), + prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); + + // Clone the down event before recycling it. + MotionEvent upEvent = MotionEvent.obtain(downEvent); + + sendMotionEvent(downEvent, policyFlags); + downEvent.recycle(); + + // Send up. + upEvent.setAction(MotionEvent.ACTION_UP); + sendMotionEvent(upEvent, policyFlags); + upEvent.recycle(); + } + + /** + * Sends a hover event. + * + * @param prototype The prototype from which to create the injected event. + * @param action The hover action. + * @param pointerIndex The action pointer index. + * @param policyFlags The policy flags associated with the event. + */ + private void sendHoverEvent(MotionEvent prototype, int action, int pointerIndex, int + policyFlags) { + PointerCoords[] pointerCoords = mTempPointerCoords; + int[] pointerIds = mTempPointerIds; + + // Keep only data relevant to a hover event. + pointerIds[0] = prototype.getPointerId(pointerIndex); + pointerCoords[0].clear(); + pointerCoords[0].x = prototype.getX(pointerIndex); + pointerCoords[0].y = prototype.getY(pointerIndex); + + final long downTime = mPointerTracker.getLastInjectedDownEventTime(); + + // Populate and inject a hover event. + MotionEvent hoverEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action, + 1, pointerIds, pointerCoords, 0, 0, 0, prototype.getDeviceId(), 0, + prototype.getSource(), 0); + + sendMotionEvent(hoverEvent, policyFlags); + hoverEvent.recycle(); + } + + /** + * Computes the action for an injected event based on a masked action + * and a pointer index. + * + * @param actionMasked The masked action. + * @param pointerIndex The index of the pointer which has changed. + * @return The action to be used for injection. + */ + private int computeInjectionAction(int actionMasked, int pointerIndex) { + switch (actionMasked) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: { + PointerTracker pointerTracker = mPointerTracker; + // Compute the action based on how many down pointers are injected. + if (pointerTracker.getInjectedPointerDownCount() == 0) { + return MotionEvent.ACTION_DOWN; + } else { + return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT) + | MotionEvent.ACTION_POINTER_DOWN; + } + } + case MotionEvent.ACTION_POINTER_UP: { + PointerTracker pointerTracker = mPointerTracker; + // Compute the action based on how many down pointers are injected. + if (pointerTracker.getInjectedPointerDownCount() == 1) { + return MotionEvent.ACTION_UP; + } else { + return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT) + | MotionEvent.ACTION_POINTER_UP; + } + } + default: + return actionMasked; + } + } + + /** + * Determines whether a two pointer gesture is a dragging one. + * + * @param event The event with the pointer data. + * @return True if the gesture is a dragging one. + */ + private boolean isDraggingGesture(MotionEvent event) { + PointerTracker pointerTracker = mPointerTracker; + int[] pointerIds = mTempPointerIds; + pointerTracker.populateActivePointerIds(pointerIds); + + final int firstPtrIndex = event.findPointerIndex(pointerIds[0]); + final int secondPtrIndex = event.findPointerIndex(pointerIds[1]); + + final float firstPtrX = event.getX(firstPtrIndex); + final float firstPtrY = event.getY(firstPtrIndex); + final float secondPtrX = event.getX(secondPtrIndex); + final float secondPtrY = event.getY(secondPtrIndex); + + // Check if the pointers are close enough. + final float deltaX = firstPtrX - secondPtrX; + final float deltaY = firstPtrY - secondPtrY; + final float deltaMove = (float) Math.hypot(deltaX, deltaY); + if (deltaMove > mDraggingDistance) { + return false; + } + + // Check if the pointers are moving in the same direction. + final float firstDeltaX = + firstPtrX - pointerTracker.getReceivedPointerDownX(firstPtrIndex); + final float firstDeltaY = + firstPtrY - pointerTracker.getReceivedPointerDownY(firstPtrIndex); + final float firstMagnitude = + (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY); + final float firstXNormalized = + (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX; + final float firstYNormalized = + (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY; + + final float secondDeltaX = + secondPtrX - pointerTracker.getReceivedPointerDownX(secondPtrIndex); + final float secondDeltaY = + secondPtrY - pointerTracker.getReceivedPointerDownY(secondPtrIndex); + final float secondMagnitude = + (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY); + final float secondXNormalized = + (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX; + final float secondYNormalized = + (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY; + + final float angleCos = + firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized; + + if (angleCos < MIN_ANGLE_COS) { + return false; + } + + return true; + } + + /** + * Sends an event announcing the start/end of a touch exploration gesture. + * + * @param eventType The type of the event to send. + */ + private void sendAccessibilityEvent(int eventType) { + AccessibilityEvent event = AccessibilityEvent.obtain(eventType); + event.setPackageName(mContext.getPackageName()); + event.setClassName(getClass().getName()); + mAccessibilityManager.sendAccessibilityEvent(event); + } + + /** + * Sends a motion event to the input filter for injection. + * + * @param event The event to send. + * @param policyFlags The policy flags associated with the event. + */ + private void sendMotionEvent(MotionEvent event, int policyFlags) { + if (DEBUG) { + Slog.d(LOG_TAG_INJECTED, "Injecting event: " + event + ", policyFlags=0x" + + Integer.toHexString(policyFlags)); + } + // Make sure that the user will see the event. + policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; + mPointerTracker.onInjectedMotionEvent(event); + mInputFilter.sendInputEvent(event, policyFlags); + } + + /** + * Clears the internal state of this explorer. + */ + private void clear() { + mSendHoverDelayed.remove(); + mPointerTracker.clear(); + mLastTouchExploreEvent = null; + mCurrentState = STATE_TOUCH_EXPLORING; + mTouchExploreGestureInProgress = false; + mDraggingPointerId = INVALID_POINTER_ID; + } + + /** + * Helper class for tracking pointers and more specifically which of + * them are currently down, which are active, and which are delivered + * to the view hierarchy. The enclosing {@link TouchExplorer} uses the + * pointer state reported by this class to perform touch exploration. + * <p> + * The main purpose of this class is to allow the touch explorer to + * disregard pointers put down by accident by the user and not being + * involved in the interaction. For example, a blind user grabs the + * device with her left hand such that she touches the screen and she + * uses her right hand's index finger to explore the screen content. + * In this scenario the touches generated by the left hand are to be + * ignored. + */ + class PointerTracker { + private static final String LOG_TAG = "PointerTracker"; + + // The coefficient by which to multiply + // ViewConfiguration.#getScaledTouchSlop() + // to compute #mThresholdActivePointer. + private static final int COEFFICIENT_ACTIVE_POINTER = 2; + + // Pointers that moved less than mThresholdActivePointer + // are considered active i.e. are ignored. + private final double mThresholdActivePointer; + + // Keep track of where and when a pointer went down. + private final float[] mReceivedPointerDownX = new float[MAX_POINTER_COUNT]; + private final float[] mReceivedPointerDownY = new float[MAX_POINTER_COUNT]; + private final long[] mReceivedPointerDownTime = new long[MAX_POINTER_COUNT]; + + // Which pointers are down. + private int mReceivedPointersDown; + + // Which down pointers are active. + private int mActivePointers; + + // Primary active pointer which is either the first that went down + // or if it goes up the next active that most recently went down. + private int mPrimaryActivePointerId; + + // Flag indicating that there is at least one active pointer moving. + private boolean mHasMovingActivePointer; + + // Keep track of which pointers sent to the system are down. + private int mInjectedPointersDown; + + // Keep track of the last up pointer data. + private float mLastReceivedUpPointerDownX; + private float mLastReveivedUpPointerDownY; + private long mLastReceivedUpPointerDownTime; + private int mLastReceivedUpPointerId; + private boolean mLastReceivedUpPointerActive; + + // The time of the last injected down. + private long mLastInjectedDownEventTime; + + // The action of the last injected hover event. + private int mLastInjectedHoverEventAction = MotionEvent.ACTION_HOVER_EXIT; + + /** + * Creates a new instance. + * + * @param context Context for looking up resources. + */ + public PointerTracker(Context context) { + mThresholdActivePointer = + ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER; + } + + /** + * Clears the internals state. + */ + public void clear() { + Arrays.fill(mReceivedPointerDownX, 0); + Arrays.fill(mReceivedPointerDownY, 0); + Arrays.fill(mReceivedPointerDownTime, 0); + mReceivedPointersDown = 0; + mActivePointers = 0; + mPrimaryActivePointerId = 0; + mHasMovingActivePointer = false; + mInjectedPointersDown = 0; + mLastReceivedUpPointerDownX = 0; + mLastReveivedUpPointerDownY = 0; + mLastReceivedUpPointerDownTime = 0; + mLastReceivedUpPointerId = 0; + mLastReceivedUpPointerActive = false; + } + + /** + * Processes a received {@link MotionEvent} event. + * + * @param event The event to process. + */ + public void onReceivedMotionEvent(MotionEvent event) { + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: { + // New gesture so restart tracking injected down pointers. + mInjectedPointersDown = 0; + handleReceivedPointerDown(0, event); + } break; + case MotionEvent.ACTION_POINTER_DOWN: { + handleReceivedPointerDown(event.getActionIndex(), event); + } break; + case MotionEvent.ACTION_MOVE: { + handleReceivedPointerMove(event); + } break; + case MotionEvent.ACTION_UP: { + handleReceivedPointerUp(0, event); + } break; + case MotionEvent.ACTION_POINTER_UP: { + handleReceivedPointerUp(event.getActionIndex(), event); + } break; + } + if (DEBUG) { + Slog.i(LOG_TAG, "Received pointer: " + toString()); + } + } + + /** + * Processes an injected {@link MotionEvent} event. + * + * @param event The event to process. + */ + public void onInjectedMotionEvent(MotionEvent event) { + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: { + handleInjectedPointerDown(0, event); + } break; + case MotionEvent.ACTION_POINTER_DOWN: { + handleInjectedPointerDown(event.getActionIndex(), event); + } break; + case MotionEvent.ACTION_UP: { + handleInjectedPointerUp(0, event); + } break; + case MotionEvent.ACTION_POINTER_UP: { + handleInjectedPointerUp(event.getActionIndex(), event); + } break; + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + case MotionEvent.ACTION_HOVER_EXIT: { + mLastInjectedHoverEventAction = event.getActionMasked(); + } break; + } + if (DEBUG) { + Slog.i(LOG_TAG, "Injected pointer: " + toString()); + } + } + + /** + * @return The number of received pointers that are down. + */ + public int getReceivedPointerDownCount() { + return Integer.bitCount(mReceivedPointersDown); + } + + /** + * @return The number of down input pointers that are active. + */ + public int getActivePointerCount() { + return Integer.bitCount(mActivePointers); + } + + /** + * Whether an received pointer is down. + * + * @param pointerId The unique pointer id. + * @return True if the pointer is down. + */ + public boolean isReceivedPointerDown(int pointerId) { + final int pointerFlag = (1 << pointerId); + return (mReceivedPointersDown & pointerFlag) != 0; + } + + /** + * Whether an injected pointer is down. + * + * @param pointerId The unique pointer id. + * @return True if the pointer is down. + */ + public boolean isInjectedPointerDown(int pointerId) { + final int pointerFlag = (1 << pointerId); + return (mInjectedPointersDown & pointerFlag) != 0; + } + + /** + * @return The number of down pointers injected to the view hierarchy. + */ + public int getInjectedPointerDownCount() { + return Integer.bitCount(mInjectedPointersDown); + } + + /** + * Whether an input pointer is active. + * + * @param pointerId The unique pointer id. + * @return True if the pointer is active. + */ + public boolean isActivePointer(int pointerId) { + final int pointerFlag = (1 << pointerId); + return (mActivePointers & pointerFlag) != 0; + } + + /** + * @param pointerId The unique pointer id. + * @return The X coordinate where the pointer went down. + */ + public float getReceivedPointerDownX(int pointerId) { + return mReceivedPointerDownX[pointerId]; + } + + /** + * @param pointerId The unique pointer id. + * @return The Y coordinate where the pointer went down. + */ + public float getReceivedPointerDownY(int pointerId) { + return mReceivedPointerDownY[pointerId]; + } + + /** + * @param pointerId The unique pointer id. + * @return The time when the pointer went down. + */ + public long getReceivedPointerDownTime(int pointerId) { + return mReceivedPointerDownTime[pointerId]; + } + + /** + * @return The id of the primary pointer. + */ + public int getPrimaryActivePointerId() { + if (mPrimaryActivePointerId == INVALID_POINTER_ID) { + mPrimaryActivePointerId = findPrimaryActivePointer(); + } + return mPrimaryActivePointerId; + } + + /** + * @return The X coordinate where the last up received pointer went down. + */ + public float getLastReceivedUpPointerDownX() { + return mLastReceivedUpPointerDownX; + } + + /** + * @return The Y coordinate where the last up received pointer went down. + */ + public float getLastReceivedUpPointerDownY() { + return mLastReveivedUpPointerDownY; + } + + /** + * @return The time when the last up received pointer went down. + */ + public long getLastReceivedUpPointerDownTime() { + return mLastReceivedUpPointerDownTime; + } + + /** + * @return The id of the last received pointer that went up. + */ + public int getLastReceivedUpPointerId() { + return mLastReceivedUpPointerId; + } + + /** + * @return Whether the last received pointer that went up was active. + */ + public boolean wasLastReceivedUpPointerActive() { + return mLastReceivedUpPointerActive; + } + + /** + * @return The time of the last injected down event. + */ + public long getLastInjectedDownEventTime() { + return mLastInjectedDownEventTime; + } + + /** + * @return The action of the last injected hover event. + */ + public int getLastInjectedHoverAction() { + return mLastInjectedHoverEventAction; + } + + /** + * Populates the active pointer IDs to the given array. + * <p> + * Note: The client is responsible for providing large enough array. + * + * @param outPointerIds The array to which to write the active pointers. + */ + public void populateActivePointerIds(int[] outPointerIds) { + int index = 0; + for (int idBits = mActivePointers; idBits != 0; ) { + final int id = Integer.numberOfTrailingZeros(idBits); + idBits &= ~(1 << id); + outPointerIds[index] = id; + index++; + } + } + + /** + * @return The number of non injected active pointers. + */ + public int getNotInjectedActivePointerCount() { + final int pointerState = mActivePointers & ~mInjectedPointersDown; + return Integer.bitCount(pointerState); + } + + /** + * @param pointerId The unique pointer id. + * @return Whether the pointer is active or was the last active than went up. + */ + private boolean isActiveOrWasLastActiveUpPointer(int pointerId) { + return (isActivePointer(pointerId) + || (mLastReceivedUpPointerId == pointerId + && mLastReceivedUpPointerActive)); + } + + /** + * Handles a received pointer down event. + * + * @param pointerIndex The index of the pointer that has changed. + * @param event The event to be handled. + */ + private void handleReceivedPointerDown(int pointerIndex, MotionEvent event) { + final int pointerId = event.getPointerId(pointerIndex); + final int pointerFlag = (1 << pointerId); + + mLastReceivedUpPointerId = 0; + mLastReceivedUpPointerDownX = 0; + mLastReveivedUpPointerDownY = 0; + mLastReceivedUpPointerDownTime = 0; + mLastReceivedUpPointerActive = false; + + mReceivedPointersDown |= pointerFlag; + mReceivedPointerDownX[pointerId] = event.getX(pointerIndex); + mReceivedPointerDownY[pointerId] = event.getY(pointerIndex); + mReceivedPointerDownTime[pointerId] = event.getEventTime(); + + if (!mHasMovingActivePointer) { + // If still no moving active pointers every + // down pointer is the only active one. + mActivePointers = pointerFlag; + mPrimaryActivePointerId = pointerId; + } else { + // If at least one moving active pointer every + // subsequent down pointer is active. + mActivePointers |= pointerFlag; + } + } + + /** + * Handles a received pointer move event. + * + * @param event The event to be handled. + */ + private void handleReceivedPointerMove(MotionEvent event) { + detectActivePointers(event); + } + + /** + * Handles a received pointer up event. + * + * @param pointerIndex The index of the pointer that has changed. + * @param event The event to be handled. + */ + private void handleReceivedPointerUp(int pointerIndex, MotionEvent event) { + final int pointerId = event.getPointerId(pointerIndex); + final int pointerFlag = (1 << pointerId); + + mLastReceivedUpPointerId = pointerId; + mLastReceivedUpPointerDownX = getReceivedPointerDownX(pointerId); + mLastReveivedUpPointerDownY = getReceivedPointerDownY(pointerId); + mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId); + mLastReceivedUpPointerActive = isActivePointer(pointerId); + + mReceivedPointersDown &= ~pointerFlag; + mActivePointers &= ~pointerFlag; + mReceivedPointerDownX[pointerId] = 0; + mReceivedPointerDownY[pointerId] = 0; + mReceivedPointerDownTime[pointerId] = 0; + + if (mActivePointers == 0) { + mHasMovingActivePointer = false; + } + if (mPrimaryActivePointerId == pointerId) { + mPrimaryActivePointerId = INVALID_POINTER_ID; + } + } + + /** + * Handles a injected pointer down event. + * + * @param pointerIndex The index of the pointer that has changed. + * @param event The event to be handled. + */ + private void handleInjectedPointerDown(int pointerIndex, MotionEvent event) { + final int pointerId = event.getPointerId(pointerIndex); + final int pointerFlag = (1 << pointerId); + mInjectedPointersDown |= pointerFlag; + mLastInjectedDownEventTime = event.getEventTime(); + } + + /** + * Handles a injected pointer up event. + * + * @param pointerIndex The index of the pointer that has changed. + * @param event The event to be handled. + */ + private void handleInjectedPointerUp(int pointerIndex, MotionEvent event) { + final int pointerId = event.getPointerId(pointerIndex); + final int pointerFlag = (1 << pointerId); + mInjectedPointersDown &= ~pointerFlag; + } + + /** + * Detects the active pointers in an event. + * + * @param event The event to examine. + */ + private void detectActivePointers(MotionEvent event) { + for (int i = 0, count = event.getPointerCount(); i < count; i++) { + final int pointerId = event.getPointerId(i); + if (mHasMovingActivePointer) { + // If already active => nothing to do. + if (isActivePointer(pointerId)) { + continue; + } + } + // Active pointers are ones that moved more than a given threshold. + final float pointerDeltaMove = computePointerDeltaMove(i, event); + if (pointerDeltaMove > mThresholdActivePointer) { + final int pointerFlag = (1 << pointerId); + mActivePointers |= pointerFlag; + mHasMovingActivePointer = true; + } + } + } + + /** + * @return The primary active pointer. + */ + private int findPrimaryActivePointer() { + int primaryActivePointerId = INVALID_POINTER_ID; + long minDownTime = Long.MAX_VALUE; + // Find the active pointer that went down first. + for (int i = 0, count = mReceivedPointerDownTime.length; i < count; i++) { + if (isActivePointer(i)) { + final long downPointerTime = mReceivedPointerDownTime[i]; + if (downPointerTime < minDownTime) { + minDownTime = downPointerTime; + primaryActivePointerId = i; + } + } + } + return primaryActivePointerId; + } + + /** + * Computes the move for a given action pointer index since the + * corresponding pointer went down. + * + * @param pointerIndex The action pointer index. + * @param event The event to examine. + * @return The distance the pointer has moved. + */ + private float computePointerDeltaMove(int pointerIndex, MotionEvent event) { + final int pointerId = event.getPointerId(pointerIndex); + final float deltaX = event.getX(pointerIndex) - mReceivedPointerDownX[pointerId]; + final float deltaY = event.getY(pointerIndex) - mReceivedPointerDownY[pointerId]; + return (float) Math.hypot(deltaX, deltaY); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("========================="); + builder.append("\nDown pointers #"); + builder.append(getReceivedPointerDownCount()); + builder.append(" [ "); + for (int i = 0; i < MAX_POINTER_COUNT; i++) { + if (isReceivedPointerDown(i)) { + builder.append(i); + builder.append(" "); + } + } + builder.append("]"); + builder.append("\nActive pointers #"); + builder.append(getActivePointerCount()); + builder.append(" [ "); + for (int i = 0; i < MAX_POINTER_COUNT; i++) { + if (isActivePointer(i)) { + builder.append(i); + builder.append(" "); + } + } + builder.append("]"); + builder.append("\nPrimary active pointer id [ "); + builder.append(getPrimaryActivePointerId()); + builder.append(" ]"); + builder.append("\n========================="); + return builder.toString(); + } + } + + /** + * Class for delayed sending of hover events. + */ + private final class SendHoverDelayed implements Runnable { + private static final String LOG_TAG = "SendHoverEnterOrExitDelayed"; + + private MotionEvent mEvent; + private int mAction; + private int mPointerIndex; + private int mPolicyFlags; + + public void post(MotionEvent prototype, int action, int pointerIndex, int policyFlags, + long delay) { + remove(); + mEvent = MotionEvent.obtain(prototype); + mAction = action; + mPointerIndex = pointerIndex; + mPolicyFlags = policyFlags; + mHandler.postDelayed(this, delay); + } + + public void remove() { + mHandler.removeCallbacks(this); + clear(); + } + + private boolean isPenidng() { + return (mEvent != null); + } + + private void clear() { + if (!isPenidng()) { + return; + } + mEvent.recycle(); + mEvent = null; + mAction = 0; + mPointerIndex = -1; + mPolicyFlags = 0; + } + + public void forceSendAndRemove() { + if (isPenidng()) { + run(); + remove(); + } + } + + public void run() { + if (DEBUG) { + if (mAction == MotionEvent.ACTION_HOVER_ENTER) { + Slog.d(LOG_TAG, "Injecting: " + MotionEvent.ACTION_HOVER_ENTER); + } else if (mAction == MotionEvent.ACTION_HOVER_MOVE) { + Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_MOVE"); + } else if (mAction == MotionEvent.ACTION_HOVER_EXIT) { + Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_EXIT"); + } + } + + sendHoverEvent(mEvent, mAction, mPointerIndex, mPolicyFlags); + clear(); + } + } +} diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java index 084ac6f..220c7fb 100644 --- a/services/java/com/android/server/wm/DimSurface.java +++ b/services/java/com/android/server/wm/DimSurface.java @@ -89,7 +89,7 @@ class DimSurface { public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mDimSurface="); pw.println(mDimSurface); pw.print(prefix); pw.print("mDimShown="); pw.print(mDimShown); - pw.print(" mLayer="); pw.println(mLayer); + pw.print(" mLayer="); pw.print(mLayer); pw.print(" mDimColor=0x"); pw.println(Integer.toHexString(mDimColor)); pw.print(prefix); pw.print("mLastDimWidth="); pw.print(mLastDimWidth); pw.print(" mLastDimWidth="); pw.println(mLastDimWidth); diff --git a/services/java/com/android/server/wm/InputFilter.java b/services/java/com/android/server/wm/InputFilter.java index 7e1ab07..8f0001a 100644 --- a/services/java/com/android/server/wm/InputFilter.java +++ b/services/java/com/android/server/wm/InputFilter.java @@ -105,11 +105,13 @@ public abstract class InputFilter { private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier = InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, - InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT) : null; + InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, + "InputFilter#InboundInputEventConsistencyVerifier") : null; private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier = InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, - InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT) : null; + InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, + "InputFilter#OutboundInputEventConsistencyVerifier") : null; /** * Creates the input filter. diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index b2e78f1..8b739a4 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -398,6 +398,7 @@ public class WindowManagerService extends IWindowManager.Stub int mRotation = 0; int mRequestedRotation = 0; int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + boolean mAltOrientation = false; int mLastRotationFlags; ArrayList<IRotationWatcher> mRotationWatchers = new ArrayList<IRotationWatcher>(); @@ -585,7 +586,6 @@ public class WindowManagerService extends IWindowManager.Stub } final Configuration mTempConfiguration = new Configuration(); - int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED; // The frame use to limit the size of the app running in compatibility mode. Rect mCompatibleScreenFrame = new Rect(); @@ -4954,7 +4954,52 @@ public class WindowManagerService extends IWindowManager.Stub rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation, mDisplayEnabled); if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation); + + int desiredRotation = rotation; + int lockedRotation = mPolicy.getLockedRotationLw(); + if (lockedRotation >= 0 && rotation != lockedRotation) { + // We are locked in a rotation but something is requesting + // a different rotation... we will either keep the locked + // rotation if it results in the same orientation, or have to + // switch into an emulated orientation mode. + + // First, we know that our rotation is actually going to be + // the locked rotation. + rotation = lockedRotation; + + // Now the difference between the desired and lockedRotation + // may mean that the orientation is different... if that is + // not the case, we can just make the desired rotation be the + // same as the new locked rotation. + switch (lockedRotation) { + case Surface.ROTATION_0: + if (rotation == Surface.ROTATION_180) { + desiredRotation = lockedRotation; + } + break; + case Surface.ROTATION_90: + if (rotation == Surface.ROTATION_270) { + desiredRotation = lockedRotation; + } + break; + case Surface.ROTATION_180: + if (rotation == Surface.ROTATION_0) { + desiredRotation = lockedRotation; + } + break; + case Surface.ROTATION_270: + if (rotation == Surface.ROTATION_90) { + desiredRotation = lockedRotation; + } + break; + } + } + changed = mDisplayEnabled && mRotation != rotation; + if (mAltOrientation != (rotation != desiredRotation)) { + changed = true; + mAltOrientation = rotation != desiredRotation; + } if (changed) { if (DEBUG_ORIENTATION) Slog.v(TAG, @@ -5000,6 +5045,7 @@ public class WindowManagerService extends IWindowManager.Stub Surface.setOrientation(0, rotation, animFlags); } } + for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); if (w.mSurface != null) { @@ -5440,8 +5486,32 @@ public class WindowManagerService extends IWindowManager.Stub // Use the effective "visual" dimensions based on current rotation final boolean rotated = (mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270); - final int dw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth; - final int dh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight; + final int realdw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth; + final int realdh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight; + + if (mAltOrientation) { + mCurDisplayWidth = realdw; + mCurDisplayHeight = realdh; + if (realdw > realdh) { + // Turn landscape into portrait. + int maxw = (int)(realdh/1.3f); + if (maxw < realdw) { + mCurDisplayWidth = maxw; + } + } else { + // Turn portrait into landscape. + int maxh = (int)(realdw/1.3f); + if (maxh < realdh) { + mCurDisplayHeight = maxh; + } + } + } else { + mCurDisplayWidth = realdw; + mCurDisplayHeight = realdh; + } + + final int dw = mCurDisplayWidth; + final int dh = mCurDisplayHeight; int orientation = Configuration.ORIENTATION_SQUARE; if (dw < dh) { @@ -5452,66 +5522,69 @@ public class WindowManagerService extends IWindowManager.Stub config.orientation = orientation; DisplayMetrics dm = new DisplayMetrics(); - mDisplay.getMetrics(dm); + mDisplay.getRealMetrics(dm); + + // Override display width and height with what we are computing, + // to be sure they remain consistent. + dm.widthPixels = dw; + dm.heightPixels = dh; + CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame); config.screenWidthDp = (int)(dm.widthPixels / dm.density); config.screenHeightDp = (int)(dm.heightPixels / dm.density); - if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) { - // Note we only do this once because at this point we don't - // expect the screen to change in this way at runtime, and want - // to avoid all of this computation for every config change. - int longSize = dw; - int shortSize = dh; - if (longSize < shortSize) { - int tmp = longSize; - longSize = shortSize; - shortSize = tmp; - } - longSize = (int)(longSize/dm.density); - shortSize = (int)(shortSize/dm.density); - - // These semi-magic numbers define our compatibility modes for - // applications with different screens. These are guarantees to - // app developers about the space they can expect for a particular - // configuration. DO NOT CHANGE! - if (longSize < 470) { - // This is shorter than an HVGA normal density screen (which - // is 480 pixels on its long side). - mScreenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL - | Configuration.SCREENLAYOUT_LONG_NO; + // Compute the screen layout size class. + int screenLayout; + int longSize = dw; + int shortSize = dh; + if (longSize < shortSize) { + int tmp = longSize; + longSize = shortSize; + shortSize = tmp; + } + longSize = (int)(longSize/dm.density); + shortSize = (int)(shortSize/dm.density); + + // These semi-magic numbers define our compatibility modes for + // applications with different screens. These are guarantees to + // app developers about the space they can expect for a particular + // configuration. DO NOT CHANGE! + if (longSize < 470) { + // This is shorter than an HVGA normal density screen (which + // is 480 pixels on its long side). + screenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL + | Configuration.SCREENLAYOUT_LONG_NO; + } else { + // What size is this screen screen? + if (longSize >= 960 && shortSize >= 720) { + // 1.5xVGA or larger screens at medium density are the point + // at which we consider it to be an extra large screen. + screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE; + } else if (longSize >= 640 && shortSize >= 480) { + // VGA or larger screens at medium density are the point + // at which we consider it to be a large screen. + screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE; } else { - // What size is this screen screen? - if (longSize >= 960 && shortSize >= 720) { - // 1.5xVGA or larger screens at medium density are the point - // at which we consider it to be an extra large screen. - mScreenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE; - } else if (longSize >= 640 && shortSize >= 480) { - // VGA or larger screens at medium density are the point - // at which we consider it to be a large screen. - mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE; - } else { - mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL; - } - - // If this screen is wider than normal HVGA, or taller - // than FWVGA, then for old apps we want to run in size - // compatibility mode. - if (shortSize > 321 || longSize > 570) { - mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; - } + screenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL; + } - // Is this a long screen? - if (((longSize*3)/5) >= (shortSize-1)) { - // Anything wider than WVGA (5:3) is considering to be long. - mScreenLayout |= Configuration.SCREENLAYOUT_LONG_YES; - } else { - mScreenLayout |= Configuration.SCREENLAYOUT_LONG_NO; - } + // If this screen is wider than normal HVGA, or taller + // than FWVGA, then for old apps we want to run in size + // compatibility mode. + if (shortSize > 321 || longSize > 570) { + screenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; + } + + // Is this a long screen? + if (((longSize*3)/5) >= (shortSize-1)) { + // Anything wider than WVGA (5:3) is considering to be long. + screenLayout |= Configuration.SCREENLAYOUT_LONG_YES; + } else { + screenLayout |= Configuration.SCREENLAYOUT_LONG_NO; } } - config.screenLayout = mScreenLayout; + config.screenLayout = screenLayout; // Determine whether a hard keyboard is available and enabled. boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS; @@ -5853,6 +5926,7 @@ public class WindowManagerService extends IWindowManager.Stub mInitialDisplayWidth = mCurDisplayWidth = mDisplay.getRealWidth(); mInitialDisplayHeight = mCurDisplayHeight = mDisplay.getRealHeight(); mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight()); + mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight); } try { @@ -6721,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; @@ -8708,24 +8782,25 @@ 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.print(mDeferredRotationAnimFlags); + pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags); pw.print(" mAnimationPending="); pw.print(mAnimationPending); pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale); pw.print(" mNextAppTransition=0x"); pw.print(Integer.toHexString(mNextAppTransition)); - pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady); - pw.print(", mAppTransitionRunning="); pw.print(mAppTransitionRunning); - pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout); + pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady); + pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning); + pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout); if (mNextAppTransitionPackage != null) { pw.print(" mNextAppTransitionPackage="); pw.print(mNextAppTransitionPackage); - pw.print(", mNextAppTransitionEnter=0x"); + pw.print(" mNextAppTransitionEnter=0x"); pw.print(Integer.toHexString(mNextAppTransitionEnter)); - pw.print(", mNextAppTransitionExit=0x"); + pw.print(" mNextAppTransitionExit=0x"); pw.print(Integer.toHexString(mNextAppTransitionExit)); } pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2f3a144..7506f29 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1241,8 +1241,10 @@ int SurfaceFlinger::setOrientation(DisplayID dpy, return orientation; } -sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid, - const String8& name, ISurfaceComposerClient::surface_data_t* params, +sp<ISurface> SurfaceFlinger::createSurface( + ISurfaceComposerClient::surface_data_t* params, + const String8& name, + const sp<Client>& client, DisplayID d, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { @@ -2414,12 +2416,12 @@ ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const { return -1; } sp<ISurface> Client::createSurface( - ISurfaceComposerClient::surface_data_t* params, int pid, + ISurfaceComposerClient::surface_data_t* params, const String8& name, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { - return mFlinger->createSurface(this, pid, name, params, + return mFlinger->createSurface(params, name, this, display, w, h, format, flags); } status_t Client::destroySurface(SurfaceID sid) { @@ -2523,7 +2525,7 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const } sp<ISurface> UserClient::createSurface( - ISurfaceComposerClient::surface_data_t* params, int pid, + ISurfaceComposerClient::surface_data_t* params, const String8& name, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8d43157..1b36d1c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -75,7 +75,7 @@ private: virtual sp<IMemoryHeap> getControlBlock() const; virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const; virtual sp<ISurface> createSurface( - surface_data_t* params, int pid, const String8& name, + surface_data_t* params, const String8& name, DisplayID display, uint32_t w, uint32_t h,PixelFormat format, uint32_t flags); virtual status_t destroySurface(SurfaceID surfaceId); @@ -107,7 +107,7 @@ private: virtual sp<IMemoryHeap> getControlBlock() const; virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const; virtual sp<ISurface> createSurface( - surface_data_t* params, int pid, const String8& name, + surface_data_t* params, const String8& name, DisplayID display, uint32_t w, uint32_t h,PixelFormat format, uint32_t flags); virtual status_t destroySurface(SurfaceID surfaceId); @@ -232,9 +232,10 @@ private: friend class Layer; friend class LayerDim; - sp<ISurface> createSurface(const sp<Client>& client, - int pid, const String8& name, + sp<ISurface> createSurface( ISurfaceComposerClient::surface_data_t* params, + const String8& name, + const sp<Client>& client, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); diff --git a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml index 69a33bc..174cc65 100644 --- a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml +++ b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml @@ -2,10 +2,10 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.rs.image"> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-sdk android:minSdkVersion="11" /> - <application android:label="Image Processing"> + <application android:label="Image Processing" + android:hardwareAccelerated="true"> <activity android:name="ImageProcessingActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg Binary files differdeleted file mode 100644 index 81a87b1..0000000 --- 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 0000000..856eeff --- /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 81a87b1..0000000 --- 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 b271b43..08a010d 100644 --- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml +++ b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml @@ -17,31 +17,12 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" - android:layout_height="fill_parent"> + android:layout_height="fill_parent" + android:id="@+id/toplevel"> <SurfaceView android:id="@+id/surface" android:layout_width="1dip" android:layout_height="1dip" /> - <ImageView - android:id="@+id/display" - android:layout_width="320dip" - android:layout_height="266dip" /> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> - <Button - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/benchmark" - android:onClick="benchmark"/> - <TextView - android:id="@+id/benchmarkText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textSize="8pt" - android:text="@string/saturation"/> - </LinearLayout> <ScrollView android:layout_width="fill_parent" android:layout_height="fill_parent"> @@ -49,6 +30,26 @@ android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> + <ImageView + android:id="@+id/display" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/benchmark" + android:onClick="benchmark"/> + <TextView + android:id="@+id/benchmarkText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="8pt" + android:text="@string/saturation"/> + </LinearLayout> <TextView android:id="@+id/inSaturationText" android:layout_width="match_parent" diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java index 4f2f52ab..7462701 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java @@ -40,7 +40,6 @@ public class ImageProcessingActivity extends Activity SeekBar.OnSeekBarChangeListener { private Bitmap mBitmapIn; private Bitmap mBitmapOut; - private Bitmap mBitmapScratch; private ScriptC_threshold mScript; private ScriptC_vertical_blur mScriptVBlur; private ScriptC_horizontal_blur mScriptHBlur; @@ -78,9 +77,20 @@ public class ImageProcessingActivity extends Activity private SurfaceView mSurfaceView; private ImageView mDisplayView; + private boolean mIsProcessing; + class FilterCallback extends RenderScript.RSMessageHandler { private Runnable mAction = new Runnable() { public void run() { + + synchronized (mDisplayView) { + mIsProcessing = false; + } + + // This is a hack to work around an invalidation bug + mBitmapOut = Bitmap.createBitmap(mBitmapOut); + mOutPixelsAllocation.copyTo(mBitmapOut); + mDisplayView.setImageBitmap(mBitmapOut); mDisplayView.invalidate(); } }; @@ -99,156 +109,6 @@ public class ImageProcessingActivity extends Activity // Store our coefficients here float gaussian[]; - private long javaFilter() { - final int width = mBitmapIn.getWidth(); - final int height = mBitmapIn.getHeight(); - final int count = width * height; - - if (in == null) { - in = new int[count]; - interm = new int[count]; - out = new int[count]; - gaussian = new float[MAX_RADIUS * 2 + 1]; - mBitmapIn.getPixels(in, 0, width, 0, 0, width, height); - } - - long t = java.lang.System.currentTimeMillis(); - - int w, h, r; - - float fRadius = (float)mRadius; - int radius = (int)mRadius; - - // Compute gaussian weights for the blur - // e is the euler's number - float e = 2.718281828459045f; - float pi = 3.1415926535897932f; - // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) - // x is of the form [-radius .. 0 .. radius] - // and sigma varies with radius. - // Based on some experimental radius values and sigma's - // we approximately fit sigma = f(radius) as - // sigma = radius * 0.4 + 0.6 - // The larger the radius gets, the more our gaussian blur - // will resemble a box blur since with large sigma - // the gaussian curve begins to lose its shape - float sigma = 0.4f * fRadius + 0.6f; - // Now compute the coefficints - // We will store some redundant values to save some math during - // the blur calculations - // precompute some values - float coeff1 = 1.0f / (float)(Math.sqrt( 2.0f * pi ) * sigma); - float coeff2 = - 1.0f / (2.0f * sigma * sigma); - float normalizeFactor = 0.0f; - float floatR = 0.0f; - for (r = -radius; r <= radius; r ++) { - floatR = (float)r; - gaussian[r + radius] = coeff1 * (float)Math.pow(e, floatR * floatR * coeff2); - normalizeFactor += gaussian[r + radius]; - } - - //Now we need to normalize the weights because all our coefficients need to add up to one - normalizeFactor = 1.0f / normalizeFactor; - for (r = -radius; r <= radius; r ++) { - floatR = (float)r; - gaussian[r + radius] *= normalizeFactor; - } - - float blurredPixelR = 0.0f; - float blurredPixelG = 0.0f; - float blurredPixelB = 0.0f; - float blurredPixelA = 0.0f; - - for (h = 0; h < height; h ++) { - for (w = 0; w < width; w ++) { - - blurredPixelR = 0.0f; - blurredPixelG = 0.0f; - blurredPixelB = 0.0f; - blurredPixelA = 0.0f; - - for (r = -radius; r <= radius; r ++) { - // Stepping left and right away from the pixel - int validW = w + r; - // Clamp to zero and width max() isn't exposed for ints yet - if (validW < 0) { - validW = 0; - } - if (validW > width - 1) { - validW = width - 1; - } - - int input = in[h*width + validW]; - - int R = ((input >> 24) & 0xff); - int G = ((input >> 16) & 0xff); - int B = ((input >> 8) & 0xff); - int A = (input & 0xff); - - float weight = gaussian[r + radius]; - - blurredPixelR += (float)(R)*weight; - blurredPixelG += (float)(G)*weight; - blurredPixelB += (float)(B)*weight; - blurredPixelA += (float)(A)*weight; - } - - int R = (int)blurredPixelR; - int G = (int)blurredPixelG; - int B = (int)blurredPixelB; - int A = (int)blurredPixelA; - - interm[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A); - } - } - - for (h = 0; h < height; h ++) { - for (w = 0; w < width; w ++) { - - blurredPixelR = 0.0f; - blurredPixelG = 0.0f; - blurredPixelB = 0.0f; - blurredPixelA = 0.0f; - for (r = -radius; r <= radius; r ++) { - int validH = h + r; - // Clamp to zero and width - if (validH < 0) { - validH = 0; - } - if (validH > height - 1) { - validH = height - 1; - } - - int input = interm[validH*width + w]; - - int R = ((input >> 24) & 0xff); - int G = ((input >> 16) & 0xff); - int B = ((input >> 8) & 0xff); - int A = (input & 0xff); - - float weight = gaussian[r + radius]; - - blurredPixelR += (float)(R)*weight; - blurredPixelG += (float)(G)*weight; - blurredPixelB += (float)(B)*weight; - blurredPixelA += (float)(A)*weight; - } - - int R = (int)blurredPixelR; - int G = (int)blurredPixelG; - int B = (int)blurredPixelB; - int A = (int)blurredPixelA; - - out[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A); - } - } - - t = java.lang.System.currentTimeMillis() - t; - android.util.Log.v("Img", "Java frame time ms " + t); - mBitmapOut.setPixels(out, 0, width, 0, 0, width, height); - return t; - } - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { @@ -280,17 +140,14 @@ public class ImageProcessingActivity extends Activity mScriptVBlur.invoke_setSaturation(mSaturation); } - long t = java.lang.System.currentTimeMillis(); - if (true) { - mScript.invoke_filter(); - mOutPixelsAllocation.copyTo(mBitmapOut); - } else { - javaFilter(); - mDisplayView.invalidate(); + synchronized (mDisplayView) { + if (mIsProcessing) { + return; + } + mIsProcessing = true; } - t = java.lang.System.currentTimeMillis() - t; - android.util.Log.v("Img", "Renderscript frame time core ms " + t); + mScript.invoke_filter(); } } @@ -305,9 +162,8 @@ public class ImageProcessingActivity extends Activity super.onCreate(savedInstanceState); setContentView(R.layout.main); - mBitmapIn = loadBitmap(R.drawable.data); - mBitmapOut = loadBitmap(R.drawable.data); - mBitmapScratch = loadBitmap(R.drawable.data); + mBitmapIn = loadBitmap(R.drawable.city); + mBitmapOut = loadBitmap(R.drawable.city); mSurfaceView = (SurfaceView) findViewById(R.id.surface); mSurfaceView.getHolder().addCallback(this); diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs index 652ffd7..45eea5e 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs @@ -19,7 +19,7 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32 } else { for (int r = -fs->radius; r <= fs->radius; r ++) { // Stepping left and right away from the pixel - int validW = rsClamp(x + r, (uint)0, (uint)(fs->width - 1)); + int validW = rsClamp((int)x + r, (int)0, (int)(fs->width - 1)); blurredPixel += input[validW].xyz * gPtr[0]; gPtr++; } diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs index bd4ae4e..6b0cde0 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs @@ -74,7 +74,7 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32 } } else { for (int r = -fs->radius; r <= fs->radius; r ++) { - int validH = rsClamp(y + r, (uint)0, (uint)(fs->height - 1)); + int validH = rsClamp((int)y + r, (int)0, (int)(fs->height - 1)); const float4 *i = input + validH * fs->width; blurredPixel += i->xyz * gPtr[0]; gPtr++; |