Merge "Enable IMEs to set additional subtypes in background"
diff --git a/api/current.txt b/api/current.txt
index 4d5a0fd..4997ae6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -207,6 +207,7 @@
field public static final int actionModeCutDrawable = 16843537; // 0x1010311
field public static final int actionModePasteDrawable = 16843539; // 0x1010313
field public static final int actionModeSelectAllDrawable = 16843647; // 0x101037f
+ field public static final int actionModeStyle = 16843688; // 0x10103a8
field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
field public static final int actionProviderClass = 16843677; // 0x101039d
field public static final int actionViewClass = 16843516; // 0x10102fc
@@ -1823,6 +1824,7 @@
method public static java.lang.String feedbackTypeToString(int);
method public static java.lang.String flagToString(int);
method public boolean getCanRetrieveWindowContent();
+ method public java.lang.String getDescription();
method public java.lang.String getId();
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
@@ -16702,6 +16704,7 @@
field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version";
+ field public static final java.lang.String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
field public static final java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country";
field public static final java.lang.String TTS_DEFAULT_LANG = "tts_default_lang";
field public static final java.lang.String TTS_DEFAULT_PITCH = "tts_default_pitch";
@@ -20492,6 +20495,14 @@
ctor public Base64OutputStream(java.io.OutputStream, int);
}
+ public final deprecated class Config {
+ field public static final deprecated boolean DEBUG = false;
+ field public static final deprecated boolean LOGD = true;
+ field public static final deprecated boolean LOGV = false;
+ field public static final deprecated boolean PROFILE = false;
+ field public static final deprecated boolean RELEASE = true;
+ }
+
public class DebugUtils {
method public static boolean isObjectSelected(java.lang.Object);
}
@@ -20731,11 +20742,12 @@
method public void set(T, V);
}
- public class SparseArray {
+ public class SparseArray implements java.lang.Cloneable {
ctor public SparseArray();
ctor public SparseArray(int);
method public void append(int, E);
method public void clear();
+ method public android.util.SparseArray<E> clone();
method public void delete(int);
method public E get(int);
method public E get(int, E);
@@ -20750,11 +20762,12 @@
method public E valueAt(int);
}
- public class SparseBooleanArray {
+ public class SparseBooleanArray implements java.lang.Cloneable {
ctor public SparseBooleanArray();
ctor public SparseBooleanArray(int);
method public void append(int, boolean);
method public void clear();
+ method public android.util.SparseBooleanArray clone();
method public void delete(int);
method public boolean get(int);
method public boolean get(int, boolean);
@@ -20766,11 +20779,12 @@
method public boolean valueAt(int);
}
- public class SparseIntArray {
+ public class SparseIntArray implements java.lang.Cloneable {
ctor public SparseIntArray();
ctor public SparseIntArray(int);
method public void append(int, int);
method public void clear();
+ method public android.util.SparseIntArray clone();
method public void delete(int);
method public int get(int);
method public int get(int, int);
@@ -20917,11 +20931,13 @@
method public abstract android.view.Menu getMenu();
method public abstract android.view.MenuInflater getMenuInflater();
method public abstract java.lang.CharSequence getSubtitle();
+ method public java.lang.Object getTag();
method public abstract java.lang.CharSequence getTitle();
method public abstract void invalidate();
method public abstract void setCustomView(android.view.View);
method public abstract void setSubtitle(java.lang.CharSequence);
method public abstract void setSubtitle(int);
+ method public void setTag(java.lang.Object);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract void setTitle(int);
}
@@ -22034,9 +22050,12 @@
method public android.graphics.SurfaceTexture getSurfaceTexture();
method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
method public boolean isAvailable();
+ method public android.graphics.Canvas lockCanvas();
+ method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
method protected final void onDraw(android.graphics.Canvas);
method public void setOpaque(boolean);
method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
+ method public void unlockCanvasAndPost(android.graphics.Canvas);
}
public static abstract interface TextureView.SurfaceTextureListener {
@@ -23265,6 +23284,7 @@
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
method public void interrupt();
method public boolean isEnabled();
+ method public boolean isTouchExplorationEnabled();
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
@@ -23301,6 +23321,7 @@
method public boolean isSelected();
method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
method public static android.view.accessibility.AccessibilityNodeInfo obtain();
+ method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
method public boolean performAction(int);
method public void recycle();
method public void setBoundsInParent(android.graphics.Rect);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dd1c275..b42f1c5 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -805,6 +805,7 @@
Vector<CodecCapabilities> results;
CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
true, // queryDecoders
+ false, // hwCodecOnly
&results), (status_t)OK);
for (size_t i = 0; i < results.size(); ++i) {
@@ -844,7 +845,12 @@
for (List<IOMX::ComponentInfo>::iterator it = list.begin();
it != list.end(); ++it) {
- printf("%s\n", (*it).mName.string());
+ printf("%s\t Roles: ", (*it).mName.string());
+ for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
+ itRoles != (*it).mRoles.end() ; ++itRoles) {
+ printf("%s\t", (*itRoles).string());
+ }
+ printf("\n");
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 5f40f25..a09607a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -171,6 +171,11 @@
private boolean mCanRetrieveWindowContent;
/**
+ * Description of the accessibility service.
+ */
+ private String mDescription;
+
+ /**
* Creates a new instance.
*/
public AccessibilityServiceInfo() {
@@ -240,6 +245,8 @@
mCanRetrieveWindowContent = asAttributes.getBoolean(
com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
false);
+ mDescription = asAttributes.getString(
+ com.android.internal.R.styleable.AccessibilityService_description);
asAttributes.recycle();
} catch (NameNotFoundException e) {
throw new XmlPullParserException( "Unable to create context for: "
@@ -313,6 +320,18 @@
}
/**
+ * Description of the accessibility service.
+ * <p>
+ * <strong>Statically set from
+ * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+ * </p>
+ * @return The description.
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
* {@inheritDoc}
*/
public int describeContents() {
@@ -329,6 +348,7 @@
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+ parcel.writeString(mDescription);
}
private void initFromParcel(Parcel parcel) {
@@ -341,6 +361,7 @@
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
mCanRetrieveWindowContent = (parcel.readInt() == 1);
+ mDescription = parcel.readString();
}
@Override
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 12a4dbb..06d18ec 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
/**
@@ -178,14 +179,17 @@
* the transition. The reason for this is that a further layout event should cause
* existing animations to stop where they are prior to starting new animations. So
* we cache all of the current animations in this map for possible cancellation on
- * another layout event.
+ * another layout event. LinkedHashMaps are used to preserve the order in which animations
+ * are inserted, so that we process events (such as setting up start values) in the same order.
*/
- private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentAppearingAnimations =
+ private final HashMap<View, Animator> pendingAnimations =
new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentDisappearingAnimations =
- new HashMap<View, Animator>();
+ private final LinkedHashMap<View, Animator> currentChangingAnimations =
+ new LinkedHashMap<View, Animator>();
+ private final LinkedHashMap<View, Animator> currentAppearingAnimations =
+ new LinkedHashMap<View, Animator>();
+ private final LinkedHashMap<View, Animator> currentDisappearingAnimations =
+ new LinkedHashMap<View, Animator>();
/**
* This hashmap is used to track the listeners that have been added to the children of
@@ -547,7 +551,7 @@
}
/**
- * This function sets up runs animations on all of the views that change during layout.
+ * This function sets up animations on all of the views that change during layout.
* For every child in the parent, we create a change animation of the appropriate
* type (appearing or disappearing) and ask it to populate its start values from its
* target view. We add layout listeners to all child views and listen for changes. For
@@ -821,24 +825,24 @@
*/
public void cancel() {
if (currentChangingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentChangingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.cancel();
}
currentChangingAnimations.clear();
}
if (currentAppearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentAppearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
currentAppearingAnimations.clear();
}
if (currentDisappearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
@@ -859,8 +863,8 @@
case CHANGE_APPEARING:
case CHANGE_DISAPPEARING:
if (currentChangingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentChangingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.cancel();
}
@@ -869,8 +873,8 @@
break;
case APPEARING:
if (currentAppearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentAppearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
@@ -879,8 +883,8 @@
break;
case DISAPPEARING:
if (currentDisappearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
@@ -1113,4 +1117,4 @@
View view, int transitionType);
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c6a746b..f6cd866 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -70,7 +70,7 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -3558,6 +3558,7 @@
}
final void handleTrimMemory(int level) {
+ WindowManagerImpl.getDefault().trimMemory(level);
}
private final void handleBindApplication(AppBindData data) {
@@ -4071,7 +4072,7 @@
sThreadLocal.set(this);
mSystemThread = system;
if (!system) {
- ViewAncestor.addFirstDrawHandler(new Runnable() {
+ ViewRootImpl.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
@@ -4101,7 +4102,7 @@
}
}
- ViewAncestor.addConfigCallback(new ComponentCallbacks() {
+ ViewRootImpl.addConfigCallback(new ComponentCallbacks() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
// We need to apply this change to the resources
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 42eda02..8e2d360 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -168,6 +168,7 @@
SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar);
searchBar.setSearchDialog(this);
mSearchView = (SearchView) findViewById(com.android.internal.R.id.search_view);
+ mSearchView.setIconified(false);
mSearchView.setOnCloseListener(mOnCloseListener);
mSearchView.setOnQueryTextListener(mOnQueryChangeListener);
mSearchView.setOnSuggestionListener(mOnSuggestionSelectionListener);
@@ -633,31 +634,6 @@
}
/**
- * Overrides the handling of the back key to move back to the previous
- * sources or dismiss the search dialog, instead of dismissing the input
- * method.
- */
- @Override
- public boolean dispatchKeyEventPreIme(KeyEvent event) {
- if (DBG)
- Log.d(LOG_TAG, "onKeyPreIme(" + event + ")");
- if (mSearchDialog != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- KeyEvent.DispatcherState state = getKeyDispatcherState();
- if (state != null) {
- if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
- state.startTracking(event, this);
- return true;
- } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()
- && state.isTracking(event)) {
- mSearchDialog.onBackPressed();
- return true;
- }
- }
- }
- return super.dispatchKeyEventPreIme(event);
- }
-
- /**
* Don't allow action modes in a SearchBar, it looks silly.
*/
@Override
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index c179b35..4c21d04 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -662,12 +662,6 @@
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("nothing to dump");
}
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- //Log.i("Service", "Finalizing Service: " + this);
- }
// ------------------ Internal API ------------------
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 7fd5a7d..8472b31 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -40,7 +40,7 @@
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -592,7 +592,7 @@
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
@@ -630,7 +630,7 @@
int x, int y, int z, Bundle extras) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+ ViewRootImpl.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
windowToken, action, x, y, z, extras, false);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
@@ -650,7 +650,7 @@
*/
public void clearWallpaperOffsets(IBinder windowToken) {
try {
- ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, -1, -1, -1, -1);
} catch (RemoteException e) {
// Ignore.
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index a2af558..0e83dc0 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -20,17 +20,21 @@
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.SparseIntArray;
import android.Manifest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -70,6 +74,40 @@
} else {
mSyncManager.dump(fd, pw);
}
+ pw.println();
+ pw.println("Observer tree:");
+ synchronized (mRootNode) {
+ int[] counts = new int[2];
+ final SparseIntArray pidCounts = new SparseIntArray();
+ mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts);
+ pw.println();
+ ArrayList<Integer> sorted = new ArrayList<Integer>();
+ for (int i=0; i<pidCounts.size(); i++) {
+ sorted.add(pidCounts.keyAt(i));
+ }
+ Collections.sort(sorted, new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ int lc = pidCounts.get(lhs);
+ int rc = pidCounts.get(rhs);
+ if (lc < rc) {
+ return 1;
+ } else if (lc > rc) {
+ return -1;
+ }
+ return 0;
+ }
+
+ });
+ for (int i=0; i<sorted.size(); i++) {
+ int pid = sorted.get(i);
+ pw.print(" pid "); pw.print(pid); pw.print(": ");
+ pw.print(pidCounts.get(pid)); pw.println(" observers");
+ }
+ pw.println();
+ pw.print(" Total number of nodes: "); pw.println(counts[0]);
+ pw.print(" Total number of observers: "); pw.println(counts[1]);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -102,7 +140,8 @@
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
synchronized (mRootNode) {
- mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode);
+ mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode,
+ Binder.getCallingUid(), Binder.getCallingPid());
if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
" with notifyForDescendents " + notifyForDescendents);
}
@@ -465,12 +504,17 @@
public static final class ObserverNode {
private class ObserverEntry implements IBinder.DeathRecipient {
public final IContentObserver observer;
+ public final int uid;
+ public final int pid;
public final boolean notifyForDescendents;
private final Object observersLock;
- public ObserverEntry(IContentObserver o, boolean n, Object observersLock) {
+ public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
+ int _uid, int _pid) {
this.observersLock = observersLock;
observer = o;
+ uid = _uid;
+ pid = _pid;
notifyForDescendents = n;
try {
observer.asBinder().linkToDeath(this, 0);
@@ -484,6 +528,16 @@
removeObserverLocked(observer);
}
}
+
+ public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ String name, String prefix, SparseIntArray pidCounts) {
+ pidCounts.put(pid, pidCounts.get(pid)+1);
+ pw.print(prefix); pw.print(name); pw.print(": pid=");
+ pw.print(pid); pw.print(" uid=");
+ pw.print(uid); pw.print(" target=");
+ pw.println(Integer.toHexString(System.identityHashCode(
+ observer != null ? observer.asBinder() : null)));
+ }
}
public static final int INSERT_TYPE = 0;
@@ -498,6 +552,37 @@
mName = name;
}
+ public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ String name, String prefix, int[] counts, SparseIntArray pidCounts) {
+ String innerName = null;
+ if (mObservers.size() > 0) {
+ if ("".equals(name)) {
+ innerName = mName;
+ } else {
+ innerName = name + "/" + mName;
+ }
+ for (int i=0; i<mObservers.size(); i++) {
+ counts[1]++;
+ mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
+ pidCounts);
+ }
+ }
+ if (mChildren.size() > 0) {
+ if (innerName == null) {
+ if ("".equals(name)) {
+ innerName = mName;
+ } else {
+ innerName = name + "/" + mName;
+ }
+ }
+ for (int i=0; i<mChildren.size(); i++) {
+ counts[0]++;
+ mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
+ counts, pidCounts);
+ }
+ }
+ }
+
private String getUriSegment(Uri uri, int index) {
if (uri != null) {
if (index == 0) {
@@ -518,15 +603,16 @@
}
public void addObserverLocked(Uri uri, IContentObserver observer,
- boolean notifyForDescendents, Object observersLock) {
- addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock);
+ boolean notifyForDescendents, Object observersLock, int uid, int pid) {
+ addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid);
}
private void addObserverLocked(Uri uri, int index, IContentObserver observer,
- boolean notifyForDescendents, Object observersLock) {
+ boolean notifyForDescendents, Object observersLock, int uid, int pid) {
// If this is the leaf node add the observer
if (index == countUriSegments(uri)) {
- mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock));
+ mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock,
+ uid, pid));
return;
}
@@ -539,7 +625,8 @@
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (node.mName.equals(segment)) {
- node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
+ node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
+ observersLock, uid, pid);
return;
}
}
@@ -547,7 +634,8 @@
// No child found, create one
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
- node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
+ node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
+ observersLock, uid, pid);
}
public boolean removeObserverLocked(IContentObserver observer) {
diff --git a/core/java/android/content/SearchRecentSuggestionsProvider.java b/core/java/android/content/SearchRecentSuggestionsProvider.java
index 3d89e92..e1a8d21 100644
--- a/core/java/android/content/SearchRecentSuggestionsProvider.java
+++ b/core/java/android/content/SearchRecentSuggestionsProvider.java
@@ -186,6 +186,9 @@
mSuggestionProjection = new String [] {
"0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT,
+ "'android.resource://system/"
+ + com.android.internal.R.drawable.ic_menu_recent_history + "' AS "
+ + SearchManager.SUGGEST_COLUMN_ICON_1,
"display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
"display2 AS " + SearchManager.SUGGEST_COLUMN_TEXT_2,
"query AS " + SearchManager.SUGGEST_COLUMN_QUERY,
@@ -196,6 +199,9 @@
mSuggestionProjection = new String [] {
"0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT,
+ "'android.resource://system/"
+ + com.android.internal.R.drawable.ic_menu_recent_history + "' AS "
+ + SearchManager.SUGGEST_COLUMN_ICON_1,
"display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
"query AS " + SearchManager.SUGGEST_COLUMN_QUERY,
"_id"
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 67d200c..b548623 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -409,9 +409,10 @@
/**
* Sets the current USB function.
+ * If function is null, then the current function is set to the default function.
*
- * @param function name of the USB function
- * @param makeDefault true if this should be set as the default
+ * @param function name of the USB function, or null to restore the default function
+ * @param makeDefault true if the function should be set as the new default function
*
* {@hide}
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23b53ae..34699e2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2683,6 +2683,13 @@
public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
/**
+ * If touch exploration is requested. Touch exploration is enabled if it is
+ * requested by this setting, accessibility is enabled and there is at least
+ * one enabled accessibility serivce that provides spoken feedback.
+ */
+ public static final String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
+
+ /**
* List of the enabled accessibility providers.
*/
public static final String ENABLED_ACCESSIBILITY_SERVICES =
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 8fc8b9d..c51ba2a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -51,7 +51,7 @@
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
@@ -650,7 +650,7 @@
mWindowToken = wrapper.mWindowToken;
mSurfaceHolder.setSizeFromLayout();
mInitializing = true;
- mSession = ViewAncestor.getWindowSession(getMainLooper());
+ mSession = ViewRootImpl.getWindowSession(getMainLooper());
mWindow.setSession(mSession);
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index dea708a..96864c4 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -17,6 +17,7 @@
import android.media.AudioFormat;
import android.media.AudioTrack;
+import android.text.TextUtils;
import android.util.Log;
import java.util.Iterator;
@@ -25,6 +26,7 @@
class AudioPlaybackHandler {
private static final String TAG = "TTS.AudioPlaybackHandler";
+ private static final boolean DBG_THREADING = false;
private static final boolean DBG = false;
private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
@@ -64,70 +66,105 @@
* Stops all synthesis for a given {@code token}. If the current token
* is currently being processed, an effort will be made to stop it but
* that is not guaranteed.
+ *
+ * NOTE: This assumes that all other messages in the queue with {@code token}
+ * have been removed already.
+ *
+ * NOTE: Must be called synchronized on {@code AudioPlaybackHandler.this}.
*/
- synchronized public void stop(MessageParams token) {
+ private void stop(MessageParams token) {
if (token == null) {
return;
}
- removeMessages(token);
+ if (DBG) Log.d(TAG, "Stopping token : " + token);
if (token.getType() == MessageParams.TYPE_SYNTHESIS) {
AudioTrack current = ((SynthesisMessageParams) token).getAudioTrack();
if (current != null) {
// Stop the current audio track if it's still playing.
- // The audio track is thread safe in this regard.
+ // The audio track is thread safe in this regard. The current
+ // handleSynthesisDataAvailable call will return soon after this
+ // call.
current.stop();
}
+ // This is safe because PlaybackSynthesisCallback#stop would have
+ // been called before this method, and will no longer enqueue any
+ // audio for this token.
+ //
+ // (Even if it did, all it would result in is a warning message).
mQueue.add(new ListEntry(SYNTHESIS_DONE, token, HIGH_PRIORITY));
- } else {
- final MessageParams current = getCurrentParams();
-
- if (current != null) {
- if (token.getType() == MessageParams.TYPE_AUDIO) {
- ((AudioMessageParams) current).getPlayer().stop();
- } else if (token.getType() == MessageParams.TYPE_SILENCE) {
- ((SilenceMessageParams) current).getConditionVariable().open();
- }
- }
+ } else if (token.getType() == MessageParams.TYPE_AUDIO) {
+ ((AudioMessageParams) token).getPlayer().stop();
+ // No cleanup required for audio messages.
+ } else if (token.getType() == MessageParams.TYPE_SILENCE) {
+ ((SilenceMessageParams) token).getConditionVariable().open();
+ // No cleanup required for silence messages.
}
}
+ // -----------------------------------------------------
+ // Methods that add and remove elements from the queue. These do not
+ // need to be synchronized strictly speaking, but they make the behaviour
+ // a lot more predictable. (though it would still be correct without
+ // synchronization).
+ // -----------------------------------------------------
+
synchronized public void removePlaybackItems(String callingApp) {
+ if (DBG_THREADING) Log.d(TAG, "Removing all callback items for : " + callingApp);
removeMessages(callingApp);
- stop(getCurrentParams());
+
+ final MessageParams current = getCurrentParams();
+ if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
+ stop(current);
+ }
}
synchronized public void removeAllItems() {
+ if (DBG_THREADING) Log.d(TAG, "Removing all items");
removeAllMessages();
stop(getCurrentParams());
}
/**
+ * @return false iff the queue is empty and no queue item is currently
+ * being handled, true otherwise.
+ */
+ public boolean isSpeaking() {
+ return (mQueue.peek() != null) || (mCurrentParams != null);
+ }
+
+ /**
* Shut down the audio playback thread.
*/
synchronized public void quit() {
+ removeAllMessages();
stop(getCurrentParams());
mQueue.add(new ListEntry(SHUTDOWN, null, HIGH_PRIORITY));
}
- void enqueueSynthesisStart(SynthesisMessageParams token) {
+ synchronized void enqueueSynthesisStart(SynthesisMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis start : " + token);
mQueue.add(new ListEntry(SYNTHESIS_START, token));
}
- void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+ synchronized void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis data available : " + token);
mQueue.add(new ListEntry(SYNTHESIS_DATA_AVAILABLE, token));
}
- void enqueueSynthesisDone(SynthesisMessageParams token) {
+ synchronized void enqueueSynthesisDone(SynthesisMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis done : " + token);
mQueue.add(new ListEntry(SYNTHESIS_DONE, token));
}
- void enqueueAudio(AudioMessageParams token) {
+ synchronized void enqueueAudio(AudioMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing audio : " + token);
mQueue.add(new ListEntry(PLAY_AUDIO, token));
}
- void enqueueSilence(SilenceMessageParams token) {
+ synchronized void enqueueSilence(SilenceMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing silence : " + token);
mQueue.add(new ListEntry(PLAY_SILENCE, token));
}
@@ -172,26 +209,6 @@
}
/*
- * Remove all messages from the queue that contain the supplied token.
- * Note that the Iterator is thread safe, and other methods can safely
- * continue adding to the queue at this point.
- */
- synchronized private void removeMessages(MessageParams token) {
- if (token == null) {
- return;
- }
-
- Iterator<ListEntry> it = mQueue.iterator();
-
- while (it.hasNext()) {
- final ListEntry current = it.next();
- if (current.mMessage == token) {
- it.remove();
- }
- }
- }
-
- /*
* Atomically clear the queue of all messages.
*/
synchronized private void removeAllMessages() {
@@ -255,6 +272,13 @@
}
private void setCurrentParams(MessageParams p) {
+ if (DBG_THREADING) {
+ if (p != null) {
+ Log.d(TAG, "Started handling :" + p);
+ } else {
+ Log.d(TAG, "End handling : " + mCurrentParams);
+ }
+ }
mCurrentParams = p;
}
@@ -345,7 +369,7 @@
private void handleSynthesisDataAvailable(MessageParams msg) {
final SynthesisMessageParams param = (SynthesisMessageParams) msg;
if (param.getAudioTrack() == null) {
- Log.w(TAG, "Error : null audio track in handleDataAvailable.");
+ Log.w(TAG, "Error : null audio track in handleDataAvailable : " + param);
return;
}
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
index 4c1b6d2..e7d6da3 100644
--- a/core/java/android/speech/tts/MessageParams.java
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -38,5 +38,10 @@
return mCallingApp;
}
+ @Override
+ public String toString() {
+ return "MessageParams[" + hashCode() + "]";
+ }
+
abstract int getType();
}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 04bd745..7dbf1ac 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -90,12 +90,10 @@
Log.w(TAG, "stop() called twice");
return;
}
+
// mToken will be null if the engine encounters
// an error before it called start().
- if (mToken != null) {
- mAudioTrackHandler.stop(mToken);
- mToken = null;
- } else {
+ if (mToken == null) {
// In all other cases, mAudioTrackHandler.stop() will
// result in onComplete being called.
mLogger.onWriteData();
@@ -158,7 +156,7 @@
}
synchronized (mStateLock) {
- if (mToken == null) {
+ if (mToken == null || mStopped) {
return TextToSpeech.ERROR;
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 32ca226..5126e48 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -109,6 +109,11 @@
/**
* Broadcast Action: The TextToSpeech synthesizer has completed processing
* of all the text in the speech queue.
+ *
+ * Note that this notifies callers when the <b>engine</b> has finished has
+ * processing text data. Audio playback might not have completed (or even started)
+ * at this point. If you wish to be notified when this happens, see
+ * {@link OnUtteranceCompletedListener}.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
@@ -576,6 +581,14 @@
service.setCallback(getPackageName(), null);
service.stop(getPackageName());
mServiceConnection.disconnect();
+ // Context#unbindService does not result in a call to
+ // ServiceConnection#onServiceDisconnected. As a result, the
+ // service ends up being destroyed (if there are no other open
+ // connections to it) but the process lives on and the
+ // ServiceConnection continues to refer to the destroyed service.
+ //
+ // This leads to tons of log spam about SynthThread being dead.
+ mServiceConnection = null;
mCurrentEngine = null;
return null;
}
@@ -796,7 +809,10 @@
}
/**
- * Checks whether the TTS engine is busy speaking.
+ * Checks whether the TTS engine is busy speaking. Note that a speech item is
+ * considered complete once it's audio data has been sent to the audio mixer, or
+ * written to a file. There might be a finite lag between this point, and when
+ * the audio hardware completes playback.
*
* @return {@code true} if the TTS engine is speaking.
*/
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 010c155..1926c92 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -282,6 +282,8 @@
if (current != null) {
current.stop();
}
+
+ // The AudioPlaybackHandler will be destroyed by the caller.
}
/**
@@ -337,6 +339,8 @@
}
removeCallbacksAndMessages(callingApp);
+ // This stops writing data to the file / or publishing
+ // items to the audio playback handler.
SpeechItem current = setCurrentSpeechItem(null);
if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
current.stop();
@@ -628,9 +632,7 @@
@Override
protected void stopImpl() {
- if (mToken != null) {
- mAudioPlaybackHandler.stop(mToken);
- }
+ // Do nothing.
}
}
@@ -657,9 +659,7 @@
@Override
protected void stopImpl() {
- if (mToken != null) {
- mAudioPlaybackHandler.stop(mToken);
- }
+ // Do nothing.
}
}
@@ -719,7 +719,7 @@
}
public boolean isSpeaking() {
- return mSynthHandler.isSpeaking();
+ return mSynthHandler.isSpeaking() || mAudioPlaybackHandler.isSpeaking();
}
public int stop(String callingApp) {
@@ -767,10 +767,6 @@
mCallbacks.setCallback(packageName, cb);
}
- private boolean isDefault(String lang, String country, String variant) {
- return Locale.getDefault().equals(new Locale(lang, country, variant));
- }
-
private String intern(String in) {
// The input parameter will be non null.
return in.intern();
diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java
new file mode 100644
index 0000000..70dc9aa
--- /dev/null
+++ b/core/java/android/util/Config.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006 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.util;
+
+/**
+ * @deprecated This class is not useful, it just returns the same value for
+ * all constants, and has always done this. Do not use it.
+ */
+@Deprecated
+public final class Config {
+ /** @hide */ public Config() {}
+
+ /**
+ * @deprecated Always false.
+ */
+ @Deprecated
+ public static final boolean DEBUG = false;
+
+ /**
+ * @deprecated Always true.
+ */
+ @Deprecated
+ public static final boolean RELEASE = true;
+
+ /**
+ * @deprecated Always false.
+ */
+ @Deprecated
+ public static final boolean PROFILE = false;
+
+ /**
+ * @deprecated Always false.
+ */
+ @Deprecated
+ public static final boolean LOGV = false;
+
+ /**
+ * @deprecated Always true.
+ */
+ @Deprecated
+ public static final boolean LOGD = true;
+}
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 132b595..09ce8e4 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -196,6 +196,12 @@
private int pos = 0;
private int limit = 0;
+ /*
+ * The offset of the first character in the buffer.
+ */
+ private int bufferStartLine = 1;
+ private int bufferStartColumn = 1;
+
private final List<JsonScope> stack = new ArrayList<JsonScope>();
{
push(JsonScope.EMPTY_DOCUMENT);
@@ -711,6 +717,16 @@
* false.
*/
private boolean fillBuffer(int minimum) throws IOException {
+ // Before clobbering the old characters, update where buffer starts
+ for (int i = 0; i < pos; i++) {
+ if (buffer[i] == '\n') {
+ bufferStartLine++;
+ bufferStartColumn = 1;
+ } else {
+ bufferStartColumn++;
+ }
+ }
+
if (limit != pos) {
limit -= pos;
System.arraycopy(buffer, pos, buffer, 0, limit);
@@ -729,6 +745,28 @@
return false;
}
+ private int getLineNumber() {
+ int result = bufferStartLine;
+ for (int i = 0; i < pos; i++) {
+ if (buffer[i] == '\n') {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ private int getColumnNumber() {
+ int result = bufferStartColumn;
+ for (int i = 0; i < pos; i++) {
+ if (buffer[i] == '\n') {
+ result = 1;
+ } else {
+ result++;
+ }
+ }
+ return result;
+ }
+
private int nextNonWhitespace() throws IOException {
while (pos < limit || fillBuffer(1)) {
int c = buffer[pos++];
@@ -1107,7 +1145,8 @@
* with this reader's content.
*/
private IOException syntaxError(String message) throws IOException {
- throw new MalformedJsonException(message + " near " + getSnippet());
+ throw new MalformedJsonException(message
+ + " at line " + getLineNumber() + " column " + getColumnNumber());
}
private CharSequence getSnippet() {
diff --git a/core/java/android/util/JsonWriter.java b/core/java/android/util/JsonWriter.java
index 47e84c5..c1e6e40 100644
--- a/core/java/android/util/JsonWriter.java
+++ b/core/java/android/util/JsonWriter.java
@@ -407,6 +407,11 @@
* quotation marks except for the characters that must be escaped:
* quotation mark, reverse solidus, and the control characters
* (U+0000 through U+001F)."
+ *
+ * We also escape '\u2028' and '\u2029', which JavaScript interprets
+ * as newline characters. This prevents eval() from failing with a
+ * syntax error.
+ * http://code.google.com/p/google-gson/issues/detail?id=341
*/
switch (c) {
case '"':
@@ -435,6 +440,11 @@
out.write("\\f");
break;
+ case '\u2028':
+ case '\u2029':
+ out.write(String.format("\\u%04x", (int) c));
+ break;
+
default:
if (c <= 0x1F) {
out.write(String.format("\\u%04x", (int) c));
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 7fc43b9..7cf4579 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -23,10 +23,14 @@
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Integers to Objects.
*/
-public class SparseArray<E> {
+public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
+ private int[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+
/**
* Creates a new SparseArray containing no mappings.
*/
@@ -47,6 +51,20 @@
mSize = 0;
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public SparseArray<E> clone() {
+ SparseArray<E> clone = null;
+ try {
+ clone = (SparseArray<E>) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
+ }
+ return clone;
+ }
+
/**
* Gets the Object mapped from the specified key, or <code>null</code>
* if no such mapping has been made.
@@ -59,6 +77,7 @@
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
+ @SuppressWarnings("unchecked")
public E get(int key, E valueIfKeyNotFound) {
int i = binarySearch(mKeys, 0, mSize, key);
@@ -209,6 +228,7 @@
* the value from the <code>index</code>th key-value mapping that this
* SparseArray stores.
*/
+ @SuppressWarnings("unchecked")
public E valueAt(int index) {
if (mGarbage) {
gc();
@@ -331,20 +351,4 @@
else
return ~high;
}
-
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
- private int[] mKeys;
- private Object[] mValues;
- private int mSize;
}
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index f7799de..76c47c6 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -24,7 +24,7 @@
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Integers to Booleans.
*/
-public class SparseBooleanArray {
+public class SparseBooleanArray implements Cloneable {
/**
* Creates a new SparseBooleanArray containing no mappings.
*/
@@ -45,6 +45,19 @@
mSize = 0;
}
+ @Override
+ public SparseBooleanArray clone() {
+ SparseBooleanArray clone = null;
+ try {
+ clone = (SparseBooleanArray) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
+ }
+ return clone;
+ }
+
/**
* Gets the boolean mapped from the specified key, or <code>false</code>
* if no such mapping has been made.
@@ -227,18 +240,6 @@
return ~high;
}
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
private int[] mKeys;
private boolean[] mValues;
private int mSize;
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 9ab3b53..8d11177 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -23,7 +23,12 @@
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Integers to Integers.
*/
-public class SparseIntArray {
+public class SparseIntArray implements Cloneable {
+
+ private int[] mKeys;
+ private int[] mValues;
+ private int mSize;
+
/**
* Creates a new SparseIntArray containing no mappings.
*/
@@ -44,6 +49,19 @@
mSize = 0;
}
+ @Override
+ public SparseIntArray clone() {
+ SparseIntArray clone = null;
+ try {
+ clone = (SparseIntArray) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
+ }
+ return clone;
+ }
+
/**
* Gets the int mapped from the specified key, or <code>0</code>
* if no such mapping has been made.
@@ -232,20 +250,4 @@
else
return ~high;
}
-
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
- private int[] mKeys;
- private int[] mValues;
- private int mSize;
}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index bfafa98..e954983 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -23,6 +23,36 @@
* Examples of good action modes include selection modes, search, content editing, etc.
*/
public abstract class ActionMode {
+ private Object mTag;
+
+ /**
+ * Set a tag object associated with this ActionMode.
+ *
+ * <p>Like the tag available to views, this allows applications to associate arbitrary
+ * data with an ActionMode for later reference.
+ *
+ * @param tag Tag to associate with this ActionMode
+ *
+ * @see #getTag()
+ */
+ public void setTag(Object tag) {
+ mTag = tag;
+ }
+
+ /**
+ * Retrieve the tag object associated with this ActionMode.
+ *
+ * <p>Like the tag available to views, this allows applications to associate arbitrary
+ * data with an ActionMode for later reference.
+ *
+ * @return Tag associated with this ActionMode
+ *
+ * @see #setTag(Object)
+ */
+ public Object getTag() {
+ return mTag;
+ }
+
/**
* Set the title of the action mode. This method will have no visible effect if
* a custom view has been set.
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 4987e2f..80244bb 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -286,6 +286,38 @@
private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Memory
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @see #flushCaches(int)
+ */
+ public static final int FLUSH_CACHES_MODERATE = 0;
+
+ /**
+ * @see #flushCaches(int)
+ */
+ public static final int FLUSH_CACHES_FULL = 1;
+
+ /**
+ * Flush caches to reclaim as much memory as possible. The amount of memory
+ * to reclaim is indicate by the level parameter.
+ *
+ * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
+ * {@link #FLUSH_CACHES_FULL}.
+ *
+ * @param level Hint about the amount of memory to reclaim
+ *
+ * @hide
+ */
+ public static void flushCaches(int level) {
+ nFlushCaches(level);
+ }
+
+ private static native void nFlushCaches(int level);
+
///////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 011e44c..9a2564f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -17,6 +17,7 @@
package android.view;
+import android.content.ComponentCallbacks;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
@@ -263,6 +264,18 @@
}
/**
+ * Invoke this method when the system is running out of memory. This
+ * method will attempt to recover as much memory as possible, based on
+ * the specified hint.
+ *
+ * @param level Hint about the amount of memory that should be trimmed,
+ * see {@link android.content.ComponentCallbacks}
+ */
+ static void trimMemory(int level) {
+ Gl20Renderer.flushCaches(level);
+ }
+
+ /**
* Indicates whether hardware acceleration is currently enabled.
*
* @return True if hardware acceleration is in use, false otherwise.
@@ -858,5 +871,16 @@
}
return null;
}
+
+ static void flushCaches(int level) {
+ switch (level) {
+ case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
+ break;
+ case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
+ break;
+ }
+ }
}
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 764899f..cbdb38e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -426,7 +426,7 @@
if (!mHaveFrame) {
return;
}
- ViewAncestor viewRoot = (ViewAncestor) getRootView().getParent();
+ ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent();
if (viewRoot != null) {
mTranslator = viewRoot.mTranslator;
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index d656f31..96d6f09 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -20,6 +20,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.util.AttributeSet;
import android.util.Log;
@@ -107,6 +108,14 @@
private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
+ private Canvas mCanvas;
+ private int mSaveCount;
+
+ private final Object[] mNativeWindowLock = new Object[0];
+ // Used from native code, do not write!
+ @SuppressWarnings({"UnusedDeclaration"})
+ private int mNativeWindow;
+
/**
* Creates a new TextureView.
*
@@ -190,7 +199,11 @@
mListener.onSurfaceTextureDestroyed(mSurface);
}
- mLayer.destroy();
+ synchronized (mNativeWindowLock) {
+ nDestroyNativeWindow();
+ }
+
+ mLayer.destroy();
mSurface = null;
mLayer = null;
}
@@ -274,6 +287,7 @@
mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ nCreateNativeWindow(mSurface);
mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@Override
@@ -431,6 +445,79 @@
}
/**
+ * <p>Start editing the pixels in the surface. The returned Canvas can be used
+ * to draw into the surface's bitmap. A null is returned if the surface has
+ * not been created or otherwise cannot be edited. You will usually need
+ * to implement
+ * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)}
+ * to find out when the Surface is available for use.</p>
+ *
+ * <p>The content of the Surface is never preserved between unlockCanvas()
+ * and lockCanvas(), for this reason, every pixel within the Surface area
+ * must be written. The only exception to this rule is when a dirty
+ * rectangle is specified, in which case, non-dirty pixels will be
+ * preserved.</p>
+ *
+ * @return A Canvas used to draw into the surface.
+ *
+ * @see #lockCanvas(android.graphics.Rect)
+ * @see #unlockCanvasAndPost(android.graphics.Canvas)
+ */
+ public Canvas lockCanvas() {
+ return lockCanvas(null);
+ }
+
+ /**
+ * Just like {@link #lockCanvas()} but allows specification of a dirty
+ * rectangle. Every pixel within that rectangle must be written; however
+ * pixels outside the dirty rectangle will be preserved by the next call
+ * to lockCanvas().
+ *
+ * @param dirty Area of the surface that will be modified.
+
+ * @return A Canvas used to draw into the surface.
+ *
+ * @see #lockCanvas()
+ * @see #unlockCanvasAndPost(android.graphics.Canvas)
+ */
+ public Canvas lockCanvas(Rect dirty) {
+ if (!isAvailable()) return null;
+
+ if (mCanvas == null) {
+ mCanvas = new Canvas();
+ }
+
+ synchronized (mNativeWindowLock) {
+ nLockCanvas(mNativeWindow, mCanvas, dirty);
+ }
+ mSaveCount = mCanvas.save();
+
+ return mCanvas;
+ }
+
+ /**
+ * Finish editing pixels in the surface. After this call, the surface's
+ * current pixels will be shown on the screen, but its content is lost,
+ * in particular there is no guarantee that the content of the Surface
+ * will remain unchanged when lockCanvas() is called again.
+ *
+ * @param canvas The Canvas previously returned by lockCanvas()
+ *
+ * @see #lockCanvas()
+ * @see #lockCanvas(android.graphics.Rect)
+ */
+ public void unlockCanvasAndPost(Canvas canvas) {
+ if (mCanvas != null && canvas == mCanvas) {
+ canvas.restoreToCount(mSaveCount);
+ mSaveCount = 0;
+
+ synchronized (mNativeWindowLock) {
+ nUnlockCanvasAndPost(mNativeWindow, mCanvas);
+ }
+ }
+ }
+
+ /**
* Returns the {@link SurfaceTexture} used by this view. This method
* may return null if the view is not attached to a window or if the surface
* texture has not been initialized yet.
@@ -506,6 +593,12 @@
public void onSurfaceTextureUpdated(SurfaceTexture surface);
}
+ private native void nCreateNativeWindow(SurfaceTexture surface);
+ private native void nDestroyNativeWindow();
+
private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
int width, int height);
+
+ private static native void nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
+ private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2a65f0c..4e9c0b7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5043,9 +5043,9 @@
}
/** Gets the ViewAncestor, or null if not attached. */
- /*package*/ ViewAncestor getViewAncestor() {
+ /*package*/ ViewRootImpl getViewRootImpl() {
View root = getRootView();
- return root != null ? (ViewAncestor)root.getParent() : null;
+ return root != null ? (ViewRootImpl)root.getParent() : null;
}
/**
@@ -5061,7 +5061,7 @@
public final boolean requestFocusFromTouch() {
// Leave touch mode if we need to
if (isInTouchMode()) {
- ViewAncestor viewRoot = getViewAncestor();
+ ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) {
viewRoot.ensureTouchMode(false);
}
@@ -5653,7 +5653,7 @@
if (mAttachInfo != null) {
return mAttachInfo.mInTouchMode;
} else {
- return ViewAncestor.isInTouchMode();
+ return ViewRootImpl.isInTouchMode();
}
}
@@ -8254,7 +8254,7 @@
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewAncestor.getRunQueue().post(action);
+ ViewRootImpl.getRunQueue().post(action);
return true;
}
@@ -8284,7 +8284,7 @@
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewAncestor.getRunQueue().postDelayed(action, delayMillis);
+ ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
@@ -8308,7 +8308,7 @@
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewAncestor.getRunQueue().removeCallbacks(action);
+ ViewRootImpl.getRunQueue().removeCallbacks(action);
return true;
}
@@ -9127,12 +9127,12 @@
// Start user padding override Left user padding. Otherwise, if Left user
// padding is not defined, use the default left padding. If Left user padding
// is defined, just use it.
- if (mUserPaddingStart > 0) {
+ if (mUserPaddingStart >= 0) {
mUserPaddingLeft = mUserPaddingStart;
} else if (mUserPaddingLeft < 0) {
mUserPaddingLeft = mPaddingLeft;
}
- if (mUserPaddingEnd > 0) {
+ if (mUserPaddingEnd >= 0) {
mUserPaddingRight = mUserPaddingEnd;
} else if (mUserPaddingRight < 0) {
mUserPaddingRight = mPaddingRight;
@@ -11122,6 +11122,10 @@
* background
*/
public void setBackgroundDrawable(Drawable d) {
+ if (d == mBGDrawable) {
+ return;
+ }
+
boolean requestLayout = false;
mBackgroundResource = 0;
@@ -11576,9 +11580,9 @@
viewParent = view.mParent;
}
- if (viewParent instanceof ViewAncestor) {
+ if (viewParent instanceof ViewRootImpl) {
// *cough*
- final ViewAncestor vr = (ViewAncestor)viewParent;
+ final ViewRootImpl vr = (ViewRootImpl)viewParent;
location[1] -= vr.mCurScrollY;
}
}
@@ -12705,7 +12709,7 @@
surface.unlockCanvasAndPost(canvas);
}
- final ViewAncestor root = getViewAncestor();
+ final ViewRootImpl root = getViewRootImpl();
// Cache the local state object for delivery with DragEvents
root.setLocalDragState(myLocalState);
@@ -13912,7 +13916,7 @@
Canvas mCanvas;
/**
- * A Handler supplied by a view's {@link android.view.ViewAncestor}. This
+ * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
* handler can be used to pump events in the UI events queue.
*/
final Handler mHandler;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index f7f5a21..b85159b 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -366,7 +366,7 @@
}
private static BufferedWriter sHierarchyTraces;
- private static ViewAncestor sHierarhcyRoot;
+ private static ViewRootImpl sHierarhcyRoot;
private static String sHierarchyTracePrefix;
/**
@@ -415,7 +415,7 @@
* @hide
*/
public static long getViewAncestorInstanceCount() {
- return Debug.countInstancesOfClass(ViewAncestor.class);
+ return Debug.countInstancesOfClass(ViewRootImpl.class);
}
/**
@@ -748,7 +748,7 @@
return;
}
- sHierarhcyRoot = (ViewAncestor) view.getRootView().getParent();
+ sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent();
}
/**
@@ -1100,7 +1100,7 @@
private static void outputDisplayList(View root, String parameter) throws IOException {
final View view = findView(root, parameter);
- view.getViewAncestor().outputDisplayList(view);
+ view.getViewRootImpl().outputDisplayList(view);
}
private static void capture(View root, final OutputStream clientStream, String parameter)
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cb3e9c6..5f7673a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -954,7 +954,7 @@
final float tx = event.mX;
final float ty = event.mY;
- ViewAncestor root = getViewAncestor();
+ ViewRootImpl root = getViewRootImpl();
// Dispatch down the view hierarchy
switch (event.mAction) {
@@ -3839,13 +3839,13 @@
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewAncestor) {
- ((ViewAncestor) parent).mIsAnimating = true;
+ } else if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).mIsAnimating = true;
}
}
- if (parent instanceof ViewAncestor) {
- ((ViewAncestor) parent).invalidate();
+ if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).invalidate();
parent = null;
} else if (view != null) {
if ((view.mPrivateFlags & DRAWN) == DRAWN ||
@@ -3902,8 +3902,8 @@
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewAncestor) {
- ((ViewAncestor) parent).mIsAnimating = true;
+ } else if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).mIsAnimating = true;
}
}
@@ -4426,7 +4426,7 @@
// If this group is dirty, check that the parent is dirty as well
if ((mPrivateFlags & DIRTY_MASK) != 0) {
final ViewParent parent = getParent();
- if (parent != null && !(parent instanceof ViewAncestor)) {
+ if (parent != null && !(parent instanceof ViewRootImpl)) {
if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
result = false;
android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
@@ -4995,7 +4995,7 @@
* @hide
*/
public void requestTransitionStart(LayoutTransition transition) {
- ViewAncestor viewAncestor = getViewAncestor();
+ ViewRootImpl viewAncestor = getViewRootImpl();
viewAncestor.requestTransitionStart(transition);
}
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewRootImpl.java
similarity index 98%
rename from core/java/android/view/ViewAncestor.java
rename to core/java/android/view/ViewRootImpl.java
index ac73611..470493d 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -92,7 +92,7 @@
* {@hide}
*/
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewAncestor extends Handler implements ViewParent,
+public final class ViewRootImpl extends Handler implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
private static final String TAG = "ViewAncestor";
private static final boolean DBG = false;
@@ -303,7 +303,7 @@
}
}
- public ViewAncestor(Context context) {
+ public ViewRootImpl(Context context) {
super();
if (MEASURE_LATENCY) {
@@ -3807,14 +3807,14 @@
}
static class InputMethodCallback extends IInputMethodCallback.Stub {
- private WeakReference<ViewAncestor> mViewAncestor;
+ private WeakReference<ViewRootImpl> mViewAncestor;
- public InputMethodCallback(ViewAncestor viewAncestor) {
- mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+ public InputMethodCallback(ViewRootImpl viewAncestor) {
+ mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
}
public void finishedEvent(int seq, boolean handled) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchFinishedEvent(seq, handled);
}
@@ -3826,15 +3826,15 @@
}
static class W extends IWindow.Stub {
- private final WeakReference<ViewAncestor> mViewAncestor;
+ private final WeakReference<ViewRootImpl> mViewAncestor;
- W(ViewAncestor viewAncestor) {
- mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+ W(ViewRootImpl viewAncestor) {
+ mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
}
public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
boolean reportDraw, Configuration newConfig) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw,
newConfig);
@@ -3842,21 +3842,21 @@
}
public void dispatchAppVisibility(boolean visible) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchAppVisibility(visible);
}
}
public void dispatchGetNewSurface() {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchGetNewSurface();
}
}
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
}
@@ -3872,7 +3872,7 @@
}
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
final View view = viewAncestor.mView;
if (view != null) {
@@ -3903,7 +3903,7 @@
}
public void closeSystemDialogs(String reason) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchCloseSystemDialogs(reason);
}
@@ -3931,14 +3931,14 @@
/* Drag/drop */
public void dispatchDragEvent(DragEvent event) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchDragEvent(event);
}
}
public void dispatchSystemUiVisibilityChanged(int visibility) {
- final ViewAncestor viewAncestor = mViewAncestor.get();
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchSystemUiVisibilityChanged(visibility);
}
@@ -4269,7 +4269,7 @@
if (!registered) {
mAttachInfo.mAccessibilityWindowId =
mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
- new AccessibilityInteractionConnection(ViewAncestor.this));
+ new AccessibilityInteractionConnection(ViewRootImpl.this));
}
}
@@ -4289,10 +4289,10 @@
*/
final class AccessibilityInteractionConnection
extends IAccessibilityInteractionConnection.Stub {
- private final WeakReference<ViewAncestor> mViewAncestor;
+ private final WeakReference<ViewRootImpl> mViewAncestor;
- AccessibilityInteractionConnection(ViewAncestor viewAncestor) {
- mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+ AccessibilityInteractionConnection(ViewRootImpl viewAncestor) {
+ mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
}
public void findAccessibilityNodeInfoByAccessibilityId(int accessibilityId,
@@ -4421,7 +4421,7 @@
try {
FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate;
predicate.init(accessibilityId);
- View root = ViewAncestor.this.mView;
+ View root = ViewRootImpl.this.mView;
View target = root.findViewByPredicate(predicate);
if (target != null && target.isShown()) {
info = target.createAccessibilityNodeInfo();
@@ -4453,7 +4453,7 @@
AccessibilityNodeInfo info = null;
try {
- View root = ViewAncestor.this.mView;
+ View root = ViewRootImpl.this.mView;
View target = root.findViewById(viewId);
if (target != null && target.isShown()) {
info = target.createAccessibilityNodeInfo();
@@ -4499,7 +4499,7 @@
if (accessibilityViewId != View.NO_ID) {
root = findViewByAccessibilityId(accessibilityViewId);
} else {
- root = ViewAncestor.this.mView;
+ root = ViewRootImpl.this.mView;
}
if (root == null || !root.isShown()) {
@@ -4624,7 +4624,7 @@
}
private View findViewByAccessibilityId(int accessibilityId) {
- View root = ViewAncestor.this.mView;
+ View root = ViewRootImpl.this.mView;
if (root == null) {
return null;
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 54e7c04..a451bb5 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,18 +16,16 @@
package android.view;
-import java.util.HashMap;
-
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.AndroidRuntimeException;
import android.util.Log;
-import android.util.Slog;
-import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
+import java.util.HashMap;
+
final class WindowLeaked extends AndroidRuntimeException {
public WindowLeaked(String msg) {
super(msg);
@@ -80,7 +78,7 @@
public static final int ADD_PERMISSION_DENIED = -8;
private View[] mViews;
- private ViewAncestor[] mRoots;
+ private ViewRootImpl[] mRoots;
private WindowManager.LayoutParams[] mParams;
private final static Object sLock = new Object();
@@ -204,7 +202,7 @@
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
- ViewAncestor root;
+ ViewRootImpl root;
View panelParentView = null;
synchronized (this) {
@@ -241,7 +239,7 @@
}
}
- root = new ViewAncestor(view.getContext());
+ root = new ViewRootImpl(view.getContext());
root.mAddNesting = 1;
if (cih == null) {
root.mCompatibilityInfo = new CompatibilityInfoHolder();
@@ -254,7 +252,7 @@
if (mViews == null) {
index = 1;
mViews = new View[1];
- mRoots = new ViewAncestor[1];
+ mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
@@ -262,7 +260,7 @@
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
- mRoots = new ViewAncestor[index];
+ mRoots = new ViewRootImpl[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
@@ -290,7 +288,7 @@
synchronized (this) {
int index = findViewLocked(view, true);
- ViewAncestor root = mRoots[index];
+ ViewRootImpl root = mRoots[index];
mParams[index] = wparams;
root.setLayoutParams(wparams, false);
}
@@ -312,7 +310,7 @@
public void removeViewImmediate(View view) {
synchronized (this) {
int index = findViewLocked(view, true);
- ViewAncestor root = mRoots[index];
+ ViewRootImpl root = mRoots[index];
View curView = root.getView();
root.mAddNesting = 0;
@@ -328,7 +326,7 @@
}
View removeViewLocked(int index) {
- ViewAncestor root = mRoots[index];
+ ViewRootImpl root = mRoots[index];
View view = root.getView();
// Don't really remove until we have matched all calls to add().
@@ -356,7 +354,7 @@
removeItem(tmpViews, mViews, index);
mViews = tmpViews;
- ViewAncestor[] tmpRoots = new ViewAncestor[count-1];
+ ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1];
removeItem(tmpRoots, mRoots, index);
mRoots = tmpRoots;
@@ -383,7 +381,7 @@
//Log.i("foo", "@ " + i + " token " + mParams[i].token
// + " view " + mRoots[i].getView());
if (token == null || mParams[i].token == token) {
- ViewAncestor root = mRoots[i];
+ ViewRootImpl root = mRoots[i];
root.mAddNesting = 1;
//Log.i("foo", "Force closing " + root);
@@ -402,7 +400,16 @@
}
}
}
-
+
+ /**
+ * @param level See {@link android.content.ComponentCallbacks}
+ */
+ public void trimMemory(int level) {
+ if (HardwareRenderer.isAvailable()) {
+ HardwareRenderer.trimMemory(level);
+ }
+ }
+
public void setStoppedState(IBinder token, boolean stopped) {
synchronized (this) {
if (mViews == null)
@@ -410,7 +417,7 @@
int count = mViews.length;
for (int i=0; i<count; i++) {
if (token == null || mParams[i].token == token) {
- ViewAncestor root = mRoots[i];
+ ViewRootImpl root = mRoots[i];
root.setStopped(stopped);
}
}
@@ -422,7 +429,7 @@
int count = mViews.length;
config = new Configuration(config);
for (int i=0; i<count; i++) {
- ViewAncestor root = mRoots[i];
+ ViewRootImpl root = mRoots[i];
root.requestUpdateConfiguration(config);
}
}
@@ -430,13 +437,13 @@
public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
ViewParent vp = view.getParent();
- while (vp != null && !(vp instanceof ViewAncestor)) {
+ while (vp != null && !(vp instanceof ViewRootImpl)) {
vp = vp.getParent();
}
if (vp == null) return null;
- ViewAncestor vr = (ViewAncestor)vp;
+ ViewRootImpl vr = (ViewRootImpl)vp;
int N = mRoots.length;
for (int i = 0; i < N; ++i) {
@@ -456,8 +463,7 @@
return new Display(Display.DEFAULT_DISPLAY, null);
}
- private static void removeItem(Object[] dst, Object[] src, int index)
- {
+ private static void removeItem(Object[] dst, Object[] src, int index) {
if (dst.length > 0) {
if (index > 0) {
System.arraycopy(src, 0, dst, 0, index);
@@ -468,8 +474,7 @@
}
}
- private int findViewLocked(View view, boolean required)
- {
+ private int findViewLocked(View view, boolean required) {
synchronized (this) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index ac86769..9be2a67 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -552,7 +552,8 @@
/**
* Returns a cached instance if such is available or a new one is
- * initialized with from the given <code>event</code>.
+ * created. The returned instance is initialized from the given
+ * <code>event</code>.
*
* @param event The other event.
* @return An instance.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 314b7ca..83c73cb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -71,7 +71,9 @@
private static AccessibilityManager sInstance;
- private static final int DO_SET_ENABLED = 10;
+ private static final int DO_SET_ACCESSIBILITY_ENABLED = 10;
+
+ private static final int DO_SET_TOUCH_EXPLORATION_ENABLED = 20;
final IAccessibilityManager mService;
@@ -79,6 +81,8 @@
boolean mIsEnabled;
+ boolean mIsTouchExplorationEnabled;
+
final CopyOnWriteArrayList<AccessibilityStateChangeListener> mAccessibilityStateChangeListeners =
new CopyOnWriteArrayList<AccessibilityStateChangeListener>();
@@ -97,7 +101,12 @@
final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() {
public void setEnabled(boolean enabled) {
- mHandler.obtainMessage(DO_SET_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
+ mHandler.obtainMessage(DO_SET_ACCESSIBILITY_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
+ }
+
+ public void setTouchExplorationEnabled(boolean enabled) {
+ mHandler.obtainMessage(DO_SET_TOUCH_EXPLORATION_ENABLED,
+ enabled ? 1 : 0, 0).sendToTarget();
}
};
@@ -110,9 +119,14 @@
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case DO_SET_ENABLED :
- final boolean isEnabled = (message.arg1 == 1);
- setAccessibilityState(isEnabled);
+ case DO_SET_ACCESSIBILITY_ENABLED :
+ final boolean isAccessibilityEnabled = (message.arg1 == 1);
+ setAccessibilityState(isAccessibilityEnabled);
+ return;
+ case DO_SET_TOUCH_EXPLORATION_ENABLED :
+ synchronized (mHandler) {
+ mIsTouchExplorationEnabled = (message.arg1 == 1);
+ }
return;
default :
Log.w(LOG_TAG, "Unknown message type: " + message.what);
@@ -168,6 +182,17 @@
}
/**
+ * Returns if the touch exploration in the system is enabled.
+ *
+ * @return True if touch exploration is enabled, false otherwise.
+ */
+ public boolean isTouchExplorationEnabled() {
+ synchronized (mHandler) {
+ return mIsTouchExplorationEnabled;
+ }
+ }
+
+ /**
* Returns the client interface this instance registers in
* the centralized accessibility manager service.
*
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 031c6ae..0e04471 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -120,7 +120,7 @@
private CharSequence mText;
private CharSequence mContentDescription;
- private final SparseIntArray mChildAccessibilityIds = new SparseIntArray();
+ private SparseIntArray mChildAccessibilityIds = new SparseIntArray();
private int mActions;
private IAccessibilityServiceConnection mConnection;
@@ -873,6 +873,20 @@
}
/**
+ * Returns a cached instance if such is available or a new one is
+ * create. The returned instance is initialized from the given
+ * <code>info</code>.
+ *
+ * @param info The other info.
+ * @return An instance.
+ */
+ public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
+ AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
+ infoClone.init(info);
+ return infoClone;
+ }
+
+ /**
* Return an instance back to be reused.
* <p>
* <strong>Note:</strong> You must not touch the object after calling this function.
@@ -945,6 +959,28 @@
}
/**
+ * Initializes this instance from another one.
+ *
+ * @param other The other instance.
+ */
+ private void init(AccessibilityNodeInfo other) {
+ mSealed = other.mSealed;
+ mConnection = other.mConnection;
+ mAccessibilityViewId = other.mAccessibilityViewId;
+ mParentAccessibilityViewId = other.mParentAccessibilityViewId;
+ mAccessibilityWindowId = other.mAccessibilityWindowId;
+ mBoundsInParent.set(other.mBoundsInParent);
+ mBoundsInScreen.set(other.mBoundsInScreen);
+ mPackageName = other.mPackageName;
+ mClassName = other.mClassName;
+ mText = other.mText;
+ mContentDescription = other.mContentDescription;
+ mActions= other.mActions;
+ mBooleanProperties = other.mBooleanProperties;
+ mChildAccessibilityIds = other.mChildAccessibilityIds.clone();
+ }
+
+ /**
* Creates a new instance from a {@link Parcel}.
*
* @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
@@ -994,6 +1030,7 @@
mConnection = null;
mAccessibilityViewId = View.NO_ID;
mParentAccessibilityViewId = View.NO_ID;
+ mAccessibilityWindowId = View.NO_ID;
mChildAccessibilityIds.clear();
mBoundsInParent.set(0, 0, 0, 0);
mBoundsInScreen.set(0, 0, 0, 0);
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 1eb60fc..4e69692 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -26,4 +26,5 @@
void setEnabled(boolean enabled);
+ void setTouchExplorationEnabled(boolean enabled);
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index abe3c2c..5ec1ec3 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -34,7 +34,7 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
class ComposingText implements NoCopySpan {
}
@@ -502,7 +502,7 @@
}
}
if (h != null) {
- h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
event));
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d07f4fd..da5baf8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -43,7 +43,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -656,7 +656,7 @@
if (vh != null) {
// This will result in a call to reportFinishInputConnection()
// below.
- vh.sendMessage(vh.obtainMessage(ViewAncestor.FINISH_INPUT_CONNECTION,
+ vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
mServedInputConnection));
}
}
@@ -1113,9 +1113,9 @@
void scheduleCheckFocusLocked(View view) {
Handler vh = view.getHandler();
- if (vh != null && !vh.hasMessages(ViewAncestor.CHECK_FOCUS)) {
+ if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) {
// This will result in a call to checkFocus() below.
- vh.sendMessage(vh.obtainMessage(ViewAncestor.CHECK_FOCUS));
+ vh.sendMessage(vh.obtainMessage(ViewRootImpl.CHECK_FOCUS));
}
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 5aa60f4..738bcb9 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -35,7 +35,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.Surface;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import junit.framework.Assert;
@@ -228,7 +228,7 @@
sConfigCallback = new ConfigCallback(
(WindowManager) appContext.getSystemService(
Context.WINDOW_SERVICE));
- ViewAncestor.addConfigCallback(sConfigCallback);
+ ViewRootImpl.addConfigCallback(sConfigCallback);
}
sConfigCallback.addHandler(this);
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 32c44d8..d7429b3 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -431,7 +431,6 @@
*/
public Intent chooseActivity(int index) {
ActivityResolveInfo chosenActivity = mActivites.get(index);
- ActivityResolveInfo defaultActivity = mActivites.get(0);
ComponentName chosenName = new ComponentName(
chosenActivity.resolveInfo.activityInfo.packageName,
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index f500b39..5b69aa8 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
@@ -92,6 +93,11 @@
private final ImageButton mDefaultActionButton;
/**
+ * The maximal width of the list popup.
+ */
+ private final int mListPopupMaxWidth;
+
+ /**
* Observer for the model data.
*/
private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
@@ -185,7 +191,7 @@
mExpandActivityOverflowButton = (ImageButton) findViewById(R.id.expand_activities_button);
mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
- mExpandActivityOverflowButton.setBackgroundDrawable(expandActivityOverflowButtonDrawable);
+ mExpandActivityOverflowButton.setImageDrawable(expandActivityOverflowButtonDrawable);
mAdapter = new ActivityChooserViewAdapter();
mAdapter.registerDataSetObserver(new DataSetObserver() {
@@ -195,6 +201,10 @@
updateButtons();
}
});
+
+ Resources resources = context.getResources();
+ mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
+ resources.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
}
/**
@@ -220,7 +230,7 @@
* @param drawable The drawable.
*/
public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
- mExpandActivityOverflowButton.setBackgroundDrawable(drawable);
+ mExpandActivityOverflowButton.setImageDrawable(drawable);
}
/**
@@ -264,7 +274,8 @@
} else {
mAdapter.setShowDefaultActivity(false);
}
- popupWindow.setContentWidth(mAdapter.measureContentWidth());
+ final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
+ popupWindow.setContentWidth(contentWidth);
popupWindow.show();
}
}
@@ -390,7 +401,7 @@
}
ResolveInfo activity = mAdapter.getDefaultActivity();
PackageManager packageManager = mContext.getPackageManager();
- mDefaultActionButton.setBackgroundDrawable(activity.loadIcon(packageManager));
+ mDefaultActionButton.setImageDrawable(activity.loadIcon(packageManager));
} else {
mDefaultActionButton.setVisibility(View.INVISIBLE);
mExpandActivityOverflowButton.setEnabled(false);
@@ -574,7 +585,7 @@
// Set the icon
ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
ResolveInfo activity = (ResolveInfo) getItem(position);
- iconView.setBackgroundDrawable(activity.loadIcon(packageManager));
+ iconView.setImageDrawable(activity.loadIcon(packageManager));
// Set the title.
TextView titleView = (TextView) convertView.findViewById(R.id.title);
titleView.setText(activity.loadLabel(packageManager));
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index b9eb5ff..f82c61a 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -28,7 +28,7 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import com.android.internal.R.styleable;
+import com.android.internal.R;
import java.lang.reflect.Array;
import java.util.ArrayList;
@@ -167,7 +167,7 @@
// Misc constants
private static final String TAG = GridLayout.class.getName();
- static final boolean DEBUG = false;
+ static boolean DEBUG = false;
private static final int PRF = 1;
// Defaults
@@ -178,19 +178,17 @@
private static final boolean DEFAULT_ORDER_PRESERVED = false;
private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
private static final int DEFAULT_CONTAINER_MARGIN = 0;
- private static final int DEFAULT_MARGIN = 8;
- private static final int DEFAULT_CONTAINER_PADDING = 16;
private static final int MAX_SIZE = 100000;
// TypedArray indices
- private static final int ORIENTATION = styleable.GridLayout_orientation;
- private static final int ROW_COUNT = styleable.GridLayout_rowCount;
- private static final int COLUMN_COUNT = styleable.GridLayout_columnCount;
- private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins;
- private static final int ALIGNMENT_MODE = styleable.GridLayout_alignmentMode;
- private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved;
- private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved;
+ private static final int ORIENTATION = R.styleable.GridLayout_orientation;
+ private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
+ private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
+ private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
+ private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
+ private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
+ private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
// Instance variables
@@ -201,6 +199,7 @@
private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
private int mDefaultGravity = Gravity.NO_GRAVITY;
+ private int mDefaultGap;
// Constructors
@@ -212,7 +211,8 @@
if (DEBUG) {
setWillNotDraw(false);
}
- TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout);
+ mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
@@ -382,7 +382,7 @@
public void setUseDefaultMargins(boolean useDefaultMargins) {
mUseDefaultMargins = useDefaultMargins;
if (useDefaultMargins) {
- int padding = DEFAULT_CONTAINER_PADDING;
+ int padding = mDefaultGap;
setPadding(padding, padding, padding, padding);
}
requestLayout();
@@ -538,7 +538,7 @@
}
private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
- return DEFAULT_MARGIN;
+ return mDefaultGap / 2;
}
private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
@@ -787,6 +787,12 @@
invalidateStructure();
}
+ @Override
+ public void removeAllViews() {
+ super.removeAllViews();
+ invalidateStructure();
+ }
+
// Measurement
private boolean isGone(View c) {
@@ -1596,8 +1602,8 @@
* each cell group. The fundamental parameters associated with each cell group are
* gathered into their vertical and horizontal components and stored
* in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
- * {@link android.widget.GridLayout.Spec Specs} are immutable structures and may be shared between the layout
- * parameters of different children.
+ * {@link android.widget.GridLayout.Spec Specs} are immutable structures
+ * and may be shared between the layout parameters of different children.
* <p>
* The row and column specs contain the leading and trailing indices along each axis
* and together specify the four grid indices that delimit the cells of this cell group.
@@ -1667,24 +1673,25 @@
// TypedArray indices
- private static final int MARGIN = styleable.ViewGroup_MarginLayout_layout_margin;
- private static final int LEFT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginLeft;
- private static final int TOP_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginTop;
- private static final int RIGHT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginRight;
+ private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin;
+ private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft;
+ private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop;
+ private static final int RIGHT_MARGIN =
+ R.styleable.ViewGroup_MarginLayout_layout_marginRight;
private static final int BOTTOM_MARGIN =
- styleable.ViewGroup_MarginLayout_layout_marginBottom;
+ R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
- private static final int COLUMN = styleable.GridLayout_Layout_layout_column;
- private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan;
+ private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
+ private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
private static final int COLUMN_FLEXIBILITY =
- styleable.GridLayout_Layout_layout_columnFlexibility;
+ R.styleable.GridLayout_Layout_layout_columnFlexibility;
- private static final int ROW = styleable.GridLayout_Layout_layout_row;
- private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan;
+ private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
+ private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
private static final int ROW_FLEXIBILITY =
- styleable.GridLayout_Layout_layout_rowFlexibility;
+ R.styleable.GridLayout_Layout_layout_rowFlexibility;
- private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity;
+ private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
// Instance variables
@@ -1804,7 +1811,8 @@
// This method could be parametrized and moved into MarginLayout.
private void reInitSuper(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, styleable.ViewGroup_MarginLayout);
+ TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
try {
int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
@@ -1840,7 +1848,7 @@
}
private void init(Context context, AttributeSet attrs, int defaultGravity) {
- TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
try {
int gravity = a.getInt(GRAVITY, defaultGravity);
@@ -2301,10 +2309,10 @@
*/
@Deprecated
public static class Group extends Spec {
- /**
- * @deprecated Please replace with {@link #spec(int, int, Alignment)}
- * @hide
- */
+ /**
+ * @deprecated Please replace with {@link #spec(int, int, Alignment)}
+ * @hide
+ */
@Deprecated
public Group(int start, int size, Alignment alignment) {
super(start, size, alignment, UNDEFINED_FLEXIBILITY);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index f3bda43..b2d1a1e 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -18,8 +18,6 @@
import static android.widget.SuggestionsAdapter.getColumnString;
-import com.android.internal.R;
-
import android.app.PendingIntent;
import android.app.SearchManager;
import android.app.SearchableInfo;
@@ -39,10 +37,14 @@
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -51,6 +53,8 @@
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.TextView.OnEditorActionListener;
+import com.android.internal.R;
+
import java.util.WeakHashMap;
/**
@@ -87,6 +91,8 @@
private View mSearchEditFrame;
private View mVoiceButton;
private SearchAutoComplete mQueryTextView;
+ private View mDropDownAnchor;
+ private ImageView mSearchHintIcon;
private boolean mSubmitButtonEnabled;
private CharSequence mQueryHint;
private boolean mQueryRefinement;
@@ -195,6 +201,7 @@
mSubmitButton = findViewById(R.id.search_go_btn);
mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
mVoiceButton = findViewById(R.id.search_voice_btn);
+ mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon);
mSearchButton.setOnClickListener(mOnClickListener);
mCloseButton.setOnClickListener(mOnClickListener);
@@ -244,7 +251,20 @@
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mDropDownAnchor = findViewById(mQueryTextView.getDropDownAnchor());
+ if (mDropDownAnchor != null) {
+ mDropDownAnchor.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ adjustDropDownSizeAndPosition();
+ }
+
+ });
+ }
+
updateViewsVisibility(mIconifiedByDefault);
+ updateQueryHint();
}
/**
@@ -263,7 +283,7 @@
}
// Cache the voice search capability
mVoiceButtonEnabled = hasVoiceSearch();
- updateViewsVisibility(mIconifiedByDefault);
+ updateViewsVisibility(isIconified());
}
/**
@@ -300,7 +320,6 @@
mQueryTextView.clearFocus();
setImeVisibility(false);
mClearingFocus = false;
- updateViewsVisibility(mIconifiedByDefault);
}
/**
@@ -555,6 +574,7 @@
mSearchButton.setVisibility(visCollapsed);
updateSubmitButton(hasText);
mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
+ mSearchHintIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
updateCloseButton();
updateVoiceButton(!hasText);
updateSubmitArea();
@@ -822,9 +842,29 @@
return result;
}
+ private int getSearchIconId() {
+ TypedValue outValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(com.android.internal.R.attr.searchViewSearchIcon,
+ outValue, true);
+ return outValue.resourceId;
+ }
+
+ private CharSequence getDecoratedHint(CharSequence hintText) {
+ // If the field is always expanded, then don't add the search icon to the hint
+ if (!mIconifiedByDefault) return hintText;
+
+ SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon
+ ssb.append(hintText);
+ Drawable searchIcon = getContext().getResources().getDrawable(getSearchIconId());
+ int textSize = (int) (mQueryTextView.getTextSize() * 1.25);
+ searchIcon.setBounds(0, 0, textSize, textSize);
+ ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return ssb;
+ }
+
private void updateQueryHint() {
if (mQueryHint != null) {
- mQueryTextView.setHint(mQueryHint);
+ mQueryTextView.setHint(getDecoratedHint(mQueryHint));
} else if (mSearchable != null) {
CharSequence hint = null;
int hintId = mSearchable.getHintId();
@@ -832,8 +872,10 @@
hint = getContext().getString(hintId);
}
if (hint != null) {
- mQueryTextView.setHint(hint);
+ mQueryTextView.setHint(getDecoratedHint(hint));
}
+ } else {
+ mQueryTextView.setHint(getDecoratedHint(""));
}
}
@@ -922,9 +964,13 @@
CharSequence text = mQueryTextView.getText();
if (TextUtils.isEmpty(text)) {
if (mIconifiedByDefault) {
- // query field already empty, hide the keyboard and remove focus
- clearFocus();
- setImeVisibility(false);
+ // If the app doesn't override the close behavior
+ if (mOnCloseListener == null || !mOnCloseListener.onClose()) {
+ // hide the keyboard and remove focus
+ clearFocus();
+ // collapse the search field
+ updateViewsVisibility(true);
+ }
}
} else {
mQueryTextView.setText("");
@@ -932,10 +978,6 @@
setImeVisibility(true);
}
- if (mIconifiedByDefault && (mOnCloseListener == null || !mOnCloseListener.onClose())) {
- updateViewsVisibility(mIconifiedByDefault);
- setImeVisibility(false);
- }
}
private void onSearchClicked() {
@@ -975,6 +1017,28 @@
updateFocusedState(mQueryTextView.hasFocus());
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ }
+
+ private void adjustDropDownSizeAndPosition() {
+ if (mDropDownAnchor.getWidth() > 1) {
+ Resources res = getContext().getResources();
+ int anchorPadding = mSearchPlate.getPaddingLeft();
+ Rect dropDownPadding = new Rect();
+ int iconOffset = mIconifiedByDefault
+ ? res.getDimensionPixelSize(R.dimen.dropdownitem_icon_width)
+ + res.getDimensionPixelSize(R.dimen.dropdownitem_text_padding_left)
+ : 0;
+ mQueryTextView.getDropDownBackground().getPadding(dropDownPadding);
+ mQueryTextView.setDropDownHorizontalOffset(-(dropDownPadding.left + iconOffset)
+ + anchorPadding);
+ mQueryTextView.setDropDownWidth(mDropDownAnchor.getWidth() + dropDownPadding.left
+ + dropDownPadding.right + iconOffset - (anchorPadding));
+ }
+ }
+
private boolean onItemClicked(int position, int actionKey, String actionMsg) {
if (mOnSuggestionListener == null
|| !mOnSuggestionListener.onSuggestionClick(position)) {
@@ -1393,5 +1457,32 @@
public boolean enoughToFilter() {
return mThreshold <= 0 || super.enoughToFilter();
}
+
+ @Override
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ // special case for the back key, we do not even try to send it
+ // to the drop down list but instead, consume it immediately
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.startTracking(event, this);
+ }
+ return true;
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.handleUpEvent(event);
+ }
+ if (event.isTracking() && !event.isCanceled()) {
+ mSearchView.clearFocus();
+ mSearchView.setImeVisibility(false);
+ return true;
+ }
+ }
+ }
+ return super.onKeyPreIme(keyCode, event);
+ }
+
}
}
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 2e0cc62..665109a 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -162,14 +162,17 @@
.setOnMenuItemClickListener(mOnMenuItemClickListener);
}
- // Add a sub-menu for showing all activities as a list item.
- SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
- collapsedActivityCount, mContext.getString(R.string.activity_chooser_view_see_all));
- for (int i = 0; i < expandedActivityCount; i++) {
- ResolveInfo activity = dataModel.getActivity(i);
- expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
- .setIcon(activity.loadIcon(packageManager))
- .setOnMenuItemClickListener(mOnMenuItemClickListener);
+ if (collapsedActivityCount < expandedActivityCount) {
+ // Add a sub-menu for showing all activities as a list item.
+ SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
+ collapsedActivityCount,
+ mContext.getString(R.string.activity_chooser_view_see_all));
+ for (int i = 0; i < expandedActivityCount; i++) {
+ ResolveInfo activity = dataModel.getActivity(i);
+ expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
+ .setIcon(activity.loadIcon(packageManager))
+ .setOnMenuItemClickListener(mOnMenuItemClickListener);
+ }
}
}
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index 2cfc016..9e32c9a 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.app.SearchDialog;
import android.app.SearchManager;
import android.app.SearchableInfo;
@@ -47,6 +45,8 @@
import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import com.android.internal.R;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -88,8 +88,8 @@
private int mIconName2Col = INVALID_INDEX;
private int mFlagsCol = INVALID_INDEX;
- private final Runnable mStartSpinnerRunnable;
- private final Runnable mStopSpinnerRunnable;
+ // private final Runnable mStartSpinnerRunnable;
+ // private final Runnable mStopSpinnerRunnable;
/**
* The amount of time we delay in the filter when the user presses the delete key.
@@ -113,17 +113,18 @@
mOutsideDrawablesCache = outsideDrawablesCache;
- mStartSpinnerRunnable = new Runnable() {
- public void run() {
- // mSearchView.setWorking(true); // TODO:
- }
- };
- mStopSpinnerRunnable = new Runnable() {
- public void run() {
- // mSearchView.setWorking(false); // TODO:
- }
- };
+ // mStartSpinnerRunnable = new Runnable() {
+ // public void run() {
+ // // mSearchView.setWorking(true); // TODO:
+ // }
+ // };
+ //
+ // mStopSpinnerRunnable = new Runnable() {
+ // public void run() {
+ // // mSearchView.setWorking(false); // TODO:
+ // }
+ // };
// delay 500ms when deleting
getFilter().setDelayer(new Filter.Delayer() {
@@ -341,10 +342,10 @@
}
if (views.mIcon1 != null) {
- setViewDrawable(views.mIcon1, getIcon1(cursor));
+ setViewDrawable(views.mIcon1, getIcon1(cursor), View.INVISIBLE);
}
if (views.mIcon2 != null) {
- setViewDrawable(views.mIcon2, getIcon2(cursor));
+ setViewDrawable(views.mIcon2, getIcon2(cursor), View.GONE);
}
if (mQueryRefinement == REFINE_ALL
|| (mQueryRefinement == REFINE_BY_ENTRY
@@ -414,13 +415,13 @@
* Sets the drawable in an image view, makes sure the view is only visible if there
* is a drawable.
*/
- private void setViewDrawable(ImageView v, Drawable drawable) {
+ private void setViewDrawable(ImageView v, Drawable drawable, int nullVisibility) {
// Set the icon even if the drawable is null, since we need to clear any
// previous icon.
v.setImageDrawable(drawable);
if (drawable == null) {
- v.setVisibility(View.GONE);
+ v.setVisibility(nullVisibility);
} else {
v.setVisibility(View.VISIBLE);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 769f5e3..66a07d3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -117,7 +117,7 @@
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
@@ -3731,13 +3731,13 @@
Handler h = getHandler();
if (h != null) {
long eventTime = SystemClock.uptimeMillis();
- h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
| KeyEvent.FLAG_EDITOR_ACTION)));
- h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 9e37c7b..f3d891d 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -33,7 +33,7 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
@@ -501,7 +501,7 @@
} else {
- ViewAncestor viewRoot = getOwnerViewAncestor();
+ ViewRootImpl viewRoot = getOwnerViewRootImpl();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
}
@@ -526,15 +526,15 @@
}
}
- private ViewAncestor getOwnerViewAncestor() {
+ private ViewRootImpl getOwnerViewRootImpl() {
View rootViewOfOwner = mOwnerView.getRootView();
if (rootViewOfOwner == null) {
return null;
}
ViewParent parentOfRootView = rootViewOfOwner.getParent();
- if (parentOfRootView instanceof ViewAncestor) {
- return (ViewAncestor) parentOfRootView;
+ if (parentOfRootView instanceof ViewRootImpl) {
+ return (ViewRootImpl) parentOfRootView;
} else {
return null;
}
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 6039cc2..e1166f1 100755
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -23,6 +23,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.widget.Toast;
import android.util.Log;
import android.location.LocationManager;
@@ -44,8 +46,12 @@
private static final int POSITIVE_BUTTON = AlertDialog.BUTTON_POSITIVE;
private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON_NEGATIVE;
+ private static final int GPS_NO_RESPONSE_TIME_OUT = 1;
// Received ID from intent, -1 when no notification is in progress
private int notificationId = -1;
+ private int timeout = -1;
+ private int default_response = -1;
+ private int default_response_timeout = 6;
/** Used to detect when NI request is received */
private BroadcastReceiver mNetInitiatedReceiver = new BroadcastReceiver() {
@@ -58,6 +64,21 @@
}
};
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case GPS_NO_RESPONSE_TIME_OUT: {
+ if (notificationId != -1) {
+ sendUserResponse(default_response);
+ }
+ finish();
+ }
+ break;
+ default:
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -75,8 +96,11 @@
p.mNegativeButtonListener = this;
notificationId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
- if (DEBUG) Log.d(TAG, "onCreate, notifId: " + notificationId);
+ timeout = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TIMEOUT, default_response_timeout);
+ default_response = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_DEFAULT_RESPONSE, GpsNetInitiatedHandler.GPS_NI_RESPONSE_ACCEPT);
+ if (DEBUG) Log.d(TAG, "onCreate() : notificationId: " + notificationId + " timeout: " + timeout + " default_response:" + default_response);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(GPS_NO_RESPONSE_TIME_OUT), (timeout * 1000));
setupAlert();
}
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 3070e3e..fb33748 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -29,7 +29,7 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
import com.android.internal.R;
public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
@@ -150,7 +150,7 @@
KeyEvent event = events[i];
event = KeyEvent.changeFlags(event, event.getFlags()
| KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
- handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY, event));
+ handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY, event));
}
}
}
@@ -158,11 +158,11 @@
public void sendDownUpKeyEvents(int keyEventCode) {
long eventTime = SystemClock.uptimeMillis();
Handler handler = mTargetView.getHandler();
- handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+ handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
- handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+ handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 06dc083..514e59d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -139,6 +139,7 @@
android_bluetooth_common.cpp \
android_bluetooth_BluetoothAudioGateway.cpp \
android_bluetooth_BluetoothSocket.cpp \
+ android_bluetooth_c.c \
android_server_BluetoothService.cpp \
android_server_BluetoothEventLoop.cpp \
android_server_BluetoothA2dpService.cpp \
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 942aa8a1..682c3c4 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -799,24 +799,6 @@
x, y, flags, paint);
}
- static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
- jcharArray text, int index, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
- jchar* textArray = env->GetCharArrayElements(text, NULL);
- drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
- env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
- }
-
- static void drawTextWithGlyphs__StringIIFFIPaint(JNIEnv* env, jobject,
- SkCanvas* canvas, jstring text,
- int start, int end,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
-
- const jchar* textArray = env->GetStringChars(text, NULL);
- drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
- env->ReleaseStringChars(text, textArray);
- }
-
static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
// TODO: need to suppress this code after the GL renderer is modified for not
@@ -833,16 +815,6 @@
paint->setTextEncoding(oldEncoding);
}
- static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
- jcharArray glyphs, int index, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
- jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
-
- doDrawGlyphs(canvas, glyphArray, index, count, x, y, flags, paint);
-
- env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
- }
-
static void drawTextRun___CIIIIFFIPaint(
JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
int count, int contextIndex, int contextCount,
@@ -1044,12 +1016,6 @@
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
{"native_drawText","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
- {"native_drawTextWithGlyphs","(I[CIIFFII)V",
- (void*) SkCanvasGlue::drawTextWithGlyphs___CIIFFIPaint},
- {"native_drawTextWithGlyphs","(ILjava/lang/String;IIFFII)V",
- (void*) SkCanvasGlue::drawTextWithGlyphs__StringIIFFIPaint},
- {"native_drawGlyphs","(I[CIIFFII)V",
- (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
{"native_drawTextRun","(I[CIIIIFFII)V",
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
{"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 6a13876..30fe298 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -323,9 +323,7 @@
void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font,
FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count,
- size_t contextCount, int dirFlags) {
- bool isRTL = dirFlags & 0x1;
-
+ size_t contextCount, bool isRTL) {
font->klass = &harfbuzzSkiaClass;
font->userData = 0;
// The values which harfbuzzSkiaClass returns are already scaled to
@@ -374,10 +372,10 @@
void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font,
FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count,
- size_t contextCount, int dirFlags) {
+ size_t contextCount, bool isRTL) {
// Setup Harfbuzz Shaper
setupShaperItem(shaperItem, font, fontData, paint, chars, start, count,
- contextCount, dirFlags);
+ contextCount, isRTL);
// Shape
resetGlyphArrays(shaperItem);
@@ -430,7 +428,7 @@
LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d",
forceLTR, forceRTL);
#endif
- computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+ computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, forceRTL,
outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
if (forceRTL && *outGlyphsCount > 1) {
@@ -451,10 +449,15 @@
LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir);
#endif
if (rc == 1 || !U_SUCCESS(status)) {
+ bool isRTL = (paraDir == 1);
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- processing SINGLE run "
+ "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL);
+#endif
computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount,
- dirFlags, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
+ isRTL, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
- if (dirFlags == 1 && *outGlyphsCount > 1) {
+ if (isRTL && *outGlyphsCount > 1) {
reverseGlyphArray(*outGlyphs, *outGlyphsCount);
}
} else {
@@ -485,14 +488,14 @@
lengthRun = endRun - startRun;
- int newFlags = (runDir == UBIDI_RTL) ? kDirection_RTL : kDirection_LTR;
+ bool isRTL = (runDir == UBIDI_RTL);
jfloat runTotalAdvance = 0;
#if DEBUG_GLYPHS
- LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d newFlags=%d",
- startRun, lengthRun, newFlags);
+ LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d isRTL=%d",
+ startRun, lengthRun, isRTL);
#endif
computeRunValuesWithHarfbuzz(paint, chars, startRun,
- lengthRun, contextCount, newFlags,
+ lengthRun, contextCount, isRTL,
outAdvances, &runTotalAdvance,
&runGlyphs, &runGlyphsCount);
@@ -506,7 +509,7 @@
LOGD(" -- glyphs[%d]=%d", j, runGlyphs[j]);
}
#endif
- glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, newFlags));
+ glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, isRTL));
}
*outGlyphs = new jchar[*outGlyphsCount];
@@ -528,13 +531,15 @@
ubidi_close(bidi);
} else {
// Cannot run BiDi, just consider one Run
+ bool isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
#if DEBUG_GLYPHS
- LOGD("computeValuesWithHarfbuzz -- cannot run BiDi, considering only one Run");
+ LOGD("computeValuesWithHarfbuzz -- cannot run BiDi, considering a SINGLE Run "
+ "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL);
#endif
- computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+ computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, isRTL,
outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
- if (dirFlags == 1 && *outGlyphsCount > 1) {
+ if (isRTL && *outGlyphsCount > 1) {
reverseGlyphArray(*outGlyphs, *outGlyphsCount);
}
}
@@ -545,17 +550,15 @@
}
void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
- size_t start, size_t count, size_t contextCount, int dirFlags,
+ size_t start, size_t count, size_t contextCount, bool isRTL,
jfloat* outAdvances, jfloat* outTotalAdvance,
jchar** outGlyphs, size_t* outGlyphsCount) {
- bool isRTL = dirFlags & 0x1;
-
HB_ShaperItem shaperItem;
HB_FontRec font;
FontData fontData;
shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count,
- contextCount, dirFlags);
+ contextCount, isRTL);
#if DEBUG_GLYPHS
LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs,
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 690caac..10dee87 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -128,11 +128,11 @@
static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
- int dirFlags);
+ bool isRTL);
static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
- int dirFlags);
+ bool isRTL);
static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
size_t count, size_t contextCount, int dirFlags,
@@ -179,7 +179,7 @@
static void resetGlyphArrays(HB_ShaperItem* shaperItem);
static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
- size_t count, size_t contextCount, int dirFlags,
+ size_t count, size_t contextCount, bool isRTL,
jfloat* outAdvances, jfloat* outTotalAdvance,
jchar** outGlyphs, size_t* outGlyphsCount);
}; // TextLayoutCacheValue
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
index cb742a3..29c9c2d 100755
--- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BluetoothAudioGateway.cpp"
#include "android_bluetooth_common.h"
+#include "android_bluetooth_c.h"
#include "android_runtime/AndroidRuntime.h"
#include "JNIHelp.h"
#include "jni.h"
@@ -491,7 +492,8 @@
}
laddr.rc_family = AF_BLUETOOTH;
- memcpy(&laddr.rc_bdaddr, BDADDR_ANY, sizeof(bdaddr_t));
+ bdaddr_t any = android_bluetooth_bdaddr_any();
+ memcpy(&laddr.rc_bdaddr, &any, sizeof(bdaddr_t));
laddr.rc_channel = channel;
if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
index d09c4e9..4c84324 100644
--- a/core/jni/android_bluetooth_BluetoothSocket.cpp
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BluetoothSocket.cpp"
#include "android_bluetooth_common.h"
+#include "android_bluetooth_c.h"
#include "android_runtime/AndroidRuntime.h"
#include "JNIHelp.h"
#include "utils/Log.h"
@@ -245,7 +246,7 @@
jint type;
socklen_t addr_sz;
struct sockaddr *addr;
- bdaddr_t bdaddr = *BDADDR_ANY;
+ bdaddr_t bdaddr = android_bluetooth_bdaddr_any();
struct asocket *s = get_socketData(env, obj);
if (!s)
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml b/core/jni/android_bluetooth_c.c
old mode 100644
new mode 100755
similarity index 63%
copy from packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
copy to core/jni/android_bluetooth_c.c
index f9bba2a..b4c6727
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
+++ b/core/jni/android_bluetooth_c.c
@@ -1,7 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
+/*
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +13,19 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
--->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
- <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
-</transition>
+
+#ifdef HAVE_BLUETOOTH
+
+#include "android_bluetooth_c.h"
+
+/*
+ * A C helper for creating a bdaddr_t object with the value BDADDR_ANY.
+ * We have to do this in C because the macro BDADDR_ANY in bluetooth.h
+ * is not valid C++ code.
+ */
+bdaddr_t android_bluetooth_bdaddr_any(void)
+{
+ bdaddr_t any = *BDADDR_ANY;
+ return any;
+}
+#endif
diff --git a/core/jni/android_bluetooth_c.h b/core/jni/android_bluetooth_c.h
new file mode 100644
index 0000000..e890244
--- /dev/null
+++ b/core/jni/android_bluetooth_c.h
@@ -0,0 +1,39 @@
+/*
+** Copyright 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.
+*/
+
+#ifndef ANDROID_BLUETOOTH_C_H
+#define ANDROID_BLUETOOTH_C_H
+#ifdef HAVE_BLUETOOTH
+
+#include <bluetooth/bluetooth.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A C helper for creating a bdaddr_t object with the value BDADDR_ANY.
+ * We have to do this in C because the macro BDADDR_ANY in bluetooth.h
+ * is not valid C++ code.
+ */
+bdaddr_t android_bluetooth_bdaddr_any(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*HAVE_BLUETOOTH*/
+#endif /*ANDROID_BLUETOOTH_C_H*/
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 681f43f..b0c2f2c 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -127,6 +127,13 @@
}
}
+static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
+ Caches::FlushMode mode) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().flush(mode);
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -735,6 +742,7 @@
{ "nIsBackBufferPreserved", "()Z", (void*) android_view_GLES20Canvas_isBackBufferPreserved },
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
{ "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
+ { "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
@@ -859,10 +867,8 @@
const char* const kActivityThreadPathName = "android/app/ActivityThread";
-int register_android_app_ActivityThread(JNIEnv* env)
-{
- return AndroidRuntime::registerNativeMethods(
- env, kActivityThreadPathName,
+int register_android_app_ActivityThread(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kActivityThreadPathName,
gActivityThreadMethods, NELEM(gActivityThreadMethods));
}
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index b046b23..9484c6b 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -19,11 +19,48 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
namespace android {
// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+static struct {
+ jmethodID set;
+ jfieldID left;
+ jfieldID top;
+ jfieldID right;
+ jfieldID bottom;
+} gRectClassInfo;
+
+static struct {
+ jfieldID nativeCanvas;
+ jfieldID surfaceFormat;
+} gCanvasClassInfo;
+
+static struct {
+ jfieldID nativeWindow;
+} gTextureViewClassInfo;
+
+#define GET_INT(object, field) \
+ env->GetIntField(object, field)
+
+#define SET_INT(object, field, value) \
+ env->SetIntField(object, field, value)
+
+#define INVOKEV(object, method, ...) \
+ env->CallVoidMethod(object, method, __VA_ARGS__)
+
+// ----------------------------------------------------------------------------
// Native layer
// ----------------------------------------------------------------------------
@@ -34,6 +71,118 @@
surfaceTexture->setDefaultBufferSize(width, height);
}
+static inline SkBitmap::Config convertPixelFormat(int32_t format) {
+ switch (format) {
+ case WINDOW_FORMAT_RGBA_8888:
+ return SkBitmap::kARGB_8888_Config;
+ case WINDOW_FORMAT_RGBX_8888:
+ return SkBitmap::kARGB_8888_Config;
+ case WINDOW_FORMAT_RGB_565:
+ return SkBitmap::kRGB_565_Config;
+ default:
+ return SkBitmap::kNo_Config;
+ }
+}
+
+/**
+ * This is a private API, and this implementation is also provided in the NDK.
+ * However, the NDK links against android_runtime, which means that using the
+ * NDK implementation would create a circular dependency between the libraries.
+ */
+static int32_t native_window_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+ Rect* inOutDirtyBounds) {
+ return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
+}
+
+static int32_t native_window_unlockAndPost(ANativeWindow* window) {
+ return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
+}
+
+static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView,
+ jobject surface) {
+
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+ sp<ANativeWindow> window = new SurfaceTextureClient(surfaceTexture);
+
+ window->incStrong(0);
+ SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
+}
+
+static void android_view_TextureView_destroyNativeWindow(JNIEnv* env, jobject textureView) {
+
+ ANativeWindow* nativeWindow = (ANativeWindow*)
+ GET_INT(textureView, gTextureViewClassInfo.nativeWindow);
+
+ if (nativeWindow) {
+ sp<ANativeWindow> window(nativeWindow);
+ window->decStrong(0);
+ SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0);
+ }
+}
+
+static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
+ jint nativeWindow, jobject canvas, jobject dirtyRect) {
+
+ if (!nativeWindow) {
+ return;
+ }
+
+ ANativeWindow_Buffer buffer;
+
+ Rect rect;
+ if (dirtyRect) {
+ rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
+ rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
+ rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
+ rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
+ } else {
+ rect.set(Rect(0x3FFF, 0x3FFF));
+ }
+
+ sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
+ native_window_lock(window.get(), &buffer, &rect);
+
+ ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format);
+
+ SkBitmap bitmap;
+ bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount);
+
+ if (buffer.format == WINDOW_FORMAT_RGBX_8888) {
+ bitmap.setIsOpaque(true);
+ }
+
+ if (buffer.width > 0 && buffer.height > 0) {
+ bitmap.setPixels(buffer.bits);
+ } else {
+ bitmap.setPixels(NULL);
+ }
+
+ SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format);
+ SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+ nativeCanvas->setBitmapDevice(bitmap);
+
+ SkRect clipRect;
+ clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
+ nativeCanvas->clipRect(clipRect);
+
+ if (dirtyRect) {
+ INVOKEV(dirtyRect, gRectClassInfo.set,
+ int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
+ }
+}
+
+static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
+ jint nativeWindow, jobject canvas) {
+
+ SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+ nativeCanvas->setBitmapDevice(SkBitmap());
+
+ if (nativeWindow) {
+ sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
+ native_window_unlockAndPost(window.get());
+ }
+}
+
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -42,10 +191,47 @@
static JNINativeMethod gMethods[] = {
{ "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V",
- (void*) android_view_TextureView_setDefaultBufferSize }
+ (void*) android_view_TextureView_setDefaultBufferSize },
+
+ { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
+ (void*) android_view_TextureView_createNativeWindow },
+ { "nDestroyNativeWindow", "()V",
+ (void*) android_view_TextureView_destroyNativeWindow },
+
+ { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V",
+ (void*) android_view_TextureView_lockCanvas },
+ { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
+ (void*) android_view_TextureView_unlockCanvasAndPost },
};
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(!var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(!var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(!var, "Unable to find field" fieldName);
+
int register_android_view_TextureView(JNIEnv* env) {
+ jclass clazz;
+ FIND_CLASS(clazz, "android/graphics/Rect");
+ GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
+ GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
+ GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
+ GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
+ GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
+
+ FIND_CLASS(clazz, "android/graphics/Canvas");
+ GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I");
+ GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I");
+
+ FIND_CLASS(clazz, "android/view/TextureView");
+ GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I");
+
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/res/res/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml
index 902b3c0..50b1878 100644
--- a/core/res/res/layout/activity_chooser_view.xml
+++ b/core/res/res/layout/activity_chooser_view.xml
@@ -23,13 +23,9 @@
style="?android:attr/actionButtonStyle">
<ImageButton android:id="@+id/default_activity_button"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginRight="8dip" />
+ style="@style/Widget.ActivityChooserViewButton" />
<ImageButton android:id="@+id/expand_activities_button"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginLeft="8dip" />
+ style="@style/Widget.ActivityChooserViewButton" />
</LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_view_list_item.xml b/core/res/res/layout/activity_chooser_view_list_item.xml
index f90044e..88498d9 100644
--- a/core/res/res/layout/activity_chooser_view_list_item.xml
+++ b/core/res/res/layout/activity_chooser_view_list_item.xml
@@ -20,6 +20,7 @@
android:layout_height="?android:attr/dropdownListPreferredItemHeight"
android:paddingLeft="16dip"
android:paddingRight="16dip"
+ android:minWidth="196dip"
android:background="?android:attr/activatedBackgroundIndicator"
android:orientation="vertical" >
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index 790ac6b..f6b5b53 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -66,7 +66,6 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxWidth="600dip"
- android:iconifiedByDefault="false"
android:layout_gravity="center_vertical"
/>
diff --git a/core/res/res/layout/search_dropdown_item_icons_2line.xml b/core/res/res/layout/search_dropdown_item_icons_2line.xml
index 53906f9..acef2cc 100644
--- a/core/res/res/layout/search_dropdown_item_icons_2line.xml
+++ b/core/res/res/layout/search_dropdown_item_icons_2line.xml
@@ -19,21 +19,21 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:paddingLeft="4dip"
- android:paddingRight="2dip"
+ android:paddingLeft="@dimen/dropdownitem_text_padding_left"
+ android:paddingRight="4dip"
android:layout_width="match_parent"
android:layout_height="?android:attr/searchResultListItemHeight" >
<!-- Icons come first in the layout, since their placement doesn't depend on
the placement of the text views. -->
<ImageView android:id="@android:id/icon1"
- android:layout_width="48dip"
+ android:layout_width="@dimen/dropdownitem_icon_width"
android:layout_height="48dip"
android:scaleType="centerInside"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
- android:visibility="gone" />
+ android:visibility="invisible" />
<ImageView android:id="@+id/edit_query"
android:layout_width="48dip"
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index fee27eb..6b70d8d 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -22,6 +22,8 @@
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
android:orientation="horizontal"
>
@@ -30,7 +32,7 @@
android:id="@+id/search_badge"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
+ android:gravity="center_vertical"
android:layout_marginBottom="2dip"
android:drawablePadding="0dip"
android:textAppearance="?android:attr/textAppearanceMedium"
@@ -54,12 +56,21 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip"
android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/search_mag_icon"
+ android:layout_width="@dimen/dropdownitem_icon_width"
+ android:layout_height="wrap_content"
+ android:scaleType="centerInside"
+ android:layout_marginLeft="@dimen/dropdownitem_text_padding_left"
+ android:layout_gravity="center_vertical"
+ android:src="?android:attr/searchViewSearchIcon"
+ android:visibility="gone"
+ />
+
<!-- Inner layout contains the app icon, button(s) and EditText -->
<LinearLayout
android:id="@+id/search_plate"
@@ -70,14 +81,6 @@
android:orientation="horizontal"
android:background="?android:attr/searchViewTextField">
- <ImageView
- android:id="@+id/search_app_icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:src="?android:attr/searchViewSearchIcon"
- />
-
<view class="android.widget.SearchView$SearchAutoComplete"
android:id="@+id/search_src_text"
android:layout_height="36dip"
@@ -85,8 +88,8 @@
android:layout_weight="1"
android:minWidth="@dimen/search_view_text_min_width"
android:layout_gravity="bottom"
- android:paddingLeft="8dip"
- android:paddingRight="6dip"
+ android:paddingLeft="@dimen/dropdownitem_text_padding_left"
+ android:paddingRight="@dimen/dropdownitem_text_padding_right"
android:singleLine="true"
android:ellipsize="end"
android:background="@null"
@@ -100,7 +103,7 @@
<ImageView
android:id="@+id/search_close_btn"
- android:layout_width="wrap_content"
+ android:layout_width="@dimen/dropdownitem_icon_width"
android:layout_height="match_parent"
android:paddingLeft="8dip"
android:paddingRight="8dip"
@@ -131,7 +134,7 @@
android:visibility="gone"
android:focusable="true"
/>
-
+
<ImageView
android:id="@+id/search_voice_btn"
android:layout_width="wrap_content"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9613712..d0361ca 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2302,6 +2302,8 @@
<!-- Flag whether the accessibility service wants to be able to retrieve the
active window content. This setting cannot be changed at runtime. -->
<attr name="canRetrieveWindowContent" format="boolean" />
+ <!-- Short description of the accessibility serivce purpose or behavior.-->
+ <attr name="description" />
</declare-styleable>
<!-- =============================== -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index abc56ec..2ba4e66 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -138,4 +138,16 @@
<!-- Minimum popup width for selecting an activity in ActivityChooserDialog/ActivityChooserView. -->
<dimen name="activity_chooser_popup_min_width">200dip</dimen>
+ <!-- The default gap between components in a layout. -->
+ <dimen name="default_gap">16dip</dimen>
+
+ <!-- Text padding for dropdown items -->
+ <dimen name="dropdownitem_text_padding_left">6dip</dimen>
+
+ <!-- Text padding for dropdown items -->
+ <dimen name="dropdownitem_text_padding_right">6dip</dimen>
+
+ <!-- Width of the icon in a dropdown list -->
+ <dimen name="dropdownitem_icon_width">48dip</dimen>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6dedc83..f464623 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1787,6 +1787,11 @@
<public type="attr" name="colorActivatedHighlight" />
<public type="attr" name="colorMultiSelectHighlight" />
+ <public type="attr" name="drawableStart" />
+ <public type="attr" name="drawableEnd" />
+
+ <public type="attr" name="actionModeStyle" />
+
<public type="style" name="TextAppearance.SuggestionHighlight" />
<public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
<public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
@@ -1826,7 +1831,4 @@
<public type="color" name="holo_purple" />
<public type="color" name="holo_blue_bright" />
- <public type="attr" name="drawableStart" />
- <public type="attr" name="drawableEnd" />
-
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6b75146..d647467 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -563,8 +563,8 @@
<style name="Widget.DropDownItem">
<item name="android:textAppearance">@style/TextAppearance.Widget.DropDownItem</item>
- <item name="android:paddingLeft">6dip</item>
- <item name="android:paddingRight">6dip</item>
+ <item name="android:paddingLeft">@dimen/dropdownitem_text_padding_left</item>
+ <item name="android:paddingRight">@dimen/dropdownitem_text_padding_right</item>
<item name="android:gravity">center_vertical</item>
</style>
@@ -713,6 +713,16 @@
<item name="android:quickContactWindowSize">modeLarge</item>
</style>
+ <style name="Widget.ActivityChooserViewButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:adjustViewBounds">true</item>
+ <item name="android:scaleType">fitCenter</item>
+ <item name="android:padding">@android:dimen/action_bar_icon_vertical_padding</item>
+ </style>
+
<!-- Text Appearances -->
<eat-comment />
diff --git a/core/tests/coretests/src/android/content/ObserverNodeTest.java b/core/tests/coretests/src/android/content/ObserverNodeTest.java
index 736c759..95b8465 100644
--- a/core/tests/coretests/src/android/content/ObserverNodeTest.java
+++ b/core/tests/coretests/src/android/content/ObserverNodeTest.java
@@ -48,9 +48,9 @@
int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
// special case
- root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root);
+ root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root, 0, 0);
for(int i = 1; i < uris.length; i++) {
- root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root);
+ root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root, 0, 0);
}
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
@@ -77,7 +77,7 @@
int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
for(int i = 0; i < uris.length; i++) {
- root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root);
+ root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root, 0, 0);
}
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java
index b5c2c27..440aeb5 100644
--- a/core/tests/coretests/src/android/util/JsonReaderTest.java
+++ b/core/tests/coretests/src/android/util/JsonReaderTest.java
@@ -856,4 +856,33 @@
} catch (IOException expected) {
}
}
+
+ public void testFailWithPosition() throws IOException {
+ testFailWithPosition("Expected literal value at line 6 column 3",
+ "[\n\n\n\n\n0,}]");
+ }
+
+ public void testFailWithPositionGreaterThanBufferSize() throws IOException {
+ String spaces = repeat(' ', 8192);
+ testFailWithPosition("Expected literal value at line 6 column 3",
+ "[\n\n" + spaces + "\n\n\n0,}]");
+ }
+
+ private void testFailWithPosition(String message, String json) throws IOException {
+ JsonReader reader = new JsonReader(new StringReader(json));
+ reader.beginArray();
+ reader.nextInt();
+ try {
+ reader.peek();
+ fail();
+ } catch (IOException expected) {
+ assertEquals(message, expected.getMessage());
+ }
+ }
+
+ private String repeat(char c, int count) {
+ char[] array = new char[count];
+ Arrays.fill(array, c);
+ return new String(array);
+ }
}
diff --git a/core/tests/coretests/src/android/util/JsonWriterTest.java b/core/tests/coretests/src/android/util/JsonWriterTest.java
index b29e2fd..1239a3c 100644
--- a/core/tests/coretests/src/android/util/JsonWriterTest.java
+++ b/core/tests/coretests/src/android/util/JsonWriterTest.java
@@ -289,6 +289,15 @@
+ "\"\\u0019\"]", stringWriter.toString());
}
+ public void testUnicodeLineBreaksEscaped() throws IOException {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter jsonWriter = new JsonWriter(stringWriter);
+ jsonWriter.beginArray();
+ jsonWriter.value("\u2028 \u2029");
+ jsonWriter.endArray();
+ assertEquals("[\"\\u2028 \\u2029\"]", stringWriter.toString());
+ }
+
public void testEmptyArray() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5b50f8f..35ed4d2 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1414,77 +1414,13 @@
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
- native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
+ native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
}
/**
- * Draw the text, with origin at (x,y), using the specified paint. The
- * origin is interpreted based on the Align setting in the paint.
- *
- * @param text The text to be drawn
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the origin of the text being drawn
- * @param paint The paint used for the text (e.g. color, size, style)
- *
- * @hide
- *
- * Used only for BiDi / RTL Tests
- */
- public void drawTextWithGlyphs(char[] text, int index, int count, float x, float y,
- Paint paint) {
- if ((index | count | (index + count) |
- (text.length - index - count)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- native_drawTextWithGlyphs(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
- paint.mNativePaint);
- }
-
- /**
- * Draw the text, with origin at (x,y), using the specified paint. The
- * origin is interpreted based on the Align setting in the paint.
- *
- * @param text The text to be drawn
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the origin of the text being drawn
- * @param paint The paint used for the text (e.g. color, size, style)
- *
- * @hide
- *
- * Used only for BiDi / RTL Tests
- */
- public void drawTextWithGlyphs(String text, float x, float y, Paint paint) {
- native_drawTextWithGlyphs(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
- paint.mNativePaint);
- }
-
- /**
- * Draw the glyphs, with origin at (x,y), using the specified paint. The
- * origin is interpreted based on the Align setting in the paint.
- *
- * @param glyphs The glyphs to be drawn
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the origin of the text being drawn
- * @param paint The paint used for the text (e.g. color, size, style)
- *
- * @hide
- *
- * Used only for BiDi / RTL Tests
- */
- public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
- Paint paint) {
- if ((index | count | (index + count) |
- (glyphs.length - index - count)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
- paint.mNativePaint);
- }
-
- /**
* Render a run of all LTR or all RTL text, with shaping. This does not run
* bidi on the provided text, but renders it as a uniform right-to-left or
* left-to-right run, as indicated by dir. Alignment of the text is as
@@ -1813,16 +1749,6 @@
int start, int end, float x,
float y, int flags, int paint);
- private static native void native_drawTextWithGlyphs(int nativeCanvas, char[] text,
- int index, int count, float x,
- float y, int flags, int paint);
- private static native void native_drawTextWithGlyphs(int nativeCanvas, String text,
- int start, int end, float x,
- float y, int flags, int paint);
- private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs,
- int index, int count, float x,
- float y, int flags, int paint);
-
private static native void native_drawTextRun(int nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, int flags, int paint);
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 5ec469e..cfe2aa1 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -21,6 +21,7 @@
#include <gui/SurfaceTexture.h>
#include <ui/egl/android_natives.h>
+#include <ui/Region.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -37,29 +38,24 @@
sp<ISurfaceTexture> getISurfaceTexture() const;
-private:
- friend class Surface;
+protected:
+ SurfaceTextureClient();
+ void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
+private:
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
SurfaceTextureClient(const SurfaceTextureClient& rhs);
+ void init();
// ANativeWindow hooks
- static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int perform(ANativeWindow* window, int operation, ...);
- static int query(const ANativeWindow* window, int what, int* value);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int setSwapInterval(ANativeWindow* window, int interval);
-
- int cancelBuffer(ANativeWindowBuffer* buffer);
- int dequeueBuffer(ANativeWindowBuffer** buffer);
- int lockBuffer(ANativeWindowBuffer* buffer);
- int perform(int operation, va_list args);
- int query(int what, int* value) const;
- int queueBuffer(ANativeWindowBuffer* buffer);
- int setSwapInterval(int interval);
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_perform(ANativeWindow* window, int operation, ...);
+ static int hook_query(const ANativeWindow* window, int what, int* value);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_setSwapInterval(ANativeWindow* window, int interval);
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
@@ -71,26 +67,38 @@
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
int dispatchSetUsage(va_list args);
+ int dispatchLock(va_list args);
+ int dispatchUnlockAndPost(va_list args);
- int connect(int api);
- int disconnect(int api);
- int setBufferCount(int bufferCount);
- int setBuffersDimensions(int w, int h);
- int setBuffersFormat(int format);
- int setBuffersTransform(int transform);
- int setBuffersTimestamp(int64_t timestamp);
- int setCrop(Rect const* rect);
- int setUsage(uint32_t reqUsage);
+protected:
+ virtual int cancelBuffer(ANativeWindowBuffer* buffer);
+ virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
+ virtual int lockBuffer(ANativeWindowBuffer* buffer);
+ virtual int perform(int operation, va_list args);
+ virtual int query(int what, int* value) const;
+ virtual int queueBuffer(ANativeWindowBuffer* buffer);
+ virtual int setSwapInterval(int interval);
- void freeAllBuffers();
- int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
-
- int getConnectedApi() const;
+ virtual int connect(int api);
+ virtual int disconnect(int api);
+ virtual int setBufferCount(int bufferCount);
+ virtual int setBuffersDimensions(int w, int h);
+ virtual int setBuffersFormat(int format);
+ virtual int setBuffersTransform(int transform);
+ virtual int setBuffersTimestamp(int64_t timestamp);
+ virtual int setCrop(Rect const* rect);
+ virtual int setUsage(uint32_t reqUsage);
+ virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+ virtual int unlockAndPost();
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+private:
+ void freeAllBuffers();
+ int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
// mSurfaceTexture is the interface to the surface texture server. All
// operations on the surface texture client ultimately translate into
// interactions with the server using this interface.
@@ -145,6 +153,12 @@
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
+
+ // must be used from the lock/unlock thread
+ sp<GraphicBuffer> mLockedBuffer;
+ sp<GraphicBuffer> mPostedBuffer;
+ mutable Region mOldDirtyRegion;
+ bool mConnectedToCpu;
};
}; // namespace android
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index ea5a9d3..1136f6c 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -25,6 +25,8 @@
#include <utils/KeyedVector.h>
#include <utils/String8.h>
+class ANativeWindow;
+
namespace android {
class Surface;
@@ -196,6 +198,8 @@
status_t prepareAsync_l();
status_t getDuration_l(int *msec);
status_t setDataSource(const sp<IMediaPlayer>& player);
+ void disconnectNativeWindow();
+ status_t reset_l();
sp<IMediaPlayer> mPlayer;
thread_id_t mLockThreadId;
@@ -218,6 +222,8 @@
int mVideoHeight;
int mAudioSessionId;
float mSendLevel;
+ sp<ANativeWindow> mConnectedWindow;
+ sp<IBinder> mConnectedWindowBinder;
};
}; // namespace android
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index a042ddb..20fcde5 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -355,7 +355,7 @@
status_t QueryCodecs(
const sp<IOMX> &omx,
- const char *mimeType, bool queryDecoders,
+ const char *mimeType, bool queryDecoders, bool hwCodecOnly,
Vector<CodecCapabilities> *results);
} // namespace android
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index dc2a845..c2a494d 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -28,6 +28,8 @@
#include <ui/Region.h>
#include <ui/egl/android_natives.h>
+#include <gui/SurfaceTextureClient.h>
+
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
@@ -37,14 +39,9 @@
// ---------------------------------------------------------------------------
-class GraphicBuffer;
-class GraphicBufferMapper;
-class IOMX;
class ISurfaceTexture;
-class Rect;
class Surface;
class SurfaceComposerClient;
-class SurfaceTextureClient;
// ---------------------------------------------------------------------------
@@ -129,8 +126,7 @@
// ---------------------------------------------------------------------------
-class Surface
- : public EGLNativeBase<ANativeWindow, Surface, RefBase>
+class Surface : public SurfaceTextureClient
{
public:
struct SurfaceInfo {
@@ -158,32 +154,14 @@
sp<ISurfaceTexture> getSurfaceTexture();
// the lock/unlock APIs must be used from the same thread
- status_t lock(SurfaceInfo* info, bool blocking = true);
- status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+ status_t lock(SurfaceInfo* info, Region* dirty = NULL);
status_t unlockAndPost();
sp<IBinder> asBinder() const;
private:
- /*
- * Android frameworks friends
- * (eventually this should go away and be replaced by proper APIs)
- */
- // camera and camcorder need access to the ISurface binder interface for preview
- friend class CameraService;
- friend class MediaRecorder;
- // MediaPlayer needs access to ISurface for display
- friend class MediaPlayer;
- friend class IOMX;
- friend class SoftwareRenderer;
// this is just to be able to write some unit tests
friend class Test;
- // videoEditor preview classes
- friend class VideoEditorPreviewController;
- friend class PreviewRenderer;
-
-private:
- friend class SurfaceComposerClient;
friend class SurfaceControl;
// can't be copied
@@ -194,62 +172,27 @@
Surface(const Parcel& data, const sp<IBinder>& ref);
~Surface();
-
- /*
- * ANativeWindow hooks
- */
- static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int query(const ANativeWindow* window, int what, int* value);
- static int perform(ANativeWindow* window, int operation, ...);
-
- int setSwapInterval(int interval);
- int dequeueBuffer(ANativeWindowBuffer** buffer);
- int lockBuffer(ANativeWindowBuffer* buffer);
- int queueBuffer(ANativeWindowBuffer* buffer);
- int cancelBuffer(ANativeWindowBuffer* buffer);
- int query(int what, int* value) const;
- int perform(int operation, va_list args);
-
/*
* private stuff...
*/
void init();
status_t validate(bool inCancelBuffer = false) const;
- int getConnectedApi() const;
-
static void cleanCachedSurfacesLocked();
+ virtual int query(int what, int* value) const;
+
// constants
status_t mInitCheck;
sp<ISurface> mSurface;
- sp<SurfaceTextureClient> mSurfaceTextureClient;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
-
- // protected by mSurfaceLock. These are also used from lock/unlock
- // but in that case, they must be called form the same thread.
- mutable Region mDirtyRegion;
-
- // must be used from the lock/unlock thread
- sp<GraphicBuffer> mLockedBuffer;
- sp<GraphicBuffer> mPostedBuffer;
- mutable Region mOldDirtyRegion;
- bool mReserved;
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
uint32_t mHeight;
- // Inherently thread-safe
- mutable Mutex mSurfaceLock;
- mutable Mutex mApiLock;
-
// A cache of Surface objects that have been deserialized into this process.
static Mutex sCachedSurfacesLock;
static DefaultKeyedVector<wp<IBinder>, wp<Surface> > sCachedSurfaces;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9185e1e..dabe643f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -46,59 +46,6 @@
namespace android {
-// ----------------------------------------------------------------------
-
-static status_t copyBlt(
- const sp<GraphicBuffer>& dst,
- const sp<GraphicBuffer>& src,
- const Region& reg)
-{
- // src and dst with, height and format must be identical. no verification
- // is done here.
- status_t err;
- uint8_t const * src_bits = NULL;
- err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
- LOGE_IF(err, "error locking src buffer %s", strerror(-err));
-
- uint8_t* dst_bits = NULL;
- err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
- LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
-
- Region::const_iterator head(reg.begin());
- Region::const_iterator tail(reg.end());
- if (head != tail && src_bits && dst_bits) {
- const size_t bpp = bytesPerPixel(src->format);
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- while (head != tail) {
- const Rect& r(*head++);
- ssize_t h = r.height();
- if (h <= 0) continue;
- size_t size = r.width() * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
-
- if (src_bits)
- src->unlock();
-
- if (dst_bits)
- dst->unlock();
-
- return err;
-}
-
// ============================================================================
// SurfaceControl
// ============================================================================
@@ -277,7 +224,8 @@
// ---------------------------------------------------------------------------
Surface::Surface(const sp<SurfaceControl>& surface)
- : mInitCheck(NO_INIT),
+ : SurfaceTextureClient(),
+ mInitCheck(NO_INIT),
mSurface(surface->mSurface),
mIdentity(surface->mIdentity),
mFormat(surface->mFormat), mFlags(surface->mFlags),
@@ -287,7 +235,8 @@
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : mInitCheck(NO_INIT)
+ : SurfaceTextureClient(),
+ mInitCheck(NO_INIT)
{
mSurface = interface_cast<ISurface>(ref);
mIdentity = parcel.readInt32();
@@ -363,36 +312,21 @@
void Surface::init()
{
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- ANativeWindow::query = query;
- ANativeWindow::perform = perform;
-
if (mSurface != NULL) {
sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
if (surfaceTexture != NULL) {
- mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
- mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+ setISurfaceTexture(surfaceTexture);
+ setUsage(GraphicBuffer::USAGE_HW_RENDER);
}
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-
- const_cast<int&>(ANativeWindow::minSwapInterval) =
- mSurfaceTextureClient->minSwapInterval;
-
- const_cast<int&>(ANativeWindow::maxSwapInterval) =
- mSurfaceTextureClient->maxSwapInterval;
-
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
- if (mSurfaceTextureClient != 0) {
+ if (surfaceTexture != NULL) {
mInitCheck = NO_ERROR;
}
}
@@ -402,7 +336,6 @@
{
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
- mSurfaceTextureClient.clear();
mSurface.clear();
IPCThreadState::self()->flushCommands();
}
@@ -431,77 +364,6 @@
// ----------------------------------------------------------------------------
-int Surface::setSwapInterval(ANativeWindow* window, int interval) {
- Surface* self = getSelf(window);
- return self->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- Surface* self = getSelf(window);
- return self->dequeueBuffer(buffer);
-}
-
-int Surface::cancelBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->queueBuffer(buffer);
-}
-
-int Surface::query(const ANativeWindow* window,
- int what, int* value) {
- const Surface* self = getSelf(window);
- return self->query(what, value);
-}
-
-int Surface::perform(ANativeWindow* window,
- int operation, ...) {
- va_list args;
- va_start(args, operation);
- Surface* self = getSelf(window);
- int res = self->perform(operation, args);
- va_end(args);
- return res;
-}
-
-// ----------------------------------------------------------------------------
-
-int Surface::setSwapInterval(int interval) {
- return mSurfaceTextureClient->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
- status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
- if (err == NO_ERROR) {
- mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
- }
- return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->queueBuffer(buffer);
-}
-
int Surface::query(int what, int* value) const {
switch (what) {
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
@@ -509,141 +371,39 @@
*value = 1;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
- // TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
}
- return mSurfaceTextureClient->query(what, value);
-}
-
-int Surface::perform(int operation, va_list args) {
- return mSurfaceTextureClient->perform(operation, args);
+ return SurfaceTextureClient::query(what, value);
}
// ----------------------------------------------------------------------------
-int Surface::getConnectedApi() const {
- return mSurfaceTextureClient->getConnectedApi();
-}
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
+ ANativeWindow_Buffer outBuffer;
-// ----------------------------------------------------------------------------
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
-{
- if (getConnectedApi()) {
- LOGE("Surface::lock(%p) failed. Already connected to another API",
- (ANativeWindow*)this);
- CallStack stack;
- stack.update();
- stack.dump("");
- return INVALID_OPERATION;
+ ARect temp;
+ ARect* inOutDirtyBounds = NULL;
+ if (dirtyIn) {
+ temp = dirtyIn->getBounds();
+ inOutDirtyBounds = &temp;
}
- if (mApiLock.tryLock() != NO_ERROR) {
- LOGE("calling Surface::lock from different threads!");
- CallStack stack;
- stack.update();
- stack.dump("");
- return WOULD_BLOCK;
- }
+ status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
- /* Here we're holding mApiLock */
-
- if (mLockedBuffer != 0) {
- LOGE("Surface::lock failed, already locked");
- mApiLock.unlock();
- return INVALID_OPERATION;
- }
-
- // we're intending to do software rendering from this point
- mSurfaceTextureClient->setUsage(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
- ANativeWindowBuffer* out;
- status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
- LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
- sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
- err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
- LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
- backBuffer->handle, strerror(-err));
- if (err == NO_ERROR) {
- const Rect bounds(backBuffer->width, backBuffer->height);
- const Region boundsRegion(bounds);
- Region scratch(boundsRegion);
- Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
- newDirtyRegion &= boundsRegion;
-
- // figure out if we can copy the frontbuffer back
- const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
- const bool canCopyBack = (frontBuffer != 0 &&
- backBuffer->width == frontBuffer->width &&
- backBuffer->height == frontBuffer->height &&
- backBuffer->format == frontBuffer->format &&
- !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
-
- // the dirty region we report to surfaceflinger is the one
- // given by the user (as opposed to the one *we* return to the
- // user).
- mDirtyRegion = newDirtyRegion;
-
- if (canCopyBack) {
- // copy the area that is invalid and not repainted this round
- const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
- if (!copyback.isEmpty())
- copyBlt(backBuffer, frontBuffer, copyback);
- } else {
- // if we can't copy-back anything, modify the user's dirty
- // region to make sure they redraw the whole buffer
- newDirtyRegion = boundsRegion;
- }
-
- // keep track of the are of the buffer that is "clean"
- // (ie: that will be redrawn)
- mOldDirtyRegion = newDirtyRegion;
-
- void* vaddr;
- status_t res = backBuffer->lock(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- newDirtyRegion.bounds(), &vaddr);
-
- LOGW_IF(res, "failed locking buffer (handle = %p)",
- backBuffer->handle);
-
- mLockedBuffer = backBuffer;
- other->w = backBuffer->width;
- other->h = backBuffer->height;
- other->s = backBuffer->stride;
- other->usage = backBuffer->usage;
- other->format = backBuffer->format;
- other->bits = vaddr;
- }
+ other->w = uint32_t(outBuffer.width);
+ other->h = uint32_t(outBuffer.height);
+ other->s = uint32_t(outBuffer.stride);
+ other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ other->format = uint32_t(outBuffer.format);
+ other->bits = outBuffer.bits;
}
- mApiLock.unlock();
return err;
}
-
-status_t Surface::unlockAndPost()
-{
- if (mLockedBuffer == 0) {
- LOGE("Surface::unlockAndPost failed, no locked buffer");
- return INVALID_OPERATION;
- }
- status_t err = mLockedBuffer->unlock();
- LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
-
- err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
- LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
- mLockedBuffer->handle, strerror(-err));
-
- mPostedBuffer = mLockedBuffer;
- mLockedBuffer = 0;
- return err;
+status_t Surface::unlockAndPost() {
+ return SurfaceTextureClient::unlockAndPost();
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1410481..a12d40a 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -495,7 +495,7 @@
}
status_t SurfaceTexture::connect(int api) {
- LOGV("SurfaceTexture::connect");
+ LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
int err = NO_ERROR;
switch (api) {
@@ -504,6 +504,8 @@
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi != NO_CONNECTED_API) {
+ LOGE("connect: already connected (cur=%d, req=%d)",
+ mConnectedApi, api);
err = -EINVAL;
} else {
mConnectedApi = api;
@@ -517,7 +519,7 @@
}
status_t SurfaceTexture::disconnect(int api) {
- LOGV("SurfaceTexture::disconnect");
+ LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
int err = NO_ERROR;
switch (api) {
@@ -528,6 +530,8 @@
if (mConnectedApi == api) {
mConnectedApi = NO_CONNECTED_API;
} else {
+ LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+ mConnectedApi, api);
err = -EINVAL;
}
break;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f39cabf..d5b7c89 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -24,24 +24,45 @@
namespace android {
SurfaceTextureClient::SurfaceTextureClient(
- const sp<ISurfaceTexture>& surfaceTexture):
- mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
- mReqHeight(0), mReqFormat(0), mReqUsage(0),
- mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
- mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
- mMutex() {
+ const sp<ISurfaceTexture>& surfaceTexture)
+{
+ SurfaceTextureClient::init();
+ SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
+}
+
+SurfaceTextureClient::SurfaceTextureClient() {
+ SurfaceTextureClient::init();
+}
+
+void SurfaceTextureClient::init() {
// Initialize the ANativeWindow function pointers.
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- ANativeWindow::query = query;
- ANativeWindow::perform = perform;
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ ANativeWindow::lockBuffer = hook_lockBuffer;
+ ANativeWindow::queueBuffer = hook_queueBuffer;
+ ANativeWindow::query = hook_query;
+ ANativeWindow::perform = hook_perform;
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqFormat = 0;
+ mReqUsage = 0;
+ mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ mQueryWidth = 0;
+ mQueryHeight = 0;
+ mQueryFormat = 0;
+ mConnectedToCpu = false;
+}
+
+void SurfaceTextureClient::setISurfaceTexture(
+ const sp<ISurfaceTexture>& surfaceTexture)
+{
+ mSurfaceTexture = surfaceTexture;
+
// Get a reference to the allocator.
mAllocator = mSurfaceTexture->getAllocator();
}
@@ -50,42 +71,42 @@
return mSurfaceTexture;
}
-int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
SurfaceTextureClient* c = getSelf(window);
return c->setSwapInterval(interval);
}
-int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
-int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
-int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
-int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
-int SurfaceTextureClient::query(const ANativeWindow* window,
+int SurfaceTextureClient::hook_query(const ANativeWindow* window,
int what, int* value) {
const SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
-int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
SurfaceTextureClient* c = getSelf(window);
@@ -219,7 +240,6 @@
*value = 0;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
- // TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
return NO_ERROR;
}
@@ -260,6 +280,12 @@
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
res = dispatchSetBuffersFormat(args);
break;
+ case NATIVE_WINDOW_LOCK:
+ res = dispatchLock(args);
+ break;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ res = dispatchUnlockAndPost(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -324,28 +350,37 @@
return setBuffersTimestamp(timestamp);
}
+int SurfaceTextureClient::dispatchLock(va_list args) {
+ ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+ ARect* inOutDirtyBounds = va_arg(args, ARect*);
+ return lock(outBuffer, inOutDirtyBounds);
+}
+
+int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
+ return unlockAndPost();
+}
+
+
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
Mutex::Autolock lock(mMutex);
- return mSurfaceTexture->connect(api);
+ int err = mSurfaceTexture->connect(api);
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = true;
+ }
+ return err;
}
int SurfaceTextureClient::disconnect(int api) {
LOGV("SurfaceTextureClient::disconnect");
Mutex::Autolock lock(mMutex);
- return mSurfaceTexture->disconnect(api);
+ int err = mSurfaceTexture->disconnect(api);
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = false;
+ }
+ return err;
}
-int SurfaceTextureClient::getConnectedApi() const
-{
- // XXX: This method will be going away shortly, and is currently bogus. It
- // always returns "nothing is connected". It will go away once Surface gets
- // updated to actually connect as the 'CPU' API when locking a buffer.
- Mutex::Autolock lock(mMutex);
- return 0;
-}
-
-
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
LOGV("SurfaceTextureClient::setUsage");
@@ -443,4 +478,160 @@
}
}
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ // src and dst with, height and format must be identical. no verification
+ // is done here.
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceTextureClient::lock(
+ ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+ if (mLockedBuffer != 0) {
+ LOGE("Surface::lock failed, already locked");
+ return INVALID_OPERATION;
+ }
+
+ if (!mConnectedToCpu) {
+ int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
+ if (err) {
+ return err;
+ }
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ }
+
+ ANativeWindowBuffer* out;
+ status_t err = dequeueBuffer(&out);
+ LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+ err = lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+ backBuffer->handle, strerror(-err));
+ if (err == NO_ERROR) {
+ const Rect bounds(backBuffer->width, backBuffer->height);
+
+ Region newDirtyRegion;
+ if (inOutDirtyBounds) {
+ newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+ newDirtyRegion.andSelf(bounds);
+ } else {
+ newDirtyRegion.set(bounds);
+ }
+
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format);
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion.set(bounds);
+ }
+
+ // keep track of the are of the buffer that is "clean"
+ // (ie: that will be redrawn)
+ mOldDirtyRegion = newDirtyRegion;
+
+ if (inOutDirtyBounds) {
+ *inOutDirtyBounds = newDirtyRegion.getBounds();
+ }
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ outBuffer->width = backBuffer->width;
+ outBuffer->height = backBuffer->height;
+ outBuffer->stride = backBuffer->stride;
+ outBuffer->format = backBuffer->format;
+ outBuffer->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t SurfaceTextureClient::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ LOGE("Surface::unlockAndPost failed, no locked buffer");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+ mLockedBuffer->handle, strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 519b40e..2b8f204 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -613,4 +613,90 @@
}
}
+class MultiSurfaceTextureClientTest : public ::testing::Test {
+
+public:
+ MultiSurfaceTextureClientTest() :
+ mEglDisplay(EGL_NO_DISPLAY),
+ mEglContext(EGL_NO_CONTEXT) {
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ mEglSurfaces[i] = EGL_NO_CONTEXT;
+ }
+ }
+
+protected:
+
+ enum { NUM_SURFACE_TEXTURES = 32 };
+
+ virtual void SetUp() {
+ mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+
+ EGLint majorVersion, minorVersion;
+ EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EGLConfig myConfig;
+ EGLint numConfigs = 0;
+ EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+ EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &myConfig, 1,
+ &numConfigs));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+ 0);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
+
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ sp<SurfaceTexture> st(new SurfaceTexture(i));
+ sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+ mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
+ static_cast<ANativeWindow*>(stc.get()), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
+ }
+ }
+
+ virtual void TearDown() {
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ if (mEglSurfaces[i] != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mEglSurfaces[i]);
+ }
+ }
+
+ if (mEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ }
+
+ if (mEglDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(mEglDisplay);
+ }
+ }
+
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurfaces[NUM_SURFACE_TEXTURES];
+ EGLContext mEglContext;
+};
+
+// XXX: This test is disabled because it causes a hang on some devices. See bug
+// 5015672.
+TEST_F(MultiSurfaceTextureClientTest, DISABLED_MakeCurrentBetweenSurfacesWorks) {
+ for (int iter = 0; iter < 8; iter++) {
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ eglMakeCurrent(mEglDisplay, mEglSurfaces[i], mEglSurfaces[i],
+ mEglContext);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mEglSurfaces[i]);
+ }
+ }
+}
+
} // namespace android
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index e232ddd..7114b6a 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -33,6 +33,16 @@
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
+// Macros
+///////////////////////////////////////////////////////////////////////////////
+
+#if DEBUG_CACHE_FLUSH
+ #define FLUSH_LOGD(...) LOGD(__VA_ARGS__)
+#else
+ #define FLUSH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
@@ -150,6 +160,30 @@
mLayerGarbage.push(layer);
}
+void Caches::flush(FlushMode mode) {
+ FLUSH_LOGD("Flushing caches (mode %d)", mode);
+
+ clearGarbage();
+
+ switch (mode) {
+ case kFlushMode_Full:
+ textureCache.clear();
+ patchCache.clear();
+ dropShadowCache.clear();
+ gradientCache.clear();
+ // fall through
+ case kFlushMode_Moderate:
+ layerCache.clear();
+ pathCache.clear();
+ roundRectShapeCache.clear();
+ circleShapeCache.clear();
+ ovalShapeCache.clear();
+ rectShapeCache.clear();
+ arcShapeCache.clear();
+ break;
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// VBO
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e64d8ac..76dff4b 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -100,6 +100,18 @@
Vector<Layer*> mLayerGarbage;
public:
+ enum FlushMode {
+ kFlushMode_Moderate = 0,
+ kFlushMode_Full
+ };
+
+ /**
+ * Flush the cache.
+ *
+ * @param mode Indicates how much of the cache should be flushed
+ */
+ void flush(FlushMode mode);
+
/**
* Indicates whether the renderer is in debug mode.
* This debug mode provides limited information to app developers.
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 2cdc8c3..5db73db 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -26,6 +26,9 @@
// Turn on to enable memory usage summary on each frame
#define DEBUG_MEMORY_USAGE 0
+// Turn on to enable debugging of cache flushes
+#define DEBUG_CACHE_FLUSH 1
+
// Turn on to enable layers debugging when rendered as regions
#define DEBUG_LAYERS_AS_REGIONS 0
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 9c10c75..794747d 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -303,6 +303,10 @@
case NATIVE_WINDOW_CONNECT:
case NATIVE_WINDOW_DISCONNECT:
break;
+ case NATIVE_WINDOW_LOCK:
+ return INVALID_OPERATION;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ return INVALID_OPERATION;
default:
return NAME_NOT_FOUND;
}
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
new file mode 100755
index 0000000..77d40b6
--- /dev/null
+++ b/media/libeffects/preprocessing/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+# audio preprocessing wrapper
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libaudiopreprocessing
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+
+LOCAL_SRC_FILES:= \
+ PreProcessing.cpp
+
+LOCAL_C_INCLUDES += \
+ external/webrtc/src \
+ external/webrtc/src/modules/interface \
+ external/webrtc/src/modules/audio_processing/main/interface \
+ system/media/audio_effects/include
+
+LOCAL_C_INCLUDES += $(call include-path-for, speex)
+
+LOCAL_SHARED_LIBRARIES := \
+ libwebrtc_audio_preprocessing \
+ libspeexresampler \
+ libutils
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_LDLIBS += -ldl
+else
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
new file mode 100755
index 0000000..ba286a1
--- /dev/null
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -0,0 +1,1609 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#define LOG_TAG "PreProcessing"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <hardware/audio_effect.h>
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_agc.h>
+#include <audio_effects/effect_ns.h>
+#include "modules/interface/module_common_types.h"
+#include "modules/audio_processing/main/interface/audio_processing.h"
+#include "speex/speex_resampler.h"
+
+
+//------------------------------------------------------------------------------
+// local definitions
+//------------------------------------------------------------------------------
+
+// maximum number of sessions
+#define PREPROC_NUM_SESSIONS 8
+
+// types of pre processing modules
+enum preproc_id
+{
+ PREPROC_AGC, // Automatic Gain Control
+ PREPROC_AEC, // Acoustic Echo Canceler
+ PREPROC_NS, // Noise Suppressor
+ PREPROC_NUM_EFFECTS
+};
+
+// Session state
+enum preproc_session_state {
+ PREPROC_SESSION_STATE_INIT, // initialized
+ PREPROC_SESSION_STATE_CONFIG // configuration received
+};
+
+// Effect/Preprocessor state
+enum preproc_effect_state {
+ PREPROC_EFFECT_STATE_INIT, // initialized
+ PREPROC_EFFECT_STATE_CREATED, // webRTC engine created
+ PREPROC_EFFECT_STATE_CONFIG, // configuration received/disabled
+ PREPROC_EFFECT_STATE_ACTIVE // active/enabled
+};
+
+// handle on webRTC engine
+typedef void* preproc_fx_handle_t;
+
+typedef struct preproc_session_s preproc_session_t;
+typedef struct preproc_effect_s preproc_effect_t;
+typedef struct preproc_ops_s preproc_ops_t;
+
+// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
+// Function pointer can be null if no action required.
+struct preproc_ops_s {
+ int (* create)(preproc_effect_t *fx);
+ int (* init)(preproc_effect_t *fx);
+ int (* reset)(preproc_effect_t *fx);
+ void (* enable)(preproc_effect_t *fx);
+ void (* disable)(preproc_effect_t *fx);
+ int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
+ int (* get_parameter)(preproc_effect_t *fx, void *param, size_t *size, void *value);
+ int (* set_device)(preproc_effect_t *fx, uint32_t device);
+};
+
+// Effect context
+struct preproc_effect_s {
+ const struct effect_interface_s *itfe;
+ uint32_t procId; // type of pre processor (enum preproc_id)
+ uint32_t state; // current state (enum preproc_effect_state)
+ preproc_session_t *session; // session the effect is on
+ const preproc_ops_t *ops; // effect ops table
+ preproc_fx_handle_t engine; // handle on webRTC engine
+};
+
+// Session context
+struct preproc_session_s {
+ struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
+ uint32_t state; // current state (enum preproc_session_state)
+ int id; // audio session ID
+ int io; // handle of input stream this session is on
+ webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
+ size_t apmFrameCount; // buffer size for webRTC process (10 ms)
+ uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
+ size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
+ uint32_t samplingRate; // sampling rate at effect process interface
+ uint32_t inChannelCount; // input channel count
+ uint32_t outChannelCount; // output channel count
+ uint32_t createdMsk; // bit field containing IDs of crested pre processors
+ uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
+ uint32_t processedMsk; // bit field containing IDs of pre processors already
+ // processed in current round
+ webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
+ int16_t *inBuf; // input buffer used when resampling
+ size_t inBufSize; // input buffer size in frames
+ size_t framesIn; // number of frames in input buffer
+ SpeexResamplerState *inResampler; // handle on input speex resampler
+ int16_t *outBuf; // output buffer used when resampling
+ size_t outBufSize; // output buffer size in frames
+ size_t framesOut; // number of frames in output buffer
+ SpeexResamplerState *outResampler; // handle on output speex resampler
+ uint32_t revChannelCount; // number of channels on reverse stream
+ uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
+ // with reverse channel
+ uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
+ // channel already processed in current round
+ webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
+ int16_t *revBuf; // reverse channel input buffer
+ size_t revBufSize; // reverse channel input buffer size
+ size_t framesRev; // number of frames in reverse channel input buffer
+ SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
+};
+
+//------------------------------------------------------------------------------
+// Effect descriptors
+//------------------------------------------------------------------------------
+
+// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
+// as the pre processing effects are not defined by OpenSL ES
+
+// Automatic Gain Control
+static const effect_descriptor_t sAgcDescriptor = {
+ { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+ { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Automatic Gain Control",
+ "The Android Open Source Project"
+};
+
+// Acoustic Echo Cancellation
+static const effect_descriptor_t sAecDescriptor = {
+ { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+ { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Acoustic Echo Canceler",
+ "The Android Open Source Project"
+};
+
+// Noise suppression
+static const effect_descriptor_t sNsDescriptor = {
+ { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+ { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Noise Suppression",
+ "The Android Open Source Project"
+};
+
+
+static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
+ &sAgcDescriptor,
+ &sAecDescriptor,
+ &sNsDescriptor
+};
+
+//------------------------------------------------------------------------------
+// Helper functions
+//------------------------------------------------------------------------------
+
+const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
+ FX_IID_AGC,
+ FX_IID_AEC,
+ FX_IID_NS
+};
+
+
+const effect_uuid_t * ProcIdToUuid(int procId)
+{
+ if (procId >= PREPROC_NUM_EFFECTS) {
+ return EFFECT_UUID_NULL;
+ }
+ return sUuidToPreProcTable[procId];
+}
+
+uint32_t UuidToProcId(const effect_uuid_t * uuid)
+{
+ size_t i;
+ for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
+ if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
+ break;
+ }
+ }
+ return i;
+}
+
+bool HasReverseStream(uint32_t procId)
+{
+ if (procId == PREPROC_AEC) {
+ return true;
+ }
+ return false;
+}
+
+
+//------------------------------------------------------------------------------
+// Automatic Gain Control (AGC)
+//------------------------------------------------------------------------------
+
+static const int kAgcDefaultTargetLevel = 0;
+static const int kAgcDefaultCompGain = 90;
+static const bool kAgcDefaultLimiter = true;
+
+int AgcInit (preproc_effect_t *effect)
+{
+ LOGV("AgcInit");
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+ agc->set_mode(webrtc::GainControl::kFixedDigital);
+ agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
+ agc->set_compression_gain_db(kAgcDefaultCompGain);
+ agc->enable_limiter(kAgcDefaultLimiter);
+ return 0;
+}
+
+int AgcCreate(preproc_effect_t *effect)
+{
+ webrtc::GainControl *agc = effect->session->apm->gain_control();
+ LOGV("AgcCreate got agc %p", agc);
+ if (agc == NULL) {
+ LOGW("AgcCreate Error");
+ return -ENOMEM;
+ }
+ effect->engine = static_cast<preproc_fx_handle_t>(agc);
+ AgcInit(effect);
+ return 0;
+}
+
+int AgcGetParameter(preproc_effect_t *effect,
+ void *pParam,
+ size_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ t_agc_settings *pProperties = (t_agc_settings *)pValue;
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ case AGC_PARAM_COMP_GAIN:
+ if (*pValueSize < sizeof(int16_t)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ if (*pValueSize < sizeof(bool)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+ case AGC_PARAM_PROPERTIES:
+ if (*pValueSize < sizeof(t_agc_settings)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ LOGW("AgcGetParameter() unknown param %08x", param);
+ status = -EINVAL;
+ break;
+ }
+
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
+ LOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
+ LOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ *(bool *) pValue = (bool)agc->is_limiter_enabled();
+ LOGV("AgcGetParameter() limiter enabled %s",
+ (*(int16_t *) pValue != 0) ? "true" : "false");
+ break;
+ case AGC_PARAM_PROPERTIES:
+ pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
+ pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
+ pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
+ break;
+ default:
+ LOGW("AgcGetParameter() unknown param %d", param);
+ status = -EINVAL;
+ break;
+ }
+ return status;
+}
+
+int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ t_agc_settings *pProperties = (t_agc_settings *)pValue;
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ LOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
+ status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ LOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
+ status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ LOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
+ status = agc->enable_limiter(*(bool *)pValue);
+ break;
+ case AGC_PARAM_PROPERTIES:
+ LOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
+ pProperties->targetLevel,
+ pProperties->compGain,
+ pProperties->limiterEnabled);
+ status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
+ if (status != 0) break;
+ status = agc->set_compression_gain_db(pProperties->compGain / 100);
+ if (status != 0) break;
+ status = agc->enable_limiter(pProperties->limiterEnabled);
+ break;
+ default:
+ LOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+
+ LOGV("AgcSetParameter() done status %d", status);
+
+ return status;
+}
+
+void AgcEnable(preproc_effect_t *effect)
+{
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+ LOGV("AgcEnable agc %p", agc);
+ agc->Enable(true);
+}
+
+void AgcDisable(preproc_effect_t *effect)
+{
+ LOGV("AgcDisable");
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+ agc->Enable(false);
+}
+
+
+static const preproc_ops_t sAgcOps = {
+ AgcCreate,
+ AgcInit,
+ NULL,
+ AgcEnable,
+ AgcDisable,
+ AgcSetParameter,
+ AgcGetParameter,
+ NULL
+};
+
+
+//------------------------------------------------------------------------------
+// Acoustic Echo Canceler (AEC)
+//------------------------------------------------------------------------------
+
+static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
+ webrtc::EchoControlMobile::kEarpiece;
+static const bool kAecDefaultComfortNoise = true;
+
+int AecInit (preproc_effect_t *effect)
+{
+ LOGV("AecInit");
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ aec->set_routing_mode(kAecDefaultMode);
+ aec->enable_comfort_noise(kAecDefaultComfortNoise);
+ return 0;
+}
+
+int AecCreate(preproc_effect_t *effect)
+{
+ webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
+ LOGV("AecCreate got aec %p", aec);
+ if (aec == NULL) {
+ LOGW("AgcCreate Error");
+ return -ENOMEM;
+ }
+ effect->engine = static_cast<preproc_fx_handle_t>(aec);
+ AecInit (effect);
+ return 0;
+}
+
+int AecGetParameter(preproc_effect_t *effect,
+ void *pParam,
+ size_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+
+ if (*pValueSize < sizeof(uint32_t)) {
+ return -EINVAL;
+ }
+ switch (param) {
+ case AEC_PARAM_ECHO_DELAY:
+ case AEC_PARAM_PROPERTIES:
+ *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
+ LOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
+ break;
+ default:
+ LOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ return status;
+}
+
+int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ uint32_t value = *(uint32_t *)pValue;
+
+ switch (param) {
+ case AEC_PARAM_ECHO_DELAY:
+ case AEC_PARAM_PROPERTIES:
+ status = effect->session->apm->set_stream_delay_ms(value/1000);
+ LOGV("AecSetParameter() echo delay %d us, status %d", value, status);
+ break;
+ default:
+ LOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ return status;
+}
+
+void AecEnable(preproc_effect_t *effect)
+{
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ LOGV("AecEnable aec %p", aec);
+ aec->Enable(true);
+}
+
+void AecDisable(preproc_effect_t *effect)
+{
+ LOGV("AecDisable");
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ aec->Enable(false);
+}
+
+int AecSetDevice(preproc_effect_t *effect, uint32_t device)
+{
+ LOGV("AecSetDevice %08x", device);
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
+
+ switch(device) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ mode = webrtc::EchoControlMobile::kEarpiece;
+ break;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ mode = webrtc::EchoControlMobile::kSpeakerphone;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ default:
+ break;
+ }
+ aec->set_routing_mode(mode);
+ return 0;
+}
+
+static const preproc_ops_t sAecOps = {
+ AecCreate,
+ AecInit,
+ NULL,
+ AecEnable,
+ AecDisable,
+ AecSetParameter,
+ AecGetParameter,
+ AecSetDevice
+};
+
+//------------------------------------------------------------------------------
+// Noise Suppression (NS)
+//------------------------------------------------------------------------------
+
+static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
+
+int NsInit (preproc_effect_t *effect)
+{
+ LOGV("NsInit");
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ ns->set_level(kNsDefaultLevel);
+ return 0;
+}
+
+int NsCreate(preproc_effect_t *effect)
+{
+ webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
+ LOGV("NsCreate got ns %p", ns);
+ if (ns == NULL) {
+ LOGW("AgcCreate Error");
+ return -ENOMEM;
+ }
+ effect->engine = static_cast<preproc_fx_handle_t>(ns);
+ NsInit (effect);
+ return 0;
+}
+
+int NsGetParameter(preproc_effect_t *effect,
+ void *pParam,
+ size_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ return status;
+}
+
+int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ return status;
+}
+
+void NsEnable(preproc_effect_t *effect)
+{
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ LOGV("NsEnable ns %p", ns);
+ ns->Enable(true);
+}
+
+void NsDisable(preproc_effect_t *effect)
+{
+ LOGV("NsDisable");
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ ns->Enable(false);
+}
+
+static const preproc_ops_t sNsOps = {
+ NsCreate,
+ NsInit,
+ NULL,
+ NsEnable,
+ NsDisable,
+ NsSetParameter,
+ NsGetParameter,
+ NULL
+};
+
+
+static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
+ &sAgcOps,
+ &sAecOps,
+ &sNsOps
+};
+
+
+//------------------------------------------------------------------------------
+// Effect functions
+//------------------------------------------------------------------------------
+
+void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
+
+extern "C" const struct effect_interface_s sEffectInterface;
+extern "C" const struct effect_interface_s sEffectInterfaceReverse;
+
+#define BAD_STATE_ABORT(from, to) \
+ LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
+
+int Effect_SetState(preproc_effect_t *effect, uint32_t state)
+{
+ int status = 0;
+ LOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
+ switch(state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ effect->ops->disable(effect);
+ Session_SetProcEnabled(effect->session, effect->procId, false);
+ case PREPROC_EFFECT_STATE_CONFIG:
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_INIT:
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ case PREPROC_EFFECT_STATE_CREATED:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ status = effect->ops->create(effect);
+ break;
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ case PREPROC_EFFECT_STATE_CONFIG:
+ LOGE("Effect_SetState invalid transition");
+ status = -ENOSYS;
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ case PREPROC_EFFECT_STATE_CONFIG:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ LOGE("Effect_SetState invalid transition");
+ status = -ENOSYS;
+ break;
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ effect->ops->disable(effect);
+ Session_SetProcEnabled(effect->session, effect->procId, false);
+ break;
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_CONFIG:
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ LOGE("Effect_SetState invalid transition");
+ status = -ENOSYS;
+ break;
+ case PREPROC_EFFECT_STATE_CONFIG:
+ effect->ops->enable(effect);
+ Session_SetProcEnabled(effect->session, effect->procId, true);
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ if (status == 0) {
+ effect->state = state;
+ }
+ return status;
+}
+
+int Effect_Init(preproc_effect_t *effect, uint32_t procId)
+{
+ if (HasReverseStream(procId)) {
+ effect->itfe = &sEffectInterfaceReverse;
+ } else {
+ effect->itfe = &sEffectInterface;
+ }
+ effect->ops = sPreProcOps[procId];
+ effect->procId = procId;
+ effect->state = PREPROC_EFFECT_STATE_INIT;
+ return 0;
+}
+
+int Effect_Create(preproc_effect_t *effect,
+ preproc_session_t *session,
+ effect_handle_t *interface)
+{
+ effect->session = session;
+ *interface = (effect_handle_t)&effect->itfe;
+ return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
+}
+
+int Effect_Release(preproc_effect_t *effect)
+{
+ return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
+}
+
+
+//------------------------------------------------------------------------------
+// Session functions
+//------------------------------------------------------------------------------
+
+#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
+
+static const int kPreprocDefaultSr = 16000;
+static const int kPreProcDefaultCnl = 1;
+
+int Session_Init(preproc_session_t *session)
+{
+ size_t i;
+ int status = 0;
+
+ session->state = PREPROC_SESSION_STATE_INIT;
+ session->id = 0;
+ session->io = 0;
+ session->createdMsk = 0;
+ session->apm = NULL;
+ for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
+ status = Effect_Init(&session->effects[i], i);
+ }
+ return status;
+}
+
+
+extern "C" int Session_CreateEffect(preproc_session_t *session,
+ int32_t procId,
+ effect_handle_t *interface)
+{
+ int status = -ENOMEM;
+
+ LOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
+
+ if (session->createdMsk == 0) {
+ session->apm = webrtc::AudioProcessing::Create(session->io);
+ if (session->apm == NULL) {
+ LOGW("Session_CreateEffect could not get apm engine");
+ goto error;
+ }
+ session->apm->set_sample_rate_hz(kPreprocDefaultSr);
+ session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
+ session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
+ session->procFrame = new webrtc::AudioFrame();
+ if (session->procFrame == NULL) {
+ LOGW("Session_CreateEffect could not allocate audio frame");
+ goto error;
+ }
+ session->revFrame = new webrtc::AudioFrame();
+ if (session->revFrame == NULL) {
+ LOGW("Session_CreateEffect could not allocate reverse audio frame");
+ goto error;
+ }
+ session->apmSamplingRate = kPreprocDefaultSr;
+ session->apmFrameCount = (kPreprocDefaultSr) / 100;
+ session->frameCount = session->apmFrameCount;
+ session->samplingRate = kPreprocDefaultSr;
+ session->inChannelCount = kPreProcDefaultCnl;
+ session->outChannelCount = kPreProcDefaultCnl;
+ session->procFrame->_frequencyInHz = kPreprocDefaultSr;
+ session->procFrame->_audioChannel = kPreProcDefaultCnl;
+ session->revChannelCount = kPreProcDefaultCnl;
+ session->revFrame->_frequencyInHz = kPreprocDefaultSr;
+ session->revFrame->_audioChannel = kPreProcDefaultCnl;
+ session->enabledMsk = 0;
+ session->processedMsk = 0;
+ session->revEnabledMsk = 0;
+ session->revProcessedMsk = 0;
+ session->inResampler = NULL;
+ session->inBuf = NULL;
+ session->inBufSize = 0;
+ session->outResampler = NULL;
+ session->outBuf = NULL;
+ session->outBufSize = 0;
+ session->revResampler = NULL;
+ session->revBuf = NULL;
+ session->revBufSize = 0;
+ }
+ status = Effect_Create(&session->effects[procId], session, interface);
+ if (status < 0) {
+ goto error;
+ }
+ LOGV("Session_CreateEffect OK");
+ session->createdMsk |= (1<<procId);
+ return status;
+
+error:
+ if (session->createdMsk == 0) {
+ delete session->revFrame;
+ session->revFrame = NULL;
+ delete session->procFrame;
+ session->procFrame = NULL;
+ webrtc::AudioProcessing::Destroy(session->apm);
+ session->apm = NULL;
+ }
+ return status;
+}
+
+int Session_ReleaseEffect(preproc_session_t *session,
+ preproc_effect_t *fx)
+{
+ LOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
+ session->createdMsk &= ~(1<<fx->procId);
+ if (session->createdMsk == 0) {
+ webrtc::AudioProcessing::Destroy(session->apm);
+ session->apm = NULL;
+ delete session->procFrame;
+ session->procFrame = NULL;
+ delete session->revFrame;
+ session->revFrame = NULL;
+ if (session->inResampler != NULL) {
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ }
+ if (session->outResampler != NULL) {
+ speex_resampler_destroy(session->outResampler);
+ session->outResampler = NULL;
+ }
+ if (session->revResampler != NULL) {
+ speex_resampler_destroy(session->revResampler);
+ session->revResampler = NULL;
+ }
+ delete session->inBuf;
+ session->inBuf = NULL;
+ delete session->outBuf;
+ session->outBuf = NULL;
+ delete session->revBuf;
+ session->revBuf = NULL;
+
+ session->io = 0;
+ }
+
+ return 0;
+}
+
+
+int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
+{
+ uint32_t sr;
+ uint32_t inCnl = popcount(config->inputCfg.channels);
+ uint32_t outCnl = popcount(config->outputCfg.channels);
+
+ if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
+ config->inputCfg.format != config->outputCfg.format ||
+ config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
+
+ LOGV("Session_SetConfig sr %d cnl %08x",
+ config->inputCfg.samplingRate, config->inputCfg.channels);
+ int status;
+
+ // AEC implementation is limited to 16kHz
+ if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
+ session->apmSamplingRate = 32000;
+ } else
+ if (config->inputCfg.samplingRate >= 16000) {
+ session->apmSamplingRate = 16000;
+ } else if (config->inputCfg.samplingRate >= 8000) {
+ session->apmSamplingRate = 8000;
+ }
+ status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
+ if (status < 0) {
+ return -EINVAL;
+ }
+ status = session->apm->set_num_channels(inCnl, outCnl);
+ if (status < 0) {
+ return -EINVAL;
+ }
+ status = session->apm->set_num_reverse_channels(inCnl);
+ if (status < 0) {
+ return -EINVAL;
+ }
+
+ session->samplingRate = config->inputCfg.samplingRate;
+ session->apmFrameCount = session->apmSamplingRate / 100;
+ if (session->samplingRate == session->apmSamplingRate) {
+ session->frameCount = session->apmFrameCount;
+ } else {
+ session->frameCount = (session->apmFrameCount * session->samplingRate) /
+ session->apmSamplingRate + 1;
+ }
+ session->inChannelCount = inCnl;
+ session->outChannelCount = outCnl;
+ session->procFrame->_audioChannel = inCnl;
+ session->procFrame->_frequencyInHz = session->apmSamplingRate;
+
+ session->revChannelCount = inCnl;
+ session->revFrame->_audioChannel = inCnl;
+ session->revFrame->_frequencyInHz = session->apmSamplingRate;
+
+ if (session->inResampler != NULL) {
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ }
+ if (session->outResampler != NULL) {
+ speex_resampler_destroy(session->outResampler);
+ session->outResampler = NULL;
+ }
+ if (session->revResampler != NULL) {
+ speex_resampler_destroy(session->revResampler);
+ session->revResampler = NULL;
+ }
+ if (session->samplingRate != session->apmSamplingRate) {
+ int error;
+ session->inResampler = speex_resampler_init(session->inChannelCount,
+ session->samplingRate,
+ session->apmSamplingRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (session->inResampler == NULL) {
+ LOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ return -EINVAL;
+ }
+ session->outResampler = speex_resampler_init(session->outChannelCount,
+ session->apmSamplingRate,
+ session->samplingRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (session->outResampler == NULL) {
+ LOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ return -EINVAL;
+ }
+ session->revResampler = speex_resampler_init(session->inChannelCount,
+ session->samplingRate,
+ session->apmSamplingRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (session->revResampler == NULL) {
+ LOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ speex_resampler_destroy(session->outResampler);
+ session->outResampler = NULL;
+ return -EINVAL;
+ }
+ }
+
+ session->state = PREPROC_SESSION_STATE_CONFIG;
+ return 0;
+}
+
+int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
+{
+ if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
+ config->inputCfg.format != config->outputCfg.format ||
+ config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
+
+ LOGV("Session_SetReverseConfig sr %d cnl %08x",
+ config->inputCfg.samplingRate, config->inputCfg.channels);
+
+ if (session->state < PREPROC_SESSION_STATE_CONFIG) {
+ return -ENOSYS;
+ }
+ if (config->inputCfg.samplingRate != session->samplingRate ||
+ config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
+ uint32_t inCnl = popcount(config->inputCfg.channels);
+ int status = session->apm->set_num_reverse_channels(inCnl);
+ if (status < 0) {
+ return -EINVAL;
+ }
+ session->revChannelCount = inCnl;
+ session->revFrame->_audioChannel = inCnl;
+ session->revFrame->_frequencyInHz = session->apmSamplingRate;
+ return 0;
+}
+
+void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
+{
+ if (enabled) {
+ if(session->enabledMsk == 0) {
+ session->framesIn = 0;
+ if (session->inResampler != NULL) {
+ speex_resampler_reset_mem(session->inResampler);
+ }
+ session->framesOut = 0;
+ if (session->outResampler != NULL) {
+ speex_resampler_reset_mem(session->outResampler);
+ }
+ }
+ session->enabledMsk |= (1 << procId);
+ if (HasReverseStream(procId)) {
+ session->framesRev = 0;
+ if (session->revResampler != NULL) {
+ speex_resampler_reset_mem(session->revResampler);
+ }
+ session->revEnabledMsk |= (1 << procId);
+ }
+ } else {
+ session->enabledMsk &= ~(1 << procId);
+ if (HasReverseStream(procId)) {
+ session->revEnabledMsk &= ~(1 << procId);
+ }
+ }
+ LOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
+ procId, enabled, session->enabledMsk, session->revEnabledMsk);
+ session->processedMsk = 0;
+ if (HasReverseStream(procId)) {
+ session->revProcessedMsk = 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Bundle functions
+//------------------------------------------------------------------------------
+
+static int sInitStatus = 1;
+static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
+
+preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
+{
+ size_t i;
+ int free = -1;
+ for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
+ if (sSessions[i].io == ioId) {
+ if (sSessions[i].createdMsk & (1 << procId)) {
+ return NULL;
+ }
+ return &sSessions[i];
+ }
+ }
+ for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
+ if (sSessions[i].io == 0) {
+ sSessions[i].id = sessionId;
+ sSessions[i].io = ioId;
+ return &sSessions[i];
+ }
+ }
+ return NULL;
+}
+
+
+int PreProc_Init() {
+ size_t i;
+ int status = 0;
+
+ if (sInitStatus <= 0) {
+ return sInitStatus;
+ }
+ for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
+ status = Session_Init(&sSessions[i]);
+ }
+ sInitStatus = status;
+ return sInitStatus;
+}
+
+const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
+{
+ size_t i;
+ for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
+ if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
+ return sDescriptors[i];
+ }
+ }
+ return NULL;
+}
+
+
+extern "C" {
+
+//------------------------------------------------------------------------------
+// Effect Control Interface Implementation
+//------------------------------------------------------------------------------
+
+int PreProcessingFx_Process(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer)
+{
+ preproc_effect_t * effect = (preproc_effect_t *)self;
+ int status = 0;
+
+ if (effect == NULL){
+ LOGV("PreProcessingFx_Process() ERROR effect == NULL");
+ return -EINVAL;
+ }
+ preproc_session_t * session = (preproc_session_t *)effect->session;
+
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL){
+ LOGW("PreProcessingFx_Process() ERROR bad pointer");
+ return -EINVAL;
+ }
+
+ session->processedMsk |= (1<<effect->procId);
+
+// LOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
+// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
+
+ if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
+ effect->session->processedMsk = 0;
+ size_t framesRq = outBuffer->frameCount;
+ size_t framesWr = 0;
+ if (session->framesOut) {
+ size_t fr = session->framesOut;
+ if (outBuffer->frameCount < fr) {
+ fr = outBuffer->frameCount;
+ }
+ memcpy(outBuffer->s16,
+ session->outBuf,
+ fr * session->outChannelCount * sizeof(int16_t));
+ memcpy(session->outBuf,
+ session->outBuf + fr * session->outChannelCount,
+ (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
+ session->framesOut -= fr;
+ framesWr += fr;
+ }
+ outBuffer->frameCount = framesWr;
+ if (framesWr == framesRq) {
+ inBuffer->frameCount = 0;
+ return 0;
+ }
+
+ if (session->inResampler != NULL) {
+ size_t fr = session->frameCount - session->framesIn;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ if (session->inBufSize < session->framesIn + fr) {
+ session->inBufSize = session->framesIn + fr;
+ session->inBuf = (int16_t *)realloc(session->inBuf,
+ session->inBufSize * session->inChannelCount * sizeof(int16_t));
+ }
+ memcpy(session->inBuf + session->framesIn * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+
+ session->framesIn += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesIn < session->frameCount) {
+ return 0;
+ }
+ size_t frIn = session->framesIn;
+ size_t frOut = session->apmFrameCount;
+ if (session->inChannelCount == 1) {
+ speex_resampler_process_int(session->inResampler,
+ 0,
+ session->inBuf,
+ &frIn,
+ session->procFrame->_payloadData,
+ &frOut);
+ } else {
+ speex_resampler_process_interleaved_int(session->inResampler,
+ session->inBuf,
+ &frIn,
+ session->procFrame->_payloadData,
+ &frOut);
+ }
+ memcpy(session->inBuf,
+ session->inBuf + frIn * session->inChannelCount,
+ (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
+ session->framesIn -= frIn;
+ } else {
+ size_t fr = session->frameCount - session->framesIn;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+ session->framesIn += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesIn < session->frameCount) {
+ return 0;
+ }
+ session->framesIn = 0;
+ }
+ session->procFrame->_payloadDataLengthInSamples =
+ session->apmFrameCount * session->inChannelCount;
+
+ effect->session->apm->ProcessStream(session->procFrame);
+
+ if (session->outBufSize < session->framesOut + session->frameCount) {
+ session->outBufSize = session->framesOut + session->frameCount;
+ session->outBuf = (int16_t *)realloc(session->outBuf,
+ session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ }
+
+ if (session->outResampler != NULL) {
+ size_t frIn = session->apmFrameCount;
+ size_t frOut = session->frameCount;
+ if (session->inChannelCount == 1) {
+ speex_resampler_process_int(session->outResampler,
+ 0,
+ session->procFrame->_payloadData,
+ &frIn,
+ session->outBuf + session->framesOut * session->outChannelCount,
+ &frOut);
+ } else {
+ speex_resampler_process_interleaved_int(session->outResampler,
+ session->procFrame->_payloadData,
+ &frIn,
+ session->outBuf + session->framesOut * session->outChannelCount,
+ &frOut);
+ }
+ session->framesOut += frOut;
+ } else {
+ memcpy(session->outBuf + session->framesOut * session->outChannelCount,
+ session->procFrame->_payloadData,
+ session->frameCount * session->outChannelCount * sizeof(int16_t));
+ session->framesOut += session->frameCount;
+ }
+ size_t fr = session->framesOut;
+ if (framesRq - framesWr < fr) {
+ fr = framesRq - framesWr;
+ }
+ memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
+ session->outBuf,
+ fr * session->outChannelCount * sizeof(int16_t));
+ memcpy(session->outBuf,
+ session->outBuf + fr * session->outChannelCount,
+ (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
+ session->framesOut -= fr;
+ outBuffer->frameCount += fr;
+
+ return 0;
+ } else {
+ return -ENODATA;
+ }
+}
+
+int PreProcessingFx_Command(effect_handle_t self,
+ uint32_t cmdCode,
+ uint32_t cmdSize,
+ void *pCmdData,
+ uint32_t *replySize,
+ void *pReplyData)
+{
+ preproc_effect_t * effect = (preproc_effect_t *) self;
+ int retsize;
+ int status;
+
+ if (effect == NULL){
+ return -EINVAL;
+ }
+
+ //LOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
+
+ switch (cmdCode){
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)){
+ return -EINVAL;
+ }
+ if (effect->ops->init) {
+ effect->ops->init(effect);
+ }
+ *(int *)pReplyData = 0;
+ break;
+
+ case EFFECT_CMD_CONFIGURE:
+ if (pCmdData == NULL||
+ cmdSize != sizeof(effect_config_t)||
+ pReplyData == NULL||
+ *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_CONFIGURE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
+ if (*(int *)pReplyData != 0) {
+ break;
+ }
+ *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+ break;
+
+ case EFFECT_CMD_CONFIGURE_REVERSE:
+ if (pCmdData == NULL||
+ cmdSize != sizeof(effect_config_t)||
+ pReplyData == NULL||
+ *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_CONFIGURE_REVERSE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Session_SetReverseConfig(effect->session,
+ (effect_config_t *)pCmdData);
+ if (*(int *)pReplyData != 0) {
+ break;
+ }
+ break;
+
+ case EFFECT_CMD_RESET:
+ if (effect->ops->reset) {
+ effect->ops->reset(effect);
+ }
+ break;
+
+ case EFFECT_CMD_GET_PARAM:{
+ if (pCmdData == NULL ||
+ cmdSize < (int)sizeof(effect_param_t) ||
+ pReplyData == NULL ||
+ *replySize < (int)sizeof(effect_param_t)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_GET_PARAM: ERROR");
+ return -EINVAL;
+ }
+ effect_param_t *p = (effect_param_t *)pCmdData;
+
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
+
+ p = (effect_param_t *)pReplyData;
+
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+
+ if (effect->ops->get_parameter) {
+ p->status = effect->ops->get_parameter(effect, p->data,
+ (size_t *)&p->vsize,
+ p->data + voffset);
+ *replySize = sizeof(effect_param_t) + voffset + p->vsize;
+ }
+ } break;
+
+ case EFFECT_CMD_SET_PARAM:{
+ if (pCmdData == NULL||
+ cmdSize < (int)sizeof(effect_param_t) ||
+ pReplyData == NULL ||
+ *replySize != sizeof(int32_t)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_SET_PARAM: ERROR");
+ return -EINVAL;
+ }
+ effect_param_t *p = (effect_param_t *) pCmdData;
+
+ if (p->psize != sizeof(int32_t)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
+ return -EINVAL;
+ }
+ if (effect->ops->set_parameter) {
+ *(int *)pReplyData = effect->ops->set_parameter(effect,
+ (void *)p->data,
+ p->data + p->psize);
+ }
+ } break;
+
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
+ break;
+
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+ break;
+
+ case EFFECT_CMD_SET_DEVICE:
+ case EFFECT_CMD_SET_INPUT_DEVICE:
+ if (pCmdData == NULL ||
+ cmdSize != sizeof(uint32_t)) {
+ LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
+ return -EINVAL;
+ }
+
+ if (effect->ops->set_device) {
+ effect->ops->set_device(effect, *(uint32_t *)pCmdData);
+ }
+ break;
+
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+int PreProcessingFx_GetDescriptor(effect_handle_t self,
+ effect_descriptor_t *pDescriptor)
+{
+ preproc_effect_t * effect = (preproc_effect_t *) self;
+
+ if (effect == NULL || pDescriptor == NULL) {
+ return -EINVAL;
+ }
+
+ memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
+
+ return 0;
+}
+
+int PreProcessingFx_ProcessReverse(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer)
+{
+ preproc_effect_t * effect = (preproc_effect_t *)self;
+ int status = 0;
+
+ if (effect == NULL){
+ LOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
+ return -EINVAL;
+ }
+ preproc_session_t * session = (preproc_session_t *)effect->session;
+
+ if (inBuffer == NULL || inBuffer->raw == NULL){
+ LOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
+ return -EINVAL;
+ }
+
+ session->revProcessedMsk |= (1<<effect->procId);
+
+// LOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
+// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
+
+
+ if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
+ effect->session->revProcessedMsk = 0;
+ if (session->revResampler != NULL) {
+ size_t fr = session->frameCount - session->framesRev;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ if (session->revBufSize < session->framesRev + fr) {
+ session->revBufSize = session->framesRev + fr;
+ session->revBuf = (int16_t *)realloc(session->revBuf,
+ session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ }
+ memcpy(session->revBuf + session->framesRev * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+
+ session->framesRev += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesRev < session->frameCount) {
+ return 0;
+ }
+ size_t frIn = session->framesRev;
+ size_t frOut = session->apmFrameCount;
+ if (session->inChannelCount == 1) {
+ speex_resampler_process_int(session->revResampler,
+ 0,
+ session->revBuf,
+ &frIn,
+ session->revFrame->_payloadData,
+ &frOut);
+ } else {
+ speex_resampler_process_interleaved_int(session->revResampler,
+ session->revBuf,
+ &frIn,
+ session->revFrame->_payloadData,
+ &frOut);
+ }
+ memcpy(session->revBuf,
+ session->revBuf + frIn * session->inChannelCount,
+ (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
+ session->framesRev -= frIn;
+ } else {
+ size_t fr = session->frameCount - session->framesRev;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+ session->framesRev += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesRev < session->frameCount) {
+ return 0;
+ }
+ session->framesRev = 0;
+ }
+ session->revFrame->_payloadDataLengthInSamples =
+ session->apmFrameCount * session->inChannelCount;
+ effect->session->apm->AnalyzeReverseStream(session->revFrame);
+ return 0;
+ } else {
+ return -ENODATA;
+ }
+}
+
+
+// effect_handle_t interface implementation for effect
+const struct effect_interface_s sEffectInterface = {
+ PreProcessingFx_Process,
+ PreProcessingFx_Command,
+ PreProcessingFx_GetDescriptor,
+ NULL
+};
+
+const struct effect_interface_s sEffectInterfaceReverse = {
+ PreProcessingFx_Process,
+ PreProcessingFx_Command,
+ PreProcessingFx_GetDescriptor,
+ PreProcessingFx_ProcessReverse
+};
+
+//------------------------------------------------------------------------------
+// Effect Library Interface Implementation
+//------------------------------------------------------------------------------
+
+int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
+{
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+ if (pNumEffects == NULL) {
+ return -EINVAL;
+ }
+ *pNumEffects = PREPROC_NUM_EFFECTS;
+ return sInitStatus;
+}
+
+int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
+{
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+ if (index >= PREPROC_NUM_EFFECTS) {
+ return -EINVAL;
+ }
+ memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
+ return 0;
+}
+
+int PreProcessingLib_Create(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_handle_t *pInterface)
+{
+ LOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
+
+ int status;
+ const effect_descriptor_t *desc;
+ preproc_session_t *session;
+ uint32_t procId;
+
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+ desc = PreProc_GetDescriptor(uuid);
+ if (desc == NULL) {
+ LOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
+ return -EINVAL;
+ }
+ procId = UuidToProcId(&desc->type);
+
+ session = PreProc_GetSession(procId, sessionId, ioId);
+ if (session == NULL) {
+ LOGW("EffectCreate: no more session available");
+ return -EINVAL;
+ }
+
+ status = Session_CreateEffect(session, procId, pInterface);
+
+ if (status < 0 && session->createdMsk == 0) {
+ session->io = 0;
+ }
+ return status;
+}
+
+int PreProcessingLib_Release(effect_handle_t interface)
+{
+ int status;
+ LOGV("EffectRelease start %p", interface);
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+
+ preproc_effect_t *fx = (preproc_effect_t *)interface;
+
+ if (fx->session->io == 0) {
+ return -EINVAL;
+ }
+ return Session_ReleaseEffect(fx->session, fx);
+}
+
+int PreProcessingLib_GetDescriptor(effect_uuid_t *uuid,
+ effect_descriptor_t *pDescriptor) {
+
+ if (pDescriptor == NULL || uuid == NULL){
+ return -EINVAL;
+ }
+
+ const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
+ if (desc == NULL) {
+ LOGV("PreProcessingLib_GetDescriptor() not found");
+ return -EINVAL;
+ }
+
+ LOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
+
+ memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+ return 0;
+}
+
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+ tag : AUDIO_EFFECT_LIBRARY_TAG,
+ version : EFFECT_LIBRARY_API_VERSION,
+ name : "Audio Preprocessing Library",
+ implementor : "The Android Open Source Project",
+ query_num_effects : PreProcessingLib_QueryNumberEffects,
+ query_effect : PreProcessingLib_QueryEffect,
+ create_effect : PreProcessingLib_Create,
+ release_effect : PreProcessingLib_Release,
+ get_descriptor : PreProcessingLib_GetDescriptor
+};
+
+}; // extern "C"
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 7b7ba74..178039c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -27,6 +27,8 @@
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
+#include <gui/SurfaceTextureClient.h>
+
#include <media/mediaplayer.h>
#include <media/AudioTrack.h>
@@ -38,6 +40,7 @@
#include <utils/String8.h>
#include <system/audio.h>
+#include <system/window.h>
namespace android {
@@ -194,13 +197,62 @@
return mPlayer->getMetadata(update_only, apply_filter, metadata);
}
+void MediaPlayer::disconnectNativeWindow() {
+ if (mConnectedWindow != NULL) {
+ status_t err = native_window_disconnect(mConnectedWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ LOGW("native_window_disconnect returned an error: %s (%d)",
+ strerror(-err), err);
+ }
+ }
+ mConnectedWindow.clear();
+}
+
status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return NO_INIT;
- return mPlayer->setVideoSurface(surface);
+ sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder());
+ if (mConnectedWindowBinder == binder) {
+ return OK;
+ }
+
+ if (surface != NULL) {
+ status_t err = native_window_connect(surface.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ // Note that we must do the reset before disconnecting from the ANW.
+ // Otherwise queue/dequeue calls could be made on the disconnected
+ // ANW, which may result in errors.
+ reset_l();
+
+ disconnectNativeWindow();
+
+ return err;
+ }
+ }
+
+ // Note that we must set the player's new surface before disconnecting the
+ // old one. Otherwise queue/dequeue calls could be made on the disconnected
+ // ANW, which may result in errors.
+ status_t err = mPlayer->setVideoSurface(surface);
+
+ disconnectNativeWindow();
+
+ mConnectedWindow = surface;
+
+ if (err == OK) {
+ mConnectedWindowBinder = binder;
+ } else {
+ disconnectNativeWindow();
+ }
+
+ return err;
}
status_t MediaPlayer::setVideoSurfaceTexture(
@@ -210,7 +262,46 @@
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return NO_INIT;
- return mPlayer->setVideoSurfaceTexture(surfaceTexture);
+ sp<IBinder> binder(surfaceTexture == NULL ? NULL :
+ surfaceTexture->asBinder());
+ if (mConnectedWindowBinder == binder) {
+ return OK;
+ }
+
+ sp<ANativeWindow> anw;
+ if (surfaceTexture != NULL) {
+ anw = new SurfaceTextureClient(surfaceTexture);
+ status_t err = native_window_connect(anw.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ // Note that we must do the reset before disconnecting from the ANW.
+ // Otherwise queue/dequeue calls could be made on the disconnected
+ // ANW, which may result in errors.
+ reset_l();
+
+ disconnectNativeWindow();
+
+ return err;
+ }
+ }
+
+ // Note that we must set the player's new SurfaceTexture before
+ // disconnecting the old one. Otherwise queue/dequeue calls could be made
+ // on the disconnected ANW, which may result in errors.
+ status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
+
+ disconnectNativeWindow();
+
+ mConnectedWindow = anw;
+
+ if (err == OK) {
+ mConnectedWindowBinder = binder;
+ } else {
+ disconnectNativeWindow();
+ }
+
+ return err;
}
// must call with lock held
@@ -434,10 +525,8 @@
return result;
}
-status_t MediaPlayer::reset()
+status_t MediaPlayer::reset_l()
{
- LOGV("reset");
- Mutex::Autolock _l(mLock);
mLoop = false;
if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
mPrepareSync = false;
@@ -458,6 +547,13 @@
return NO_ERROR;
}
+status_t MediaPlayer::reset()
+{
+ LOGV("reset");
+ Mutex::Autolock _l(mLock);
+ return reset_l();
+}
+
status_t MediaPlayer::setAudioStreamType(int type)
{
LOGV("MediaPlayer::setAudioStreamType");
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 5a5330d..0251baf 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -58,8 +58,10 @@
}
NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
- mLiveSession->disconnect();
- mLiveLooper->stop();
+ if (mLiveSession != NULL) {
+ mLiveSession->disconnect();
+ mLiveLooper->stop();
+ }
}
void NuPlayer::HTTPLiveSource::start() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7cd8b6c..c6fca2c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -118,9 +118,15 @@
mPlayer->start();
if (mStartupSeekTimeUs >= 0) {
- mPlayer->seekToAsync(mStartupSeekTimeUs);
+ if (mStartupSeekTimeUs == 0) {
+ notifySeekComplete();
+ } else {
+ mPlayer->seekToAsync(mStartupSeekTimeUs);
+ }
+
mStartupSeekTimeUs = -1;
}
+
break;
}
case PLAYING:
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 5cab60e..4f8336e 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -4330,26 +4330,19 @@
status_t QueryCodecs(
const sp<IOMX> &omx,
- const char *mime, bool queryDecoders,
+ const char *mime, bool queryDecoders, bool hwCodecOnly,
Vector<CodecCapabilities> *results) {
+ Vector<String8> matchingCodecs;
results->clear();
- for (int index = 0;; ++index) {
- const char *componentName;
+ OMXCodec::findMatchingCodecs(mime,
+ !queryDecoders /*createEncoder*/,
+ NULL /*matchComponentName*/,
+ hwCodecOnly ? OMXCodec::kHardwareCodecsOnly : 0 /*flags*/,
+ &matchingCodecs);
- if (!queryDecoders) {
- componentName = GetCodec(
- kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
- } else {
- componentName = GetCodec(
- kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
- }
-
- if (!componentName) {
- return OK;
- }
+ for (size_t c = 0; c < matchingCodecs.size(); c++) {
+ const char *componentName = matchingCodecs.itemAt(c).string();
if (strncmp(componentName, "OMX.", 4)) {
// Not an OpenMax component but a software codec.
@@ -4411,6 +4404,8 @@
CHECK_EQ(omx->freeNode(node), (status_t)OK);
}
+
+ return OK;
}
void OMXCodec::restorePatchedDataPointer(BufferInfo *info) {
diff --git a/media/libstagefright/codecs/aacenc/src/bit_cnt.c b/media/libstagefright/codecs/aacenc/src/bit_cnt.c
index dd0b9b4..8853efc 100644
--- a/media/libstagefright/codecs/aacenc/src/bit_cnt.c
+++ b/media/libstagefright/codecs/aacenc/src/bit_cnt.c
@@ -496,7 +496,7 @@
{
Word32 i, t0, t1, t2, t3, t00, t01;
- Word16 codeWord, codeLength;
+ UWord16 codeWord, codeLength;
Word16 sign, signLength;
diff --git a/media/libstagefright/codecs/aacenc/src/memalign.c b/media/libstagefright/codecs/aacenc/src/memalign.c
index 7d203527..44dd4ba 100644
--- a/media/libstagefright/codecs/aacenc/src/memalign.c
+++ b/media/libstagefright/codecs/aacenc/src/memalign.c
@@ -23,6 +23,11 @@
#include "memalign.h"
+#ifdef _MSC_VER
+#include <stddef.h>
+#else
+#include <stdint.h>
+#endif
/*****************************************************************************
*
@@ -66,8 +71,8 @@
pMemop->Set(CodecID, tmp, 0, size + alignment);
mem_ptr =
- (unsigned char *) ((unsigned int) (tmp + alignment - 1) &
- (~((unsigned int) (alignment - 1))));
+ (unsigned char *) ((intptr_t) (tmp + alignment - 1) &
+ (~((intptr_t) (alignment - 1))));
if (mem_ptr == tmp)
mem_ptr += alignment;
diff --git a/media/libstagefright/codecs/amrwbenc/src/cmnMemory.c b/media/libstagefright/codecs/amrwbenc/src/cmnMemory.c
deleted file mode 100644
index dd7c26d..0000000
--- a/media/libstagefright/codecs/amrwbenc/src/cmnMemory.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- ** Copyright 2003-2010, VisualOn, Inc.
- **
- ** 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.
- */
-/*******************************************************************************
- File: cmnMemory.c
-
- Content: sample code for memory operator implementation
-
-*******************************************************************************/
-#include "cmnMemory.h"
-
-#include <malloc.h>
-#if defined LINUX
-#include <string.h>
-#endif
-
-//VO_MEM_OPERATOR g_memOP;
-
-VO_U32 cmnMemAlloc (VO_S32 uID, VO_MEM_INFO * pMemInfo)
-{
- if (!pMemInfo)
- return VO_ERR_INVALID_ARG;
-
- pMemInfo->VBuffer = malloc (pMemInfo->Size);
- return 0;
-}
-
-VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pMem)
-{
- free (pMem);
- return 0;
-}
-
-VO_U32 cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize)
-{
- memset (pBuff, uValue, uSize);
- return 0;
-}
-
-VO_U32 cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
-{
- memcpy (pDest, pSource, uSize);
- return 0;
-}
-
-VO_U32 cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize)
-{
- return 0;
-}
-
-VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize)
-{
- return memcmp(pBuffer1, pBuffer2, uSize);
-}
-
-VO_U32 cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
-{
- memmove (pDest, pSource, uSize);
- return 0;
-}
-
diff --git a/media/libstagefright/codecs/common/cmnMemory.c b/media/libstagefright/codecs/common/cmnMemory.c
index dd7c26d..aa52bd9 100644
--- a/media/libstagefright/codecs/common/cmnMemory.c
+++ b/media/libstagefright/codecs/common/cmnMemory.c
@@ -21,10 +21,8 @@
*******************************************************************************/
#include "cmnMemory.h"
-#include <malloc.h>
-#if defined LINUX
+#include <stdlib.h>
#include <string.h>
-#endif
//VO_MEM_OPERATOR g_memOP;
diff --git a/media/libstagefright/codecs/common/include/voType.h b/media/libstagefright/codecs/common/include/voType.h
index 70b2e83..5f659ab 100644
--- a/media/libstagefright/codecs/common/include/voType.h
+++ b/media/libstagefright/codecs/common/include/voType.h
@@ -101,7 +101,7 @@
since the compiler does not support the way the component was written.
*/
#ifndef VO_SKIP64BIT
-#ifdef _WIN32
+#ifdef _MSC_VER
/** VO_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */
typedef unsigned __int64 VO_U64;
/** VO_S64 is a 64 bit signed quantity that is 64 bit word aligned */
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index ca61b3d..73b3d5b 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -494,6 +494,12 @@
bool firstTime = (mPlaylist == NULL);
+ if ((ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
+ // If we switch bandwidths, do not pay any heed to whether
+ // playlists changed since the last time...
+ mPlaylist.clear();
+ }
+
bool unchanged;
sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged);
if (playlist == NULL) {
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 817eac05..20225ba 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -345,56 +345,28 @@
#ifdef MTP_DEVICE
int MtpDataPacket::read(int fd) {
- // first read the header
- int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret != MTP_CONTAINER_HEADER_SIZE)
+ int ret = ::read(fd, mBuffer, mBufferSize);
+ if (ret < MTP_CONTAINER_HEADER_SIZE)
return -1;
- // then the following data
- int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
- allocate(total);
- int remaining = total - MTP_CONTAINER_HEADER_SIZE;
- ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
- if (ret != remaining)
- return -1;
-
- mPacketSize = total;
+ mPacketSize = ret;
mOffset = MTP_CONTAINER_HEADER_SIZE;
- return total;
-}
-
-int MtpDataPacket::readDataHeader(int fd) {
- int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret > 0)
- mPacketSize = ret;
- else
- mPacketSize = 0;
return ret;
}
int MtpDataPacket::write(int fd) {
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- // send header separately from data
- int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret == MTP_CONTAINER_HEADER_SIZE)
- ret = ::write(fd, mBuffer + MTP_CONTAINER_HEADER_SIZE,
- mPacketSize - MTP_CONTAINER_HEADER_SIZE);
- return (ret < 0 ? ret : 0);
-}
-
-int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
- MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
- MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ int ret = ::write(fd, mBuffer, mPacketSize);
return (ret < 0 ? ret : 0);
}
int MtpDataPacket::writeData(int fd, void* data, uint32_t length) {
- MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length + MTP_CONTAINER_HEADER_SIZE);
+ allocate(length);
+ memcpy(mBuffer + MTP_CONTAINER_HEADER_SIZE, data, length);
+ length += MTP_CONTAINER_HEADER_SIZE;
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret == MTP_CONTAINER_HEADER_SIZE)
- ret = ::write(fd, data, length);
+ int ret = ::write(fd, mBuffer, length);
return (ret < 0 ? ret : 0);
}
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 8a08948..2b81063 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -41,6 +41,7 @@
void setOperationCode(MtpOperationCode code);
void setTransactionID(MtpTransactionID id);
+ inline const uint8_t* getData() const { return mBuffer + MTP_CONTAINER_HEADER_SIZE; }
inline uint8_t getUInt8() { return (uint8_t)mBuffer[mOffset++]; }
inline int8_t getInt8() { return (int8_t)mBuffer[mOffset++]; }
uint16_t getUInt16();
@@ -95,11 +96,9 @@
#ifdef MTP_DEVICE
// fill our buffer with data from the given file descriptor
int read(int fd);
- int readDataHeader(int fd);
// write our data to the given file descriptor
int write(int fd);
- int writeDataHeader(int fd, uint32_t length);
int writeData(int fd, void* data, uint32_t length);
#endif
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 4047e2e..a9b539b 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -731,14 +731,12 @@
}
mfr.offset = 0;
mfr.length = fileLength;
-
- // send data header
- mData.setOperationCode(mRequest.getOperationCode());
- mData.setTransactionID(mRequest.getTransactionID());
- mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
+ mfr.command = mRequest.getOperationCode();
+ mfr.transaction_id = mRequest.getTransactionID();
// then transfer the file
- int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+ int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+ LOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
close(mfr.fd);
if (ret < 0) {
if (errno == ECANCELED)
@@ -798,15 +796,13 @@
}
mfr.offset = offset;
mfr.length = length;
+ mfr.command = mRequest.getOperationCode();
+ mfr.transaction_id = mRequest.getTransactionID();
mResponse.setParameter(1, length);
- // send data header
- mData.setOperationCode(mRequest.getOperationCode());
- mData.setTransactionID(mRequest.getTransactionID());
- mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
-
- // then transfer the file
- int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+ // transfer the file
+ int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+ LOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
close(mfr.fd);
if (ret < 0) {
if (errno == ECANCELED)
@@ -918,7 +914,7 @@
return MTP_RESPONSE_GENERAL_ERROR;
MtpResponseCode result = MTP_RESPONSE_OK;
mode_t mask;
- int ret;
+ int ret, initialData;
if (mSendObjectHandle == kInvalidObjectHandle) {
LOGE("Expected SendObjectInfo before SendObject");
@@ -926,12 +922,13 @@
goto done;
}
- // read the header
- ret = mData.readDataHeader(mFD);
- // FIXME - check for errors here.
-
- // reset so we don't attempt to send this back
- mData.reset();
+ // read the header, and possibly some data
+ ret = mData.read(mFD);
+ if (ret < MTP_CONTAINER_HEADER_SIZE) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ goto done;
+ }
+ initialData = ret - MTP_CONTAINER_HEADER_SIZE;
mtp_file_range mfr;
mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
@@ -945,16 +942,20 @@
fchmod(mfr.fd, mFilePermission);
umask(mask);
- mfr.offset = 0;
- mfr.length = mSendObjectFileSize;
+ if (initialData > 0)
+ ret = write(mfr.fd, mData.getData(), initialData);
- LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
- // transfer the file
- ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ if (mSendObjectFileSize - initialData > 0) {
+ mfr.offset = initialData;
+ mfr.length = mSendObjectFileSize - initialData;
+
+ LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
+ // transfer the file
+ ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ LOGV("MTP_RECEIVE_FILE returned %d\n", ret);
+ }
close(mfr.fd);
- LOGV("MTP_RECEIVE_FILE returned %d", ret);
-
if (ret < 0) {
unlink(mSendObjectFilePath);
if (errno == ECANCELED)
@@ -964,6 +965,9 @@
}
done:
+ // reset so we don't attempt to send the data back
+ mData.reset();
+
mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
result == MTP_RESPONSE_OK);
mSendObjectHandle = kInvalidObjectHandle;
@@ -1096,23 +1100,31 @@
return MTP_RESPONSE_GENERAL_ERROR;
}
- // read the header
- int ret = mData.readDataHeader(mFD);
- // FIXME - check for errors here.
-
- // reset so we don't attempt to send this back
- mData.reset();
-
const char* filePath = (const char *)edit->mPath;
- LOGV("receiving partial %s %lld %ld\n", filePath, offset, length);
- mtp_file_range mfr;
- mfr.fd = edit->mFD;
- mfr.offset = offset;
- mfr.length = length;
+ LOGV("receiving partial %s %lld %lld\n", filePath, offset, length);
- // transfer the file
- ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
- LOGV("MTP_RECEIVE_FILE returned %d", ret);
+ // read the header, and possibly some data
+ int ret = mData.read(mFD);
+ if (ret < MTP_CONTAINER_HEADER_SIZE)
+ return MTP_RESPONSE_GENERAL_ERROR;
+ int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
+
+ if (initialData > 0) {
+ ret = write(edit->mFD, mData.getData(), initialData);
+ offset += initialData;
+ length -= initialData;
+ }
+
+ if (length > 0) {
+ mtp_file_range mfr;
+ mfr.fd = edit->mFD;
+ mfr.offset = offset;
+ mfr.length = length;
+
+ // transfer the file
+ ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ LOGV("MTP_RECEIVE_FILE returned %d", ret);
+ }
if (ret < 0) {
mResponse.setParameter(1, 0);
if (errno == ECANCELED)
@@ -1120,6 +1132,9 @@
else
return MTP_RESPONSE_GENERAL_ERROR;
}
+
+ // reset so we don't attempt to send this back
+ mData.reset();
mResponse.setParameter(1, length);
uint64_t end = offset + length;
if (end > edit->mSize) {
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 2c0e88e..5c016c4 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -81,39 +81,9 @@
int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
ARect* inOutDirtyBounds) {
- int type = -1;
- if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &type) != 0 ||
- type != NATIVE_WINDOW_SURFACE) {
- return BAD_VALUE;
- }
-
- Region dirtyRegion;
- Region* dirtyParam = NULL;
- if (inOutDirtyBounds != NULL) {
- dirtyRegion.set(*(Rect*)inOutDirtyBounds);
- dirtyParam = &dirtyRegion;
- }
-
- Surface::SurfaceInfo info;
- status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam);
- if (res != OK) {
- return -1;
- }
-
- outBuffer->width = (int32_t)info.w;
- outBuffer->height = (int32_t)info.h;
- outBuffer->stride = (int32_t)info.s;
- outBuffer->format = (int32_t)info.format;
- outBuffer->bits = info.bits;
-
- if (inOutDirtyBounds != NULL) {
- *inOutDirtyBounds = dirtyRegion.getBounds();
- }
-
- return 0;
+ return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
}
int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
- status_t res = static_cast<Surface*>(window)->unlockAndPost();
- return res == android::OK ? 0 : -1;
+ return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
}
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 337fa96..2f4f2d3 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -99,10 +99,16 @@
* width and height must be either both zero or both non-zero.
*
*/
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
+ int32_t width, int32_t height, int32_t format);
/**
* Lock the window's next drawing surface for writing.
+ * inOutDirtyBounds is used as an in/out parameter, upon entering the
+ * function, it contains the dirty region, that is, the region the caller
+ * intends to redraw. When the function returns, inOutDirtyBounds is updated
+ * with the actual area the caller needs to redraw -- this region is often
+ * extended by ANativeWindow_lock.
*/
int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
ARect* inOutDirtyBounds);
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1123e16..6a199db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -226,7 +226,7 @@
#ifndef EGL_ANDROID_image_native_buffer
#define EGL_ANDROID_image_native_buffer 1
struct ANativeWindowBuffer;
-#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
#endif
#ifndef EGL_ANDROID_swap_rectangle
@@ -237,6 +237,11 @@
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
#endif
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142 /* EGLConfig attribute */
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/specs/EGL_ANDROID_recordable.txt b/opengl/specs/EGL_ANDROID_recordable.txt
index cf44465..8dbd26f 100644
--- a/opengl/specs/EGL_ANDROID_recordable.txt
+++ b/opengl/specs/EGL_ANDROID_recordable.txt
@@ -55,7 +55,7 @@
Accepted by the <attribute> parameter of eglGetConfigAttrib and
the <attrib_list> parameter of eglChooseConfig:
- EGL_RECORDABLE_ANDROID 0xXXXX
+ EGL_RECORDABLE_ANDROID 0x3142
Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
@@ -103,11 +103,38 @@
RESOLVED: It should not affect sorting. Some implementations may not have
any drawback associated with using a recordable EGLConfig. Such
- implementations should not have to double-up some of their configs to one sort earlier than .
- Implementations that do have drawbacks can use the existing caveat
- mechanism to report this drawback to the client.
+ implementations should not have to double-up some of their configs to one
+ sort earlier than . Implementations that do have drawbacks can use the
+ existing caveat mechanism to report this drawback to the client.
+
+ 3. How is this extension expected to be implemented?
+
+ RESPONSE: There are two basic approaches to implementing this extension
+ that were considered during its design. In both cases it is assumed that a
+ color space conversion must be performed at some point because most video
+ encoding formats use a YUV color space. The two approaches are
+ distinguished by the point at which this color space conversion is
+ performed.
+
+ One approach involves performing the color space conversion as part of the
+ eglSwapBuffers call before queuing the rendered image to the ANativeWindow.
+ In this case, the VisualID of the EGLConfig would correspond to a YUV
+ Android HAL pixel format from which the video encoder can read. The
+ EGLConfig would likely have the EGL_SLOW_CONFIG caveat because using that
+ config to render normal window contents would result in an RGB -> YUV color
+ space conversion when rendering the frame as well as a YUV -> RGB
+ conversion when compositing the window.
+
+ The other approach involves performing the color space conversion in the
+ video encoder. In this case, the VisualID of the EGLConfig would
+ correspond to an RGB HAL pixel format from which the video encoder can
+ read. The EGLConfig would likely not need to have any caveat set, as using
+ this config for normal window rendering would not have any added cost.
Revision History
+#2 (Jamie Gennis, July 15, 2011)
+ - Added issue 3.
+
#1 (Jamie Gennis, July 8, 2011)
- Initial draft.
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml b/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml
deleted file mode 100644
index 0e58e12..0000000
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
-
- <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
-
- <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
- <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
- <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
- <item android:state_focused="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml b/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml
new file mode 100644
index 0000000..6cae2c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/recents_thumbnail_bg" android:id="@+id/base_layer"/>
+ <item android:drawable="@drawable/recents_thumbnail_overlay" android:id="@+id/overlay_layer"/>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
new file mode 100644
index 0000000..200bac4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+ <item android:drawable="@*android:color/transparent"/>
+</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index be4f1d7..8c29042 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -24,14 +24,15 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
- <ImageView android:id="@+id/app_thumbnail"
+ <FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
- android:background="@drawable/recents_thumbnail_bg_selector"
+ android:clickable="true"
+ android:background="@drawable/recents_thumbnail_layers"
/>
<ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index efdd9ac..20ef7cf 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -51,7 +51,6 @@
android:fadingEdge="horizontal"
android:scrollbars="none"
android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
- android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:layout_gravity="bottom|left"
android:orientation="horizontal"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index 76965c9..c705a69 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -24,13 +24,15 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
- <ImageView android:id="@+id/app_thumbnail"
+ <FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
+ android:clickable="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
+ android:background="@drawable/recents_thumbnail_layers"
/>
<ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index 28ef239..c680b8e 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -48,7 +48,6 @@
android:fadingEdge="vertical"
android:scrollbars="none"
android:fadingEdgeLength="@*android:dimen/status_bar_height"
- android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:layout_gravity="bottom|left"
android:clipToPadding="false"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 9687866..386ce30 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -24,13 +24,15 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
- <ImageView android:id="@+id/app_thumbnail"
+ <FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
+ android:clickable="true"
+ android:background="@drawable/recents_thumbnail_layers"
/>
<ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 75fdc67..2c9a152 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -56,7 +56,6 @@
android:scrollbars="none"
android:fadingEdgeLength="20dip"
android:layout_gravity="bottom|left"
- android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:clipToPadding="false"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml b/packages/SystemUI/res/menu/recent_popup_menu.xml
similarity index 70%
rename from packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
rename to packages/SystemUI/res/menu/recent_popup_menu.xml
index f9bba2a..eecfb9a 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
+++ b/packages/SystemUI/res/menu/recent_popup_menu.xml
@@ -17,7 +17,7 @@
** limitations under the License.
*/
-->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
- <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
-</transition>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/recent_remove_item" android:title="@string/status_bar_recent_remove_item_title" />
+ <item android:id="@+id/recent_inspect_item" android:title="@string/status_bar_recent_inspect_item_title" />
+</menu>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 882455e..01cf2dc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -35,6 +35,14 @@
shown again. [CHAR LIMIT=25] -->
<string name="status_bar_please_disturb_button">Show notifications</string>
+ <!-- Title shown in recents popup for removing an application from the list -->
+ <string name="status_bar_recent_remove_item_title">Remove</string>
+
+ <!-- Title shown in recents popup for inspecting an application's properties -->
+ <string name="status_bar_recent_inspect_item_title">Inspect</string>
+
+
+
<!-- The label in the bar at the top of the status bar when there are no notifications
showing. [CHAR LIMIT=40]-->
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index 37a9913..2d327c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -53,8 +53,6 @@
void createAnimation(boolean appearing) {
float start, end;
- if (RecentsPanelView.DEBUG) Log.e(TAG, "createAnimation()", new Exception());
-
// 0: on-screen
// height: off-screen
float y = mContentView.getTranslationY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 5d29e2a..797f94c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -26,5 +26,5 @@
void handleOnClick(View selectedView);
void handleSwipe(View selectedView, int direction);
- void handleLongPress(View selectedView);
+ void handleLongPress(View selectedView, View anchorView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index f984aac..2a5d1dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -20,6 +20,7 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -30,7 +31,6 @@
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -42,10 +42,9 @@
import com.android.systemui.R;
-public class RecentsHorizontalScrollView extends HorizontalScrollView
- implements View.OnClickListener, View.OnTouchListener {
- private static final boolean DEBUG_INVALIDATE = false;
+public class RecentsHorizontalScrollView extends HorizontalScrollView {
private static final String TAG = RecentsPanelView.TAG;
+ private static final boolean DEBUG_INVALIDATE = false;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
private LinearLayout mLinearLayout;
private ActivityDescriptionAdapter mAdapter;
@@ -57,6 +56,15 @@
private VelocityTracker mVelocityTracker;
private float mDensityScale;
private float mPagingTouchSlop;
+ private OnLongClickListener mOnLongClick = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = v.findViewById(R.id.app_description);
+ mCurrentView = v;
+ mCallback.handleLongPress(v, anchorView);
+ mCurrentView = null; // make sure we don't accept the return click from this
+ return true;
+ }
+ };
public RecentsHorizontalScrollView(Context context) {
this(context, null);
@@ -72,13 +80,12 @@
return mLinearLayout.getWidth() - getWidth();
}
- public void update() {
+ private void update() {
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- View view = mAdapter.getView(i, null, mLinearLayout);
+ final View view = mAdapter.getView(i, null, mLinearLayout);
view.setClickable(true);
- view.setOnClickListener(this);
- view.setOnTouchListener(this);
+ view.setOnLongClickListener(mOnLongClick);
mLinearLayout.addView(view);
}
// Scroll to end after layout.
@@ -91,7 +98,20 @@
}
@Override
+ public void removeViewInLayout(final View view) {
+ ObjectAnimator anim = animateClosed(view, Constants.MAX_ESCAPE_ANIMATION_DURATION,
+ "y", view.getY(), view.getY() + view.getHeight());
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ RecentsHorizontalScrollView.super.removeView(view);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
@@ -100,6 +120,18 @@
case MotionEvent.ACTION_DOWN:
mDragging = false;
mLastY = ev.getY();
+ final float x = ev.getX() + getScrollX();
+ final float y = ev.getY() + getScrollY();
+ mCurrentView = null;
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View item = mLinearLayout.getChildAt(i);
+ if (x >= item.getLeft() && x < item.getRight()
+ && y >= item.getTop() && y < item.getBottom()) {
+ mCurrentView = item;
+ if (DEBUG) Log.v(TAG, "Hit item " + item);
+ break;
+ }
+ }
break;
case MotionEvent.ACTION_MOVE:
@@ -111,6 +143,9 @@
break;
case MotionEvent.ACTION_UP:
+ if (mCurrentView != null) {
+ mCallback.handleOnClick(mCurrentView);
+ }
mDragging = false;
break;
}
@@ -125,7 +160,6 @@
} else if (view.getY() < thumbHeight * (1.0f - Constants.ALPHA_FADE_START)) {
result = 1.0f + (thumbHeight * Constants.ALPHA_FADE_START + view.getY()) / fadeHeight;
}
- if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -138,12 +172,12 @@
mVelocityTracker.addMovement(ev);
final View animView = mCurrentView;
- // TODO: Cache thumbnail
- final View thumb = animView.findViewById(R.id.app_thumbnail);
+
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (animView != null) {
final float delta = ev.getY() - mLastY;
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
animView.setY(animView.getY() + delta);
animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
invalidateGlobalRegion(animView);
@@ -167,35 +201,18 @@
long duration =
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
- anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
- anim.setInterpolator(new LinearInterpolator());
- final int swipeDirection = animView.getY() >= 0.0f ?
- RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
- anim.addListener(new AnimatorListener() {
- public void onAnimationStart(Animator animation) {
- }
- public void onAnimationRepeat(Animator animation) {
- }
- public void onAnimationEnd(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- public void onAnimationCancel(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- });
- anim.setDuration(duration);
+ anim = animateClosed(animView, duration, "y", curY, newY);
} else { // Animate back to position
long duration = Math.abs(velocityY) > 0.0f ?
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
: Constants.SNAP_BACK_DURATION;
duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
- anim.setInterpolator(new DecelerateInterpolator(2.0f));
+ anim.setInterpolator(new DecelerateInterpolator(4.0f));
anim.setDuration(duration);
}
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
@@ -212,6 +229,26 @@
return true;
}
+ private ObjectAnimator animateClosed(final View animView, long duration,
+ String attr, float from, float to) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(animView, attr, from, to);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getX() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ return anim;
+ }
+
void invalidateGlobalRegion(View view) {
RectF childBounds
= new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
@@ -236,13 +273,8 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
setScrollbarFadingEnabled(true);
-
mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-
final int leftPadding = mContext.getResources()
.getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
setOverScrollEffectPadding(leftPadding, 0);
@@ -306,16 +338,7 @@
mLinearLayout.setLayoutTransition(transition);
}
- public void onClick(View view) {
- mCallback.handleOnClick(view);
- }
-
public void setCallback(RecentsCallback callback) {
mCallback = callback;
}
-
- public boolean onTouch(View v, MotionEvent event) {
- mCurrentView = v;
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index a55fe9c..bc0a508 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -22,6 +22,7 @@
import android.animation.Animator;
import android.animation.LayoutTransition;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -39,16 +40,22 @@
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
+import android.widget.Button;
import android.widget.ImageView;
+import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -69,7 +76,7 @@
private int mIconDpi;
private View mRecentsScrim;
private View mRecentsGlowView;
- private View mRecentsContainer;
+ private ViewGroup mRecentsContainer;
private Bitmap mGlowBitmap;
// TODO: add these widgets attributes to the layout file
private int mGlowBitmapPaddingLeftPx;
@@ -107,8 +114,18 @@
}
};
+ private final class OnLongClickDelegate implements View.OnLongClickListener {
+ View mOtherView;
+ OnLongClickDelegate(View other) {
+ mOtherView = other;
+ }
+ public boolean onLongClick(View v) {
+ return mOtherView.performLongClick();
+ }
+ }
+
/* package */ final static class ViewHolder {
- ImageView thumbnailView;
+ View thumbnailView;
ImageView iconView;
TextView labelView;
TextView descriptionView;
@@ -139,7 +156,7 @@
if (convertView == null) {
convertView = mInflater.inflate(R.layout.status_bar_recent_item, null);
holder = new ViewHolder();
- holder.thumbnailView = (ImageView) convertView.findViewById(R.id.app_thumbnail);
+ holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -153,11 +170,12 @@
final ActivityDescription activityDescription = mActivityDescriptions.get(activityId);
final Bitmap thumb = activityDescription.thumbnail;
- holder.thumbnailView.setImageBitmap(compositeBitmap(mGlowBitmap, thumb));
+ updateDrawable(holder.thumbnailView, compositeBitmap(mGlowBitmap, thumb));
holder.iconView.setImageDrawable(activityDescription.icon);
holder.labelView.setText(activityDescription.label);
holder.descriptionView.setText(activityDescription.description);
holder.thumbnailView.setTag(activityDescription);
+ holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
holder.activityDescription = activityDescription;
return convertView;
@@ -174,6 +192,20 @@
return x >= l && x < r && y >= t && y < b;
}
+ private void updateDrawable(View thumbnailView, Bitmap bitmap) {
+ Drawable d = thumbnailView.getBackground();
+ if (d instanceof LayerDrawable) {
+ LayerDrawable layerD = (LayerDrawable) d;
+ Drawable thumb = layerD.findDrawableByLayerId(R.id.base_layer);
+ if (thumb != null) {
+ layerD.setDrawableByLayerId(R.id.base_layer,
+ new BitmapDrawable(getResources(), bitmap));
+ return;
+ }
+ }
+ Log.w(TAG, "Failed to update drawable");
+ }
+
public void show(boolean show, boolean animate) {
if (animate) {
if (mShowing != show) {
@@ -260,7 +292,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mRecentsContainer = findViewById(R.id.recents_container);
+ mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
mListAdapter = new ActivityDescriptionAdapter(mContext);
if (mRecentsContainer instanceof RecentsListView) {
RecentsListView listView = (RecentsListView) mRecentsContainer;
@@ -503,7 +535,35 @@
am.removeTask(ad.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
}
- public void handleLongPress(View selectedView) {
- // TODO show context menu : "Remove from list", "Show properties"
+ private void startApplicationDetailsActivity(String packageName) {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", packageName, null));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ }
+
+ public void handleLongPress(final View selectedView, final View anchorView) {
+ PopupMenu popup = new PopupMenu(mContext, anchorView == null ? selectedView : anchorView);
+ popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
+ popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == R.id.recent_remove_item) {
+ mRecentsContainer.removeViewInLayout(selectedView);
+ } else if (item.getItemId() == R.id.recent_inspect_item) {
+ ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
+ if (viewHolder != null) {
+ final ActivityDescription ad = viewHolder.activityDescription;
+ startApplicationDetailsActivity(ad.packageName);
+ mBar.animateCollapse();
+ } else {
+ throw new IllegalStateException("Oops, no tag on view " + selectedView);
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+ });
+ popup.show();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 27bb0b5..47ee4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -20,6 +20,7 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -42,8 +43,7 @@
import com.android.systemui.R;
-public class RecentsVerticalScrollView extends ScrollView
- implements View.OnClickListener, View.OnTouchListener {
+public class RecentsVerticalScrollView extends ScrollView {
private static final String TAG = RecentsPanelView.TAG;
private static final boolean DEBUG_INVALIDATE = false;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -57,6 +57,15 @@
private VelocityTracker mVelocityTracker;
private float mDensityScale;
private float mPagingTouchSlop;
+ private OnLongClickListener mOnLongClick = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = v.findViewById(R.id.app_description);
+ mCurrentView = v;
+ mCallback.handleLongPress(v, anchorView);
+ mCurrentView = null; // make sure we don't accept the return click from this
+ return true;
+ }
+ };
public RecentsVerticalScrollView(Context context) {
this(context, null);
@@ -72,13 +81,12 @@
return mLinearLayout.getHeight() - getHeight();
}
- public void update() {
+ private void update() {
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- View view = mAdapter.getView(i, null, mLinearLayout);
+ final View view = mAdapter.getView(i, null, mLinearLayout);
view.setClickable(true);
- view.setOnClickListener(this);
- view.setOnTouchListener(this);
+ view.setOnLongClickListener(mOnLongClick);
mLinearLayout.addView(view);
}
// Scroll to end after layout.
@@ -91,7 +99,20 @@
}
@Override
+ public void removeViewInLayout(final View view) {
+ ObjectAnimator anim = animateClosed(view, Constants.MAX_ESCAPE_ANIMATION_DURATION,
+ "x", view.getX(), view.getX() + view.getWidth());
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ RecentsVerticalScrollView.super.removeView(view);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
@@ -100,6 +121,18 @@
case MotionEvent.ACTION_DOWN:
mDragging = false;
mLastX = ev.getX();
+ final float x = ev.getX() + getScrollX();
+ final float y = ev.getY() + getScrollY();
+ mCurrentView = null;
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View item = mLinearLayout.getChildAt(i);
+ if (x >= item.getLeft() && x < item.getRight()
+ && y >= item.getTop() && y < item.getBottom()) {
+ mCurrentView = item;
+ Log.v(TAG, "Hit item " + item);
+ break;
+ }
+ }
break;
case MotionEvent.ACTION_MOVE:
@@ -111,6 +144,9 @@
break;
case MotionEvent.ACTION_UP:
+ if (mCurrentView != null) {
+ mCallback.handleOnClick(mCurrentView);
+ }
mDragging = false;
break;
}
@@ -125,7 +161,6 @@
} else if (view.getX() < thumbWidth* (1.0f - Constants.ALPHA_FADE_START)) {
result = 1.0f + (thumbWidth*Constants.ALPHA_FADE_START + view.getX()) / fadeWidth;
}
- if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -138,12 +173,12 @@
mVelocityTracker.addMovement(ev);
final View animView = mCurrentView;
- // TODO: Cache thumbnail
- final View thumb = animView.findViewById(R.id.app_thumbnail);
+
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (animView != null) {
final float delta = ev.getX() - mLastX;
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
animView.setX(animView.getX() + delta);
animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
invalidateGlobalRegion(animView);
@@ -163,29 +198,11 @@
final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
if (Math.abs(velocityX) > Math.abs(velocityY)
&& Math.abs(velocityX) > maxVelocity
- && (velocityX > 0.0f) == (animView.getX() >= 0)) {
+ && (velocityX >= 0.0f) == (animView.getX() >= 0)) {
long duration =
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
- anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
- anim.setInterpolator(new LinearInterpolator());
- final int swipeDirection = animView.getX() >= 0.0f ?
- RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
- anim.addListener(new AnimatorListener() {
- public void onAnimationStart(Animator animation) {
- }
- public void onAnimationRepeat(Animator animation) {
- }
- public void onAnimationEnd(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- public void onAnimationCancel(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- });
- anim.setDuration(duration);
+ anim = animateClosed(animView, duration, "x", curX, newX);
} else { // Animate back to position
long duration = Math.abs(velocityX) > 0.0f ?
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
@@ -196,6 +213,7 @@
anim.setDuration(duration);
}
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
@@ -212,6 +230,26 @@
return true;
}
+ private ObjectAnimator animateClosed(final View animView, long duration,
+ String attr, float from, float to) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(animView, attr, from, to);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getX() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ return anim;
+ }
+
void invalidateGlobalRegion(View view) {
RectF childBounds
= new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
@@ -236,13 +274,8 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
setScrollbarFadingEnabled(true);
-
mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-
final int leftPadding = mContext.getResources()
.getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
setOverScrollEffectPadding(leftPadding, 0);
@@ -306,16 +339,7 @@
mLinearLayout.setLayoutTransition(transition);
}
- public void onClick(View view) {
- mCallback.handleOnClick(view);
- }
-
public void setCallback(RecentsCallback callback) {
mCallback = callback;
}
-
- public boolean onTouch(View v, MotionEvent event) {
- mCurrentView = v;
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index dedbe5d..af5c72d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -218,9 +218,165 @@
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
- R.drawable.stat_sys_roaming_cdma_0 //83
+ R.drawable.stat_sys_roaming_cdma_0, //83
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0 //239
- // 128-255 Reserved
+ // 240-255 Reserved
};
//***** Data connection icons
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9b09983..0eff776 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -502,77 +502,82 @@
// ----------------------------------------------------------------------------
-// set the Surface that the preview will use
-status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
- LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
+static void disconnectWindow(const sp<ANativeWindow>& window) {
+ if (window != 0) {
+ status_t result = native_window_disconnect(window.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (result != NO_ERROR) {
+ LOGW("native_window_disconnect failed: %s (%d)", strerror(-result),
+ result);
+ }
+ }
+}
+
+status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder,
+ const sp<ANativeWindow>& window) {
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
- result = NO_ERROR;
-
// return if no change in surface.
- sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
if (binder == mSurface) {
- return result;
+ return NO_ERROR;
}
- if (mSurface != 0) {
- LOG1("clearing old preview surface %p", mSurface.get());
- }
- mSurface = binder;
- mPreviewWindow = surface;
-
- // If preview has been already started, register preview
- // buffers now.
- if (mHardware->previewEnabled()) {
- if (mPreviewWindow != 0) {
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
- result = mHardware->setPreviewWindow(mPreviewWindow);
+ if (window != 0) {
+ result = native_window_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
+ if (result != NO_ERROR) {
+ LOGE("native_window_connect failed: %s (%d)", strerror(-result),
+ result);
+ return result;
}
}
+ // If preview has been already started, register preview buffers now.
+ if (mHardware->previewEnabled()) {
+ if (window != 0) {
+ native_window_set_buffers_transform(window.get(), mOrientation);
+ result = mHardware->setPreviewWindow(window);
+ }
+ }
+
+ if (result == NO_ERROR) {
+ // Everything has succeeded. Disconnect the old window and remember the
+ // new window.
+ disconnectWindow(mPreviewWindow);
+ mSurface = binder;
+ mPreviewWindow = window;
+ } else {
+ // Something went wrong after we connected to the new window, so
+ // disconnect here.
+ disconnectWindow(window);
+ }
+
return result;
}
+// set the Surface that the preview will use
+status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
+ LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
+
+ sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
+ sp<ANativeWindow> window(surface);
+ return setPreviewWindow(binder, window);
+}
+
// set the SurfaceTexture that the preview will use
status_t CameraService::Client::setPreviewTexture(
const sp<ISurfaceTexture>& surfaceTexture) {
LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
getCallingPid());
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
- // return if no change in surface.
- // asBinder() is safe on NULL (returns NULL)
- if (surfaceTexture->asBinder() == mSurface) {
- return result;
- }
-
- if (mSurface != 0) {
- LOG1("clearing old preview surface %p", mSurface.get());
- }
- mSurface = surfaceTexture->asBinder();
+ sp<IBinder> binder;
+ sp<ANativeWindow> window;
if (surfaceTexture != 0) {
- mPreviewWindow = new SurfaceTextureClient(surfaceTexture);
- } else {
- mPreviewWindow = 0;
+ binder = surfaceTexture->asBinder();
+ window = new SurfaceTextureClient(surfaceTexture);
}
-
- // If preview has been already started, set overlay or register preview
- // buffers now.
- if (mHardware->previewEnabled()) {
- // XXX: What if the new preview window is 0?
- if (mPreviewWindow != 0) {
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
- result = mHardware->setPreviewWindow(mPreviewWindow);
- }
- }
-
- return result;
+ return setPreviewWindow(binder, window);
}
// set the preview callback flag to affect how the received frames from
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 5e2d571..c5fefb8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -161,6 +161,10 @@
int getOrientation(int orientation, bool mirror);
+ status_t setPreviewWindow(
+ const sp<IBinder>& binder,
+ const sp<ANativeWindow>& window);
+
// these are initialized in the constructor.
sp<CameraService> mCameraService; // immutable after constructor
sp<ICameraClient> mCameraClient;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index a8dc885..bb9d15b 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -127,13 +127,15 @@
private int mHandledFeedbackTypes = 0;
- private boolean mIsEnabled;
+ private boolean mIsAccessibilityEnabled;
+
+ private boolean mIsTouchExplorationRequested;
private AccessibilityInputFilter mInputFilter;
private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>();
- private boolean mHasInputFilter;
+ private boolean mIsTouchExplorationEnabled;
private final WindowManagerService mWindowManagerService;
@@ -230,16 +232,21 @@
if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
synchronized (mLock) {
populateAccessibilityServiceListLocked();
- // get the accessibility enabled setting on boot
- mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ // get accessibility enabled setting on boot
+ mIsAccessibilityEnabled = Settings.Secure.getInt(
+ mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-
// if accessibility is enabled inform our clients we are on
- if (mIsEnabled) {
- updateClientsLocked();
+ if (mIsAccessibilityEnabled) {
+ sendAccessibilityEnabledToClientsLocked();
}
-
manageServicesLocked();
+
+ // get touch exploration enabled setting on boot
+ mIsTouchExplorationRequested = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
+ updateTouchExplorationEnabledLocked();
}
return;
@@ -264,29 +271,48 @@
private void registerSettingsContentObservers() {
ContentResolver contentResolver = mContext.getContentResolver();
- Uri enabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_ENABLED);
- contentResolver.registerContentObserver(enabledUri, false,
+ Uri accessibilityEnabledUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_ENABLED);
+ contentResolver.registerContentObserver(accessibilityEnabledUri, false,
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
synchronized (mLock) {
- mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ mIsAccessibilityEnabled = Settings.Secure.getInt(
+ mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
- if (mIsEnabled) {
+ if (mIsAccessibilityEnabled) {
manageServicesLocked();
} else {
unbindAllServicesLocked();
}
- updateClientsLocked();
+ sendAccessibilityEnabledToClientsLocked();
}
}
});
- Uri providersUri =
+ Uri touchExplorationRequestedUri = Settings.Secure.getUriFor(
+ Settings.Secure.TOUCH_EXPLORATION_REQUESTED);
+ contentResolver.registerContentObserver(touchExplorationRequestedUri, false,
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+
+ synchronized (mLock) {
+ mIsTouchExplorationRequested = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
+ updateTouchExplorationEnabledLocked();
+ }
+ }
+ });
+
+ Uri accessibilityServicesUri =
Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- contentResolver.registerContentObserver(providersUri, false,
+ contentResolver.registerContentObserver(accessibilityServicesUri, false,
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
@@ -312,7 +338,7 @@
}
}
}, 0);
- return mIsEnabled;
+ return mIsAccessibilityEnabled;
}
}
@@ -602,7 +628,7 @@
service.linkToOwnDeath();
mServices.add(service);
mComponentNameToServiceMap.put(service.mComponentName, service);
- updateInputFilterLocked();
+ updateTouchExplorationEnabledLocked();
} catch (RemoteException e) {
/* do nothing */
}
@@ -622,7 +648,7 @@
mComponentNameToServiceMap.remove(service.mComponentName);
mHandler.removeMessages(service.mId);
service.unlinkToOwnDeath();
- updateInputFilterLocked();
+ updateTouchExplorationEnabledLocked();
return removed;
}
@@ -727,7 +753,7 @@
Set<ComponentName> enabledServices) {
Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
- boolean isEnabled = mIsEnabled;
+ boolean isEnabled = mIsAccessibilityEnabled;
for (int i = 0, count = installedServices.size(); i < count; i++) {
AccessibilityServiceInfo installedService = installedServices.get(i);
@@ -741,7 +767,7 @@
service = new Service(componentName, installedService, false);
}
service.bind();
- } else if (!enabledServices.contains(componentName)) {
+ } else {
if (service != null) {
service.unbind();
}
@@ -757,10 +783,10 @@
/**
* Updates the state of {@link android.view.accessibility.AccessibilityManager} clients.
*/
- private void updateClientsLocked() {
+ private void sendAccessibilityEnabledToClientsLocked() {
for (int i = 0, count = mClients.size(); i < count; i++) {
try {
- mClients.get(i).setEnabled(mIsEnabled);
+ mClients.get(i).setEnabled(mIsAccessibilityEnabled);
} catch (RemoteException re) {
mClients.remove(i);
count--;
@@ -770,29 +796,48 @@
}
/**
- * Updates the input filter state. The filter is enabled if accessibility
- * is enabled and there is at least one accessibility service providing
- * spoken feedback.
+ * Sends the touch exploration state to clients.
*/
- private void updateInputFilterLocked() {
- if (mIsEnabled) {
- final boolean hasSpokenFeedbackServices = !getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
- if (hasSpokenFeedbackServices) {
- if (mHasInputFilter) {
- return;
+ private void sendTouchExplorationEnabledToClientsLocked() {
+ for (int i = 0, count = mClients.size(); i < count; i++) {
+ try {
+ mClients.get(i).setTouchExplorationEnabled(mIsTouchExplorationEnabled);
+ } catch (RemoteException re) {
+ mClients.remove(i);
+ count--;
+ i--;
+ }
+ }
+ }
+
+ /**
+ * Updates the touch exploration state. Touch exploration is enabled if it
+ * is requested, accessibility is on and there is at least one enabled
+ * accessibility service providing spoken feedback.
+ */
+ private void updateTouchExplorationEnabledLocked() {
+ if (mIsAccessibilityEnabled && mIsTouchExplorationRequested) {
+ final boolean hasSpeakingServicesEnabled = !getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
+ if (!mIsTouchExplorationEnabled) {
+ if (!hasSpeakingServicesEnabled) {
+ return;
}
if (mInputFilter == null) {
mInputFilter = new AccessibilityInputFilter(mContext);
}
mWindowManagerService.setInputFilter(mInputFilter);
- mHasInputFilter = true;
+ mIsTouchExplorationEnabled = true;
+ sendTouchExplorationEnabledToClientsLocked();
+ return;
+ } else if (hasSpeakingServicesEnabled) {
return;
}
}
- if (mHasInputFilter) {
+ if (mIsTouchExplorationEnabled) {
mWindowManagerService.setInputFilter(null);
- mHasInputFilter = false;
+ mIsTouchExplorationEnabled = false;
+ sendTouchExplorationEnabledToClientsLocked();
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a8fb1ed..94af46d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3610,8 +3610,10 @@
String processName = app.processName;
try {
- thread.asBinder().linkToDeath(new AppDeathRecipient(
- app, pid, thread), 0);
+ AppDeathRecipient adr = new AppDeathRecipient(
+ app, pid, thread);
+ thread.asBinder().linkToDeath(adr, 0);
+ app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList();
startProcessLocked(app, "link fail", processName);
@@ -3687,6 +3689,7 @@
Slog.w(TAG, "Exception thrown during bind!", e);
app.resetPackageList();
+ app.unlinkDeathRecipient();
startProcessLocked(app, "bind fail", processName);
return false;
}
@@ -9210,6 +9213,7 @@
app.notResponding = false;
app.resetPackageList();
+ app.unlinkDeathRecipient();
app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
@@ -9327,7 +9331,6 @@
// This app is persistent, so we need to keep its record around.
// If it is not already on the pending app list, add it there
// and start a new process for it.
- app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
if (mPersistentStartingProcesses.indexOf(app) < 0) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 99830f9..9e597aa 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -73,6 +73,7 @@
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
int lruSeq; // Sequence id for identifying LRU update cycles
CompatibilityInfo compat; // last used compatibility mode
+ IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
ComponentName instrumentationClass;// class installed to instrument app
ApplicationInfo instrumentationInfo; // the application being instrumented
String instrumentationProfileFile; // where to save profiling
@@ -297,6 +298,13 @@
}
}
+ public void unlinkDeathRecipient() {
+ if (deathRecipient != null && thread != null) {
+ thread.asBinder().unlinkToDeath(deathRecipient, 0);
+ }
+ deathRecipient = null;
+ }
+
public String toShortString() {
if (shortStringName != null) {
return shortStringName;
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 3139798..c80cd0a 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -473,10 +473,7 @@
case MSG_SET_CURRENT_FUNCTION:
String function = (String)msg.obj;
boolean makeDefault = (msg.arg1 == 1);
- if (makeDefault) {
- if (function == null) {
- throw new NullPointerException();
- }
+ if (function != null && makeDefault) {
if (mAdbEnabled) {
function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 118cd55..8146fca 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -51,6 +51,8 @@
float mCurrentX, mCurrentY;
float mThumbOffsetX, mThumbOffsetY;
InputChannel mServerChannel, mClientChannel;
+ InputApplicationHandle mDragApplicationHandle;
+ InputWindowHandle mDragWindowHandle;
WindowState mTargetWindow;
ArrayList<WindowState> mNotifiedWindows;
boolean mDragInProgress;
@@ -91,6 +93,38 @@
mService.mInputManager.registerInputChannel(mServerChannel, null);
InputQueue.registerInputChannel(mClientChannel, mService.mDragInputHandler,
mService.mH.getLooper().getQueue());
+
+ mDragApplicationHandle = new InputApplicationHandle(null);
+ mDragApplicationHandle.name = "drag";
+ mDragApplicationHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+
+ mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null);
+ mDragWindowHandle.name = "drag";
+ mDragWindowHandle.inputChannel = mServerChannel;
+ mDragWindowHandle.layer = getDragLayerLw();
+ mDragWindowHandle.layoutParamsFlags = 0;
+ mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
+ mDragWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.visible = true;
+ mDragWindowHandle.canReceiveKeys = false;
+ mDragWindowHandle.hasFocus = true;
+ mDragWindowHandle.hasWallpaper = false;
+ mDragWindowHandle.paused = false;
+ mDragWindowHandle.ownerPid = Process.myPid();
+ mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.inputFeatures = 0;
+ mDragWindowHandle.scaleFactor = 1.0f;
+
+ // The drag window cannot receive new touches.
+ mDragWindowHandle.touchableRegion.setEmpty();
+
+ // The drag window covers the entire display
+ mDragWindowHandle.frameLeft = 0;
+ mDragWindowHandle.frameTop = 0;
+ mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
+ mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
}
}
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 08a3560..12ef238 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -42,10 +42,6 @@
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
- // Fake handles for the drag surface, lazily initialized.
- private InputApplicationHandle mDragApplicationHandle;
- private InputWindowHandle mDragWindowHandle;
-
// Array of window handles to provide to the input dispatcher.
private InputWindowHandle[] mInputWindowHandles;
private int mInputWindowHandleCount;
@@ -121,44 +117,6 @@
return 0; // abort dispatching
}
- private void addDragInputWindowLw() {
- if (mDragWindowHandle == null) {
- mDragApplicationHandle = new InputApplicationHandle(null);
- mDragApplicationHandle.name = "drag";
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
-
- mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null);
- mDragWindowHandle.name = "drag";
- mDragWindowHandle.layoutParamsFlags = 0;
- mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- mDragWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- mDragWindowHandle.visible = true;
- mDragWindowHandle.canReceiveKeys = false;
- mDragWindowHandle.hasFocus = true;
- mDragWindowHandle.hasWallpaper = false;
- mDragWindowHandle.paused = false;
- mDragWindowHandle.ownerPid = Process.myPid();
- mDragWindowHandle.ownerUid = Process.myUid();
- mDragWindowHandle.inputFeatures = 0;
- mDragWindowHandle.scaleFactor = 1.0f;
-
- // The drag window cannot receive new touches.
- mDragWindowHandle.touchableRegion.setEmpty();
- }
-
- mDragWindowHandle.layer = mService.mDragState.getDragLayerLw();
-
- // The drag window covers the entire display
- mDragWindowHandle.frameLeft = 0;
- mDragWindowHandle.frameTop = 0;
- mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
- mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
-
- addInputWindowHandleLw(mDragWindowHandle);
- }
-
private void addInputWindowHandleLw(InputWindowHandle windowHandle) {
if (mInputWindowHandles == null) {
mInputWindowHandles = new InputWindowHandle[16];
@@ -202,7 +160,7 @@
if (WindowManagerService.DEBUG_DRAG) {
Log.d(WindowManagerService.TAG, "Inserting drag window");
}
- addDragInputWindowLw();
+ addInputWindowHandleLw(mService.mDragState.mDragWindowHandle);
}
final int N = windows.size();
@@ -429,4 +387,4 @@
private void updateInputDispatchModeLw() {
mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen);
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index 302a2d6..1234bfd 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -542,6 +542,9 @@
public void setEnabled(boolean enabled) {
mIsEnabled = enabled;
}
+
+ public void setTouchExplorationEnabled(boolean enabled) {
+ }
}
/**
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 8427d14..f0d2fba 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -857,22 +857,28 @@
*/
public static int getLteOnCdmaModeStatic() {
int retVal;
- String productType;
+ int curVal;
+ String productType = "";
- Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
- if (matcher.find()) {
- productType = matcher.group(1);
- if (sLteOnCdmaProductType.equals(productType)) {
- retVal = Phone.LTE_ON_CDMA_TRUE;
+ curVal = SystemProperties.getInt(TelephonyProperties.PROPERTY_LTE_ON_CDMA_DEVICE,
+ Phone.LTE_ON_CDMA_UNKNOWN);
+ retVal = curVal;
+ if (retVal == Phone.LTE_ON_CDMA_UNKNOWN) {
+ Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
+ if (matcher.find()) {
+ productType = matcher.group(1);
+ if (sLteOnCdmaProductType.equals(productType)) {
+ retVal = Phone.LTE_ON_CDMA_TRUE;
+ } else {
+ retVal = Phone.LTE_ON_CDMA_FALSE;
+ }
} else {
retVal = Phone.LTE_ON_CDMA_FALSE;
}
- } else {
- retVal = Phone.LTE_ON_CDMA_FALSE;
- productType = "";
}
- Log.d(LOG_TAG, "getLteOnCdmaMode=" + retVal + " product_type='" + productType +
+ Log.d(LOG_TAG, "getLteOnCdmaMode=" + retVal + " curVal=" + curVal +
+ " product_type='" + productType +
"' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
return retVal;
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 60cf9b7..abb4523 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -79,6 +79,15 @@
*/
static final String PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE = "telephony.lteOnCdmaProductType";
+ /**
+ * The contents of this property is the one of {@link Phone#LTE_ON_CDMA_TRUE} or
+ * {@link Phone#LTE_ON_CDMA_FALSE}. If absent the value will assumed to be false
+ * and the {@see #PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE} will be used to determine its
+ * final value which could also be {@link Phone#LTE_ON_CDMA_FALSE}.
+ * {@see BaseCommands#getLteOnCdmaMode()}
+ */
+ static final String PROPERTY_LTE_ON_CDMA_DEVICE = "telephony.lteOnCdmaDevice";
+
static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
//****** SIM Card
diff --git a/tests/BiDiTests/res/layout/canvas2.xml b/tests/BiDiTests/res/layout/canvas2.xml
new file mode 100644
index 0000000..b3e038f
--- /dev/null
+++ b/tests/BiDiTests/res/layout/canvas2.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/canvas2"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <LinearLayout
+ xmlns:local="http://schemas.android.com/apk/res/com.android.bidi"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:text="@string/ltr"
+ android:textSize="40dip"
+ android:gravity="center"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <com.android.bidi.BiDiTestViewDrawText
+ local:text="@string/ltr"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp" />
+
+ <TextView
+ android:text="@string/rtl"
+ android:textSize="40dip"
+ android:gravity="center"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <com.android.bidi.BiDiTestViewDrawText
+ local:text="@string/rtl"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp" />
+
+ <TextView
+ android:text="@string/composing"
+ android:textSize="40dip"
+ android:gravity="center"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <com.android.bidi.BiDiTestViewDrawText
+ local:text="@string/composing"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp" />
+
+ </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/values/attrs.xml b/tests/BiDiTests/res/values/attrs.xml
new file mode 100644
index 0000000..7f8a1d8
--- /dev/null
+++ b/tests/BiDiTests/res/values/attrs.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <declare-styleable name="DrawTextTestView">
+ <attr name="size" format="dimension" />
+ <attr name="color" format="color" />
+ <attr name="text" format="string" />
+ </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index bc99e79..1f6be7f 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -42,5 +42,8 @@
<string name="textview_hebrew_text">םמab?!</string>
<string name="textview_latin_text">abםמ?!</string>
<string name="textview_multiline_text">םמ?!\nab?!\n?!</string>
+ <string name="ltr">Left to right text"</string>
+ <string name="rtl">"والحق أن تترك ونص"</string>
+ <string name="composing">"\u0644\u0627"</string>
</resources>
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 7002c41..6b38cc1 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -102,6 +102,7 @@
addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas);
+ addItem(result, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2);
addItem(result, "Linear LTR", BiDiTestLinearLayoutLtr.class, R.id.linear_layout_ltr);
addItem(result, "Linear RTL", BiDiTestLinearLayoutRtl.class, R.id.linear_layout_rtl);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas2.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas2.java
new file mode 100644
index 0000000..b801f0e
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas2.java
@@ -0,0 +1,36 @@
+/*
+ * 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 com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+
+import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
+import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
+
+public class BiDiTestCanvas2 extends Fragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.canvas2, container, false);
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index 4f17e52..0126dea 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -21,7 +21,7 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.Typeface;
+import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -37,7 +37,6 @@
private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
- private Paint paint = new Paint();
private Rect rect = new Rect();
private String NORMAL_TEXT;
@@ -51,8 +50,7 @@
private String CHINESE_TEXT;
private String MIXED_TEXT_1;
private String HEBREW_TEXT;
-
- private Typeface typeface;
+ private String RTL_TEXT;
private int currentTextSize;
@@ -83,9 +81,7 @@
CHINESE_TEXT = context.getString(R.string.chinese_text);
MIXED_TEXT_1 = context.getString(R.string.mixed_text_1);
HEBREW_TEXT = context.getString(R.string.hebrew_text);
-
- typeface = paint.getTypeface();
- paint.setAntiAlias(true);
+ RTL_TEXT = context.getString(R.string.rtl);
}
public void setCurrentTextSize(int size) {
@@ -95,54 +91,56 @@
@Override
public void onDraw(Canvas canvas) {
- drawInsideRect(canvas, Color.BLACK);
+ drawInsideRect(canvas, new Paint(), Color.BLACK);
int deltaX = 0;
deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
- paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+ false, false, Paint.DIRECTION_LTR, currentTextSize);
deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
- paint, typeface, true, false, Paint.DIRECTION_LTR, currentTextSize);
+ true, false, Paint.DIRECTION_LTR, currentTextSize);
deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
- paint, typeface, false, true, Paint.DIRECTION_LTR, currentTextSize);
+ false, true, Paint.DIRECTION_LTR, currentTextSize);
deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
- paint, typeface, true, true, Paint.DIRECTION_LTR, currentTextSize);
+ true, true, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+ false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+ false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test with a long string
deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+ false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Arabic ligature
deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_RTL, currentTextSize);
+ false, false, Paint.DIRECTION_RTL, currentTextSize);
// Test Chinese
deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+ false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Mixed (English and Arabic)
deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+ false, false, Paint.DIRECTION_LTR, currentTextSize);
// Test Hebrew
- deltaX = testString(canvas, HEBREW_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize,
- paint, typeface, false, false, Paint.DIRECTION_RTL, currentTextSize);
+ deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize,
+ false, false, Paint.DIRECTION_RTL, currentTextSize);
}
- private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
+ private int testString(Canvas canvas, String text, int x, int y,
boolean isItalic, boolean isBold, int dir, int textSize) {
- paint.setTypeface(typeface);
+
+ TextPaint paint = new TextPaint();
+ paint.setAntiAlias(true);
// Set paint properties
boolean oldFakeBold = paint.isFakeBoldText();
@@ -153,9 +151,9 @@
paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
}
- Log.v(TAG, "START -- drawTextWithCanvasDrawText");
- drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE, dir);
- Log.v(TAG, "END -- drawTextWithCanvasDrawText");
+ paint.setTextSize(textSize);
+ paint.setColor(Color.WHITE);
+ canvas.drawText(text, x, y, paint);
int length = text.length();
float[] advances = new float[length];
@@ -167,17 +165,6 @@
logAdvances(text, textWidthHB, textWidthICU, advances);
drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
- paint.setColor(Color.WHITE);
-// char[] glyphs = new char[2*length];
-// int count = getGlyphs(text, glyphs, dir);
-//
-// logGlypths(glyphs, count);
-// drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
-
- Log.v(TAG, "START -- drawTextWithGlyphs");
- drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir);
- Log.v(TAG, "END -- drawTextWithGlyphs");
-
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
paint.setTextSkewX(oldTextSkewX);
@@ -190,27 +177,7 @@
paint.setBidiFlags(dir);
}
- private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
- canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
- }
-
- private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) {
- setPaintDir(paint, dir);
- canvas.drawTextWithGlyphs(text, x, y, paint);
- }
-
- private void logGlypths(char[] glyphs, int count) {
- Log.v(TAG, "GlyphIds - count=" + count);
- for (int n = 0; n < count; n++) {
- Log.v(TAG, "GlyphIds - Id[" + n + "]="+ (int)glyphs[n]);
- }
- }
-
- private int getGlyphs(String text, char[] glyphs, int dir) {
- return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
- }
-
- private void drawInsideRect(Canvas canvas, int color) {
+ private void drawInsideRect(Canvas canvas, Paint paint, int color) {
paint.setColor(color);
int width = getWidth();
int height = getHeight();
@@ -218,16 +185,9 @@
canvas.drawRect(rect, paint);
}
- private void drawTextWithCanvasDrawText(String text, Canvas canvas,
- float x, float y, float textSize, int color, int dir) {
- setPaintDir(paint, dir);
- paint.setColor(color);
- paint.setTextSize(textSize);
- canvas.drawText(text, x, y, paint);
- }
-
private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
float textWidthICU, int textSize, int color, int colorICU) {
+ Paint paint = new Paint();
paint.setColor(color);
canvas.drawLine(x, y - textSize, x, y + 8, paint);
canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestViewDrawText.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestViewDrawText.java
new file mode 100644
index 0000000..dfdb807
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestViewDrawText.java
@@ -0,0 +1,66 @@
+/*
+ * 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 com.android.bidi;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint.Align;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class BiDiTestViewDrawText extends View {
+ private float mSize;
+ private int mColor;
+ private String mText;
+
+ public BiDiTestViewDrawText(Context context) {
+ this(context, null);
+ }
+
+ public BiDiTestViewDrawText(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BiDiTestViewDrawText(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.DrawTextTestView, defStyle, 0);
+ mSize = a.getDimension(R.styleable.DrawTextTestView_size, 40.0f);
+ mColor = a.getColor(R.styleable.DrawTextTestView_color, Color.YELLOW);
+ final CharSequence text = a.getText(R.styleable.DrawTextTestView_text);
+ mText = (text != null) ? text.toString() : "(empty)";
+ a.recycle();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ final int width = getWidth();
+ final int height = getHeight();
+
+ final TextPaint paint = new TextPaint();
+ paint.setTextSize(mSize);
+ paint.setColor(mColor);
+ paint.setTextAlign(Align.CENTER);
+
+ canvas.drawText(mText, width / 2, height * 2 / 3, paint);
+ }
+}
\ No newline at end of file
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index af5006f..38a85a3 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -95,9 +95,7 @@
}
{
Space v = new Space(context);
- {
- vg.addView(v, new LayoutParams(row5, col3));
- }
+ vg.addView(v, new LayoutParams(row5, col3));
}
{
Button v = new Button(context);
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 32a6a65..9fcd05a 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -94,6 +94,15 @@
</activity>
<activity
+ android:name="CanvasTextureViewActivity"
+ android:label="_CanvasTextureView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="GLTextureViewActivity"
android:label="_TextureViewGL">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
new file mode 100644
index 0000000..81c22b8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
@@ -0,0 +1,120 @@
+/*
+ * 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 com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class CanvasTextureViewActivity extends Activity
+ implements TextureView.SurfaceTextureListener {
+ private TextureView mTextureView;
+ private CanvasTextureViewActivity.RenderingThread mThread;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout content = new FrameLayout(this);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+ mTextureView.setOpaque(false);
+
+ content.addView(mTextureView, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER));
+ setContentView(content);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ mThread = new RenderingThread(mTextureView);
+ mThread.start();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ // Ignored
+ }
+
+ @Override
+ public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ if (mThread != null) mThread.stopRendering();
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ // Ignored
+ }
+
+ private static class RenderingThread extends Thread {
+ private final TextureView mSurface;
+ private volatile boolean mRunning = true;
+
+ public RenderingThread(TextureView surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ public void run() {
+ float x = 0.0f;
+ float y = 0.0f;
+ float speedX = 5.0f;
+ float speedY = 3.0f;
+
+ Paint paint = new Paint();
+ paint.setColor(0xff00ff00);
+
+ while (mRunning && !Thread.interrupted()) {
+ final Canvas canvas = mSurface.lockCanvas(null);
+ try {
+ canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
+ canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint);
+ } finally {
+ mSurface.unlockCanvasAndPost(canvas);
+ }
+
+ if (x + 20.0f + speedX >= mSurface.getWidth() || x + speedX <= 0.0f) {
+ speedX = -speedX;
+ }
+ if (y + 20.0f + speedY >= mSurface.getHeight() || y + speedY <= 0.0f) {
+ speedY = -speedY;
+ }
+
+ x += speedX;
+ y += speedY;
+
+ try {
+ Thread.sleep(15);
+ } catch (InterruptedException e) {
+ // Interrupted
+ }
+ }
+ }
+
+ void stopRendering() {
+ interrupt();
+ mRunning = false;
+ }
+ }
+}