Merge "Add C code to use BDADDR_ANY macro properly. The macro expands into code that is not valid C++. So we need to use a C helper."
diff --git a/api/current.txt b/api/current.txt
index d85873d..e4a1bc6 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();
@@ -13927,6 +13929,10 @@
public static class Debug.MemoryInfo implements android.os.Parcelable {
ctor public Debug.MemoryInfo();
method public int describeContents();
+ method public static java.lang.String getOtherLabel(int);
+ method public int getOtherPrivateDirty(int);
+ method public int getOtherPss(int);
+ method public int getOtherSharedDirty(int);
method public int getTotalPrivateDirty();
method public int getTotalPss();
method public int getTotalSharedDirty();
@@ -16698,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";
@@ -20488,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);
}
@@ -20727,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);
@@ -20746,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);
@@ -20762,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);
@@ -22030,9 +22048,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 {
@@ -23261,6 +23282,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);
}
@@ -23297,6 +23319,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 ef4adca..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() {
@@ -193,8 +198,6 @@
mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
mResolveInfo = resolveInfo;
- String settingsActivityName = null;
- boolean retrieveScreenContent = false;
XmlResourceParser parser = null;
try {
@@ -242,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: "
@@ -315,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() {
@@ -331,6 +348,7 @@
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+ parcel.writeString(mDescription);
}
private void initFromParcel(Parcel parcel) {
@@ -343,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 8994b17..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;
@@ -413,10 +413,10 @@
native private void dumpGraphicsInfo(FileDescriptor fd);
private final class ApplicationThread extends ApplicationThreadNative {
- private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
- private static final String ONE_COUNT_COLUMN = "%17s %8d";
- private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
- private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d";
+ private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
+ private static final String ONE_COUNT_COLUMN = "%21s %8d";
+ private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
+ private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
// Formatting for checkin service - update version if row format changes
@@ -729,12 +729,17 @@
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args != null && args.length == 1 && args[0].equals("graphics")) {
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) {
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new PrintWriter(fout);
+ try {
+ return dumpMemInfo(fd, pw, args);
+ } finally {
pw.flush();
- dumpGraphicsInfo(fd);
- return;
}
+ }
+
+ private Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, PrintWriter pw, String[] args) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -742,14 +747,6 @@
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
- final int nativeShared = memInfo.nativeSharedDirty;
- final int dalvikShared = memInfo.dalvikSharedDirty;
- final int otherShared = memInfo.otherSharedDirty;
-
- final int nativePrivate = memInfo.nativePrivateDirty;
- final int dalvikPrivate = memInfo.dalvikPrivateDirty;
- final int otherPrivate = memInfo.otherPrivateDirty;
-
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.totalMemory() / 1024;
@@ -813,16 +810,18 @@
pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
// Heap info - shared
- pw.print(nativeShared); pw.print(',');
- pw.print(dalvikShared); pw.print(',');
- pw.print(otherShared); pw.print(',');
- pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
+ pw.print(memInfo.nativeSharedDirty); pw.print(',');
+ pw.print(memInfo.dalvikSharedDirty); pw.print(',');
+ pw.print(memInfo.otherSharedDirty); pw.print(',');
+ pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
+ + memInfo.otherSharedDirty); pw.print(',');
// Heap info - private
- pw.print(nativePrivate); pw.print(',');
- pw.print(dalvikPrivate); pw.print(',');
- pw.print(otherPrivate); pw.print(',');
- pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
+ pw.print(memInfo.nativePrivateDirty); pw.print(',');
+ pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
+ pw.print(memInfo.otherPrivateDirty); pw.print(',');
+ pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
+ + memInfo.otherPrivateDirty); pw.print(',');
// Object counts
pw.print(viewInstanceCount); pw.print(',');
@@ -850,24 +849,38 @@
pw.print(',');
}
- return;
+ return memInfo;
}
// otherwise, show human-readable format
- printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
- printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
- printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
- nativeAllocated + dalvikAllocated);
- printRow(pw, HEAP_COLUMN, "free:", nativeFree, dalvikFree, "N/A",
- nativeFree + dalvikFree);
+ printRow(pw, HEAP_COLUMN, "", "", "Shared", "Private", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_COLUMN, "", "Pss", "Dirty", "Dirty", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
+ "------");
+ printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSharedDirty,
+ memInfo.nativePrivateDirty, nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSharedDirty,
+ memInfo.dalvikPrivateDirty, dalvikMax, dalvikAllocated, dalvikFree);
- printRow(pw, HEAP_COLUMN, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
- memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
+ int otherPss = memInfo.otherPss;
+ int otherSharedDirty = memInfo.otherSharedDirty;
+ int otherPrivateDirty = memInfo.otherPrivateDirty;
- printRow(pw, HEAP_COLUMN, "(shared dirty):", nativeShared, dalvikShared, otherShared,
- nativeShared + dalvikShared + otherShared);
- printRow(pw, HEAP_COLUMN, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
- nativePrivate + dalvikPrivate + otherPrivate);
+ for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+ printRow(pw, HEAP_COLUMN, memInfo.getOtherLabel(i),
+ memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
+ memInfo.getOtherPrivateDirty(i), "", "", "");
+ otherPss -= memInfo.getOtherPss(i);
+ otherSharedDirty -= memInfo.getOtherSharedDirty(i);
+ otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
+ }
+
+ printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSharedDirty,
+ otherPrivateDirty, "", "", "");
+ printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+ nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
+ nativeFree+dalvikFree);
pw.println(" ");
pw.println(" Objects");
@@ -916,6 +929,13 @@
pw.println(" Asset Allocations");
pw.print(assetAlloc);
}
+
+ return memInfo;
+ }
+
+ @Override
+ public void dumpGfxInfo(FileDescriptor fd, String[] args) {
+ dumpGraphicsInfo(fd);
}
private void printRow(PrintWriter pw, String format, Object...objs) {
@@ -3538,6 +3558,7 @@
}
final void handleTrimMemory(int level) {
+ WindowManagerImpl.getDefault().trimMemory(level);
}
private final void handleBindApplication(AppBindData data) {
@@ -4051,7 +4072,7 @@
sThreadLocal.set(this);
mSystemThread = system;
if (!system) {
- ViewAncestor.addFirstDrawHandler(new Runnable() {
+ ViewRootImpl.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
@@ -4081,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/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 16181e0..942f245 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -485,6 +485,48 @@
scheduleTrimMemory(level);
return true;
}
+
+ case DUMP_MEM_INFO_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ String[] args = data.readStringArray();
+ Debug.MemoryInfo mi = null;
+ if (fd != null) {
+ try {
+ mi = dumpMemInfo(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // swallowed, not propagated back to the caller
+ }
+ }
+ }
+ reply.writeNoException();
+ mi.writeToParcel(reply, 0);
+ return true;
+ }
+
+ case DUMP_GFX_INFO_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ String[] args = data.readStringArray();
+ if (fd != null) {
+ try {
+ dumpGfxInfo(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // swallowed, not propagated back to the caller
+ }
+ }
+ }
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1004,4 +1046,28 @@
mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
}
+
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Debug.MemoryInfo info = new Debug.MemoryInfo();
+ info.readFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ return info;
+ }
+
+ public void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ mRemote.transact(DUMP_GFX_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 285f1c1..c82c9ec 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1307,6 +1307,7 @@
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
+ mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 94c2c86..9de0bf4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -120,6 +120,8 @@
void setCoreSettings(Bundle coreSettings) throws RemoteException;
void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
void scheduleTrimMemory(int level) throws RemoteException;
+ Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException;
+ void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -164,4 +166,6 @@
int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
int SCHEDULE_TRIM_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
+ int DUMP_MEM_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
+ int DUMP_GFX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
}
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/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/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index ccef122..aa6400bb 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -19,6 +19,7 @@
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import android.content.Context;
+import android.os.Build;
import android.telephony.TelephonyManager;
import com.android.internal.util.Objects;
@@ -68,7 +69,7 @@
subTypeName = Integer.toString(mSubType);
}
- final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+ final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
final String roaming = mRoaming ? ", ROAMING" : "";
return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId="
+ scrubSubscriberId + roaming + "]";
@@ -91,6 +92,17 @@
}
/**
+ * Scrub given IMSI on production builds.
+ */
+ public static String scrubSubscriberId(String subscriberId) {
+ if ("eng".equals(Build.TYPE)) {
+ return subscriberId;
+ } else {
+ return subscriberId != null ? "valid" : "null";
+ }
+ }
+
+ /**
* Build a {@link NetworkIdentity} from the given {@link NetworkState},
* assuming that any mobile networks are using the current IMSI.
*/
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 1ef0d9d..cd49023 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -16,10 +16,11 @@
package android.net;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkIdentity.scrubSubscriberId;
import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
@@ -119,7 +120,7 @@
@Override
public String toString() {
- final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+ final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId="
+ scrubSubscriberId;
}
@@ -150,7 +151,7 @@
}
/**
- * Test if this network matches the given template and IMEI.
+ * Test if this network matches the given template and IMSI.
*/
public boolean matches(NetworkIdentity ident) {
switch (mMatchRule) {
@@ -170,7 +171,7 @@
}
/**
- * Check if mobile network with matching IMEI. Also matches
+ * Check if mobile network with matching IMSI. Also matches
* {@link #TYPE_WIMAX}.
*/
private boolean matchesMobile(NetworkIdentity ident) {
@@ -183,7 +184,7 @@
}
/**
- * Check if mobile network classified 3G or lower with matching IMEI.
+ * Check if mobile network classified 3G or lower with matching IMSI.
*/
private boolean matchesMobile3gLower(NetworkIdentity ident) {
if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
@@ -198,7 +199,7 @@
}
/**
- * Check if mobile network classified 4G with matching IMEI. Also matches
+ * Check if mobile network classified 4G with matching IMSI. Also matches
* {@link #TYPE_WIMAX}.
*/
private boolean matchesMobile4g(NetworkIdentity ident) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ba69246..da2afb6 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -129,6 +129,11 @@
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
+ /** @hide */
+ public static final int NUM_OTHER_STATS = 9;
+
+ private int[] otherStats = new int[NUM_OTHER_STATS*3];
+
public MemoryInfo() {
}
@@ -153,6 +158,38 @@
return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
}
+ /* @hide */
+ public int getOtherPss(int which) {
+ return otherStats[which*3];
+ }
+
+ /* @hide */
+ public int getOtherPrivateDirty(int which) {
+ return otherStats[which*3 + 1];
+ }
+
+ /* @hide */
+ public int getOtherSharedDirty(int which) {
+ return otherStats[which*3 + 2];
+ }
+
+
+ /* @hide */
+ public static String getOtherLabel(int which) {
+ switch (which) {
+ case 0: return "Cursor";
+ case 1: return "Ashmem";
+ case 2: return "Other dev";
+ case 3: return ".so mmap";
+ case 4: return ".jar mmap";
+ case 5: return ".apk mmap";
+ case 6: return ".ttf mmap";
+ case 7: return ".dex mmap";
+ case 8: return "Other mmap";
+ default: return "????";
+ }
+ }
+
public int describeContents() {
return 0;
}
@@ -167,6 +204,7 @@
dest.writeInt(otherPss);
dest.writeInt(otherPrivateDirty);
dest.writeInt(otherSharedDirty);
+ dest.writeIntArray(otherStats);
}
public void readFromParcel(Parcel source) {
@@ -179,6 +217,7 @@
otherPss = source.readInt();
otherPrivateDirty = source.readInt();
otherSharedDirty = source.readInt();
+ otherStats = source.createIntArray();
}
public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
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/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/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index f4d5e89..210106f 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -50,7 +50,7 @@
*/
public class AccessibilityRecord {
- private static final int INVALID_POSITION = -1;
+ private static final int UNDEFINED = -1;
private static final int PROPERTY_CHECKED = 0x00000001;
private static final int PROPERTY_ENABLED = 0x00000002;
@@ -68,15 +68,15 @@
boolean mSealed;
int mBooleanProperties;
- int mCurrentItemIndex;
- int mItemCount;
- int mFromIndex;
- int mToIndex;
- int mScrollX;
- int mScrollY;
+ int mCurrentItemIndex = UNDEFINED;
+ int mItemCount = UNDEFINED;
+ int mFromIndex = UNDEFINED;
+ int mToIndex = UNDEFINED;
+ int mScrollX = UNDEFINED;
+ int mScrollY = UNDEFINED;
- int mAddedCount;
- int mRemovedCount;
+ int mAddedCount= UNDEFINED;
+ int mRemovedCount = UNDEFINED;
int mSourceViewId = View.NO_ID;
int mSourceWindowId = View.NO_ID;
@@ -681,14 +681,14 @@
void clear() {
mSealed = false;
mBooleanProperties = 0;
- mCurrentItemIndex = INVALID_POSITION;
- mItemCount = 0;
- mFromIndex = 0;
- mToIndex = 0;
- mScrollX = 0;
- mScrollY = 0;
- mAddedCount = 0;
- mRemovedCount = 0;
+ mCurrentItemIndex = UNDEFINED;
+ mItemCount = UNDEFINED;
+ mFromIndex = UNDEFINED;
+ mToIndex = UNDEFINED;
+ mScrollX = UNDEFINED;
+ mScrollY = UNDEFINED;
+ mAddedCount = UNDEFINED;
+ mRemovedCount = UNDEFINED;
mClassName = null;
mContentDescription = null;
mBeforeText = null;
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 a1a7281..e5f3fc9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -42,7 +42,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;
@@ -655,7 +655,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));
}
}
@@ -1112,9 +1112,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/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 2410eb2..d3cdad8 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -217,6 +217,7 @@
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
+ info.setCheckable(true);
info.setChecked(mChecked);
}
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/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/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/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 6bb40a4..678751c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -370,6 +370,19 @@
mMenuView = menuView;
}
+ public boolean hasExpandedActionView() {
+ return mExpandedMenuPresenter != null &&
+ mExpandedMenuPresenter.mCurrentExpandedItem != null;
+ }
+
+ public void collapseActionView() {
+ final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
+ mExpandedMenuPresenter.mCurrentExpandedItem;
+ if (item != null) {
+ item.collapseActionView();
+ }
+ }
+
public void setCustomNavigationView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
if (mCustomNavView != null && showCustom) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d034eab..bbddf29 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -114,6 +114,23 @@
private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false);
private static FileObserver sPasswordObserver;
+ private static class PasswordFileObserver extends FileObserver {
+ public PasswordFileObserver(String path, int mask) {
+ super(path, mask);
+ }
+
+ @Override
+ public void onEvent(int event, String path) {
+ if (LOCK_PATTERN_FILE.equals(path)) {
+ Log.d(TAG, "lock pattern file changed");
+ sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
+ } else if (LOCK_PASSWORD_FILE.equals(path)) {
+ Log.d(TAG, "lock password file changed");
+ sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
+ }
+ }
+ }
+
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
mDevicePolicyManager =
@@ -143,18 +160,7 @@
sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
FileObserver.MOVED_TO | FileObserver.CREATE;
- sPasswordObserver = new FileObserver(dataSystemDirectory, fileObserverMask) {
- @Override
- public void onEvent(int event, String path) {
- if (LOCK_PATTERN_FILE.equals(path)) {
- Log.d(TAG, "lock pattern file changed");
- sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
- } else if (LOCK_PASSWORD_FILE.equals(path)) {
- Log.d(TAG, "lock password file changed");
- sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
- }
- }
- };
+ sPasswordObserver = new PasswordFileObserver(dataSystemDirectory, fileObserverMask);
sPasswordObserver.startWatching();
}
}
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/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 08431cd..6ab8fe3 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -627,15 +627,6 @@
"-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
mOptions.add(opt);
- char enableDPBuf[sizeof("-Xdeadlockpredict:") + PROPERTY_VALUE_MAX];
- property_get("dalvik.vm.deadlock-predict", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(enableDPBuf, "-Xdeadlockpredict:");
- strcat(enableDPBuf, propBuf);
- opt.optionString = enableDPBuf;
- mOptions.add(opt);
- }
-
LOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
/* extended JNI checking */
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_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index a4432c3..3a3f07e 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <errno.h>
#include <assert.h>
+#include <ctype.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
@@ -35,28 +36,50 @@
namespace android
{
-static jfieldID dalvikPss_field;
-static jfieldID dalvikPrivateDirty_field;
-static jfieldID dalvikSharedDirty_field;
-static jfieldID nativePss_field;
-static jfieldID nativePrivateDirty_field;
-static jfieldID nativeSharedDirty_field;
-static jfieldID otherPss_field;
-static jfieldID otherPrivateDirty_field;
-static jfieldID otherSharedDirty_field;
+enum {
+ HEAP_UNKNOWN,
+ HEAP_DALVIK,
+ HEAP_NATIVE,
+ HEAP_CURSOR,
+ HEAP_ASHMEM,
+ HEAP_UNKNOWN_DEV,
+ HEAP_SO,
+ HEAP_JAR,
+ HEAP_APK,
+ HEAP_TTF,
+ HEAP_DEX,
+ HEAP_UNKNOWN_MAP,
+
+ _NUM_HEAP,
+ _NUM_CORE_HEAP = HEAP_NATIVE+1
+};
+
+struct stat_fields {
+ jfieldID pss_field;
+ jfieldID privateDirty_field;
+ jfieldID sharedDirty_field;
+};
+
+struct stat_field_names {
+ const char* pss_name;
+ const char* privateDirty_name;
+ const char* sharedDirty_name;
+};
+
+static stat_fields stat_fields[_NUM_CORE_HEAP];
+
+static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
+ { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
+ { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
+ { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
+};
+
+jfieldID otherStats_field;
struct stats_t {
- int dalvikPss;
- int dalvikPrivateDirty;
- int dalvikSharedDirty;
-
- int nativePss;
- int nativePrivateDirty;
- int nativeSharedDirty;
-
- int otherPss;
- int otherPrivateDirty;
- int otherSharedDirty;
+ int pss;
+ int privateDirty;
+ int sharedDirty;
};
#define BINDER_STATS "/proc/binder/stats"
@@ -94,48 +117,71 @@
static void read_mapinfo(FILE *fp, stats_t* stats)
{
char line[1024];
- int len;
+ int len, nameLen;
bool skip, done = false;
- unsigned start = 0, size = 0, resident = 0, pss = 0;
+ unsigned size = 0, resident = 0, pss = 0;
unsigned shared_clean = 0, shared_dirty = 0;
unsigned private_clean = 0, private_dirty = 0;
unsigned referenced = 0;
unsigned temp;
- int isNativeHeap;
- int isDalvikHeap;
- int isSqliteHeap;
+ unsigned long int start;
+ unsigned long int end = 0;
+ unsigned long int prevEnd = 0;
+ char* name;
+ int name_pos;
- if(fgets(line, 1024, fp) == 0) return;
+ int whichHeap = HEAP_UNKNOWN;
+ int prevHeap = HEAP_UNKNOWN;
+
+ if(fgets(line, sizeof(line), fp) == 0) return;
while (!done) {
- isNativeHeap = 0;
- isDalvikHeap = 0;
- isSqliteHeap = 0;
+ prevHeap = whichHeap;
+ prevEnd = end;
+ whichHeap = HEAP_UNKNOWN;
skip = false;
len = strlen(line);
if (len < 1) return;
line[--len] = 0;
- /* ignore guard pages */
- if (len > 18 && line[17] == '-') skip = true;
+ if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+ skip = true;
+ } else {
+ while (isspace(line[name_pos])) {
+ name_pos += 1;
+ }
+ name = line + name_pos;
+ nameLen = strlen(name);
- start = strtoul(line, 0, 16);
-
- if (strstr(line, "[heap]")) {
- isNativeHeap = 1;
- } else if (strstr(line, "/dalvik-LinearAlloc")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/mspace/dalvik-heap")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/dalvik-heap-bitmap/")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/data/dalvik-cache/")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/tmp/sqlite-heap")) {
- isSqliteHeap = 1;
+ if (strstr(name, "[heap]") == name) {
+ whichHeap = HEAP_NATIVE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
+ whichHeap = HEAP_DALVIK;
+ } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
+ whichHeap = HEAP_CURSOR;
+ } else if (strstr(name, "/dev/ashmem/") == name) {
+ whichHeap = HEAP_ASHMEM;
+ } else if (strstr(name, "/dev/") == name) {
+ whichHeap = HEAP_UNKNOWN_DEV;
+ } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
+ whichHeap = HEAP_SO;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
+ whichHeap = HEAP_JAR;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
+ whichHeap = HEAP_APK;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
+ whichHeap = HEAP_TTF;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) {
+ whichHeap = HEAP_DEX;
+ } else if (nameLen > 0) {
+ whichHeap = HEAP_UNKNOWN_MAP;
+ } else if (start == prevEnd && prevHeap == HEAP_SO) {
+ // bss section of a shared library.
+ whichHeap = HEAP_SO;
+ }
}
//LOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
@@ -171,21 +217,9 @@
}
if (!skip) {
- if (isNativeHeap) {
- stats->nativePss += pss;
- stats->nativePrivateDirty += private_dirty;
- stats->nativeSharedDirty += shared_dirty;
- } else if (isDalvikHeap) {
- stats->dalvikPss += pss;
- stats->dalvikPrivateDirty += private_dirty;
- stats->dalvikSharedDirty += shared_dirty;
- } else if ( isSqliteHeap) {
- // ignore
- } else {
- stats->otherPss += pss;
- stats->otherPrivateDirty += private_dirty;
- stats->otherSharedDirty += shared_dirty;
- }
+ stats[whichHeap].pss += pss;
+ stats[whichHeap].privateDirty += private_dirty;
+ stats[whichHeap].sharedDirty += shared_dirty;
}
}
}
@@ -206,22 +240,38 @@
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
- stats_t stats;
- memset(&stats, 0, sizeof(stats_t));
+ stats_t stats[_NUM_HEAP];
+ memset(&stats, 0, sizeof(stats));
- load_maps(pid, &stats);
+ load_maps(pid, stats);
- env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
- env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
- env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty);
+ for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+ stats[HEAP_UNKNOWN].pss += stats[i].pss;
+ stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
+ stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
+ }
+
+ for (int i=0; i<_NUM_CORE_HEAP; i++) {
+ env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
+ env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
+ env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
+ }
- env->SetIntField(object, nativePss_field, stats.nativePss);
- env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty);
- env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty);
+ jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
- env->SetIntField(object, otherPss_field, stats.otherPss);
- env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty);
- env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
+ jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
+ if (otherArray == NULL) {
+ return;
+ }
+
+ int j=0;
+ for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+ otherArray[j++] = stats[i].pss;
+ otherArray[j++] = stats[i].privateDirty;
+ otherArray[j++] = stats[i].sharedDirty;
+ }
+
+ env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
}
static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
@@ -487,19 +537,18 @@
int register_android_os_Debug(JNIEnv *env)
{
jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
-
- dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I");
- dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I");
- dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I");
- nativePss_field = env->GetFieldID(clazz, "nativePss", "I");
- nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I");
- nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I");
-
- otherPss_field = env->GetFieldID(clazz, "otherPss", "I");
- otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I");
- otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I");
-
+ for (int i=0; i<_NUM_CORE_HEAP; i++) {
+ stat_fields[i].pss_field =
+ env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
+ stat_fields[i].privateDirty_field =
+ env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
+ stat_fields[i].sharedDirty_field =
+ env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
+ }
+
+ otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
+
return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
}
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/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/config.xml b/core/res/res/values/config.xml
index 1f2b7fb..215700c 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -665,4 +665,7 @@
<!-- Timeout to wait for NTP server response. -->
<integer name="config_ntpTimeout">20000</integer>
+ <!-- Default network policy warning threshold, in megabytes. -->
+ <integer name="config_networkPolicyDefaultWarning">2048</integer>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index abc56ec..73f636f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -138,4 +138,7 @@
<!-- 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>
+
</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..5b5e7c3 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -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/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 4be00c5..b963b13 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1668,14 +1668,6 @@
}
}
- // Back cancels action modes first.
- if (mActionMode != null && keyCode == KeyEvent.KEYCODE_BACK) {
- if (action == KeyEvent.ACTION_UP) {
- mActionMode.finish();
- }
- return true;
- }
-
if (!isDestroyed()) {
final Callback cb = getCallback();
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
@@ -1684,6 +1676,7 @@
return true;
}
}
+
return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
: PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
@@ -1730,7 +1723,32 @@
}
public boolean superDispatchKeyEvent(KeyEvent event) {
- return super.dispatchKeyEvent(event);
+ if (super.dispatchKeyEvent(event)) {
+ return true;
+ }
+
+ // Not handled by the view hierarchy, does the action bar want it
+ // to cancel out of something special?
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ final int action = event.getAction();
+ // Back cancels action modes first.
+ if (mActionMode != null) {
+ if (action == KeyEvent.ACTION_UP) {
+ mActionMode.finish();
+ }
+ return true;
+ }
+
+ // Next collapse any expanded action views.
+ if (mActionBar != null && mActionBar.hasExpandedActionView()) {
+ if (action == KeyEvent.ACTION_UP) {
+ mActionBar.collapseActionView();
+ }
+ return true;
+ }
+ }
+
+ return false;
}
public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
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/MountService.java b/services/java/com/android/server/MountService.java
index 94465fd..7f61c635 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1339,7 +1339,11 @@
String state = mVolumeStates.get(mountPoint);
if (state == null) {
Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
- throw new IllegalArgumentException();
+ if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
+ state = Environment.MEDIA_REMOVED;
+ } else {
+ throw new IllegalArgumentException();
+ }
}
return state;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index f99951fa..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();
}
}
@@ -935,9 +980,11 @@
}
}
- public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId)
+ throws RemoteException {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
if (!permissionGranted) {
return null;
@@ -975,15 +1022,16 @@
}
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
- String text) {
+ String text) throws RemoteException {
return findAccessibilityNodeInfosByViewText(text,
mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID);
}
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
- int accessibilityWindowId, int accessibilityViewId) {
+ int accessibilityWindowId, int accessibilityViewId) throws RemoteException {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
if (!permissionGranted) {
@@ -1026,9 +1074,10 @@
}
public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
- int accessibilityWindowId, int accessibilityViewId) {
+ int accessibilityWindowId, int accessibilityViewId) throws RemoteException {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
if (!permissionGranted) {
@@ -1199,6 +1248,15 @@
return service.mCanRetrieveScreenContent;
}
+ public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
+ // This happens due to incorrect registration so make it apparent.
+ if (!canRetrieveWindowContent(service)) {
+ Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
+ "declare android:canRetrieveWindowContent.");
+ throw new RemoteException();
+ }
+ }
+
private boolean isRetrievalAllowingWindow(int windowId) {
return (mRetrievalAlowingWindowId == windowId);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f546cf1..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;
}
@@ -8885,25 +8888,59 @@
pw.println("Applications Graphics Acceleration Info:");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
- String callArgs[] = {"graphics"};
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
try {
- TransferPipe.goDump(r.thread.asBinder(), fd, callArgs);
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.thread.dumpGfxInfo(tp.getWriteFd().getFileDescriptor(), args);
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
} catch (IOException e) {
- pw.println("Failure: " + e);
+ pw.println("Failure while dumping the app: " + r);
pw.flush();
} catch (RemoteException e) {
- pw.println("Got RemoteException!");
+ pw.println("Got a RemoteException while dumping the app " + r);
pw.flush();
}
}
}
}
+ final static class MemItem {
+ final String label;
+ final long pss;
+
+ public MemItem(String _label, long _pss) {
+ label = _label;
+ pss = _pss;
+ }
+ }
+
+ final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items) {
+ Collections.sort(items, new Comparator<MemItem>() {
+ @Override
+ public int compare(MemItem lhs, MemItem rhs) {
+ if (lhs.pss < rhs.pss) {
+ return 1;
+ } else if (lhs.pss > rhs.pss) {
+ return -1;
+ }
+ return 0;
+ }
+ });
+
+ for (int i=0; i<items.size(); i++) {
+ MemItem mi = items.get(i);
+ pw.print(prefix); pw.printf("%8d Kb: ", mi.pss); pw.println(mi.label);
+ }
+ }
+
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args) {
ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
@@ -8923,6 +8960,11 @@
pw.println("Applications Memory Usage (kB):");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
}
+
+ ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+ long nativePss=0, dalvikPss=0, otherPss=0;
+ long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
@@ -8930,19 +8972,48 @@
pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
}
+ Debug.MemoryInfo mi = null;
try {
- TransferPipe.goDump(r.thread.asBinder(), fd, args);
- } catch (IOException e) {
- pw.println("Failure: " + e);
- pw.flush();
+ mi = r.thread.dumpMemInfo(fd, args);
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
pw.flush();
}
}
+ if (!isCheckinRequest && mi != null) {
+ procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")",
+ mi.getTotalPss()));
+
+ nativePss += mi.nativePss;
+ dalvikPss += mi.dalvikPss;
+ otherPss += mi.otherPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ }
+ }
}
}
+
+ if (!isCheckinRequest && procs.size() > 1) {
+ ArrayList<MemItem> catMems = new ArrayList<MemItem>();
+
+ catMems.add(new MemItem("Native", nativePss));
+ catMems.add(new MemItem("Dalvik", dalvikPss));
+ catMems.add(new MemItem("Unknown", otherPss));
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
+ }
+
+ pw.println();
+ pw.println("Total PSS by process:");
+ dumpMemItems(pw, " ", procMems);
+ pw.println();
+ pw.println("Total PSS by category:");
+ dumpMemItems(pw, " ", catMems);
+ }
}
/**
@@ -9142,6 +9213,7 @@
app.notResponding = false;
app.resetPackageList();
+ app.unlinkDeathRecipient();
app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
@@ -9259,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/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 0c78fe7..435c394 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -22,6 +22,7 @@
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED;
@@ -174,10 +175,12 @@
/** Current policy for network templates. */
private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
+ /** Current derived network rules for ifaces. */
+ private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
/** Current policy for each UID. */
private SparseIntArray mUidPolicy = new SparseIntArray();
- /** Current derived network rules for each UID. */
+ /** Current derived rules for each UID. */
private SparseIntArray mUidRules = new SparseIntArray();
/** Set of ifaces that are metered. */
@@ -199,8 +202,6 @@
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
- // TODO: watch for package added broadcast to catch new UIDs.
-
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats,
INetworkManagementService networkManagement) {
@@ -242,7 +243,6 @@
synchronized (mRulesLock) {
// read policy from disk
readPolicyLocked();
- updateNotificationsLocked();
}
updateScreenOn();
@@ -268,9 +268,12 @@
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
- // listen for uid removal to clean policy
- final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
- mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+ // listen for package/uid changes to update policy
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(ACTION_UID_REMOVED);
+ packageFilter.addDataScheme("package");
+ mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
// listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
@@ -331,17 +334,28 @@
}
};
- private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // on background handler thread, and UID_REMOVED is protected
- // broadcast.
+ // on background handler thread, and PACKAGE_ADDED and UID_REMOVED
+ // are protected broadcasts.
+
+ final String action = intent.getAction();
final int uid = intent.getIntExtra(EXTRA_UID, 0);
synchronized (mRulesLock) {
- // remove any policy and update rules to clean up
- mUidPolicy.delete(uid);
- updateRulesForUidLocked(uid);
- writePolicyLocked();
+ if (ACTION_PACKAGE_ADDED.equals(action)) {
+ // update rules for UID, since it might be subject to
+ // global background data policy.
+ if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
+ updateRulesForUidLocked(uid);
+
+ } else if (ACTION_UID_REMOVED.equals(action)) {
+ // remove any policy and update rules to clean up.
+ if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
+ mUidPolicy.delete(uid);
+ updateRulesForUidLocked(uid);
+ writePolicyLocked();
+ }
}
}
};
@@ -396,8 +410,8 @@
// TODO: when switching to kernel notifications, compute next future
// cycle boundary to recompute notifications.
- // examine stats for each policy defined
- for (NetworkPolicy policy : mNetworkPolicy) {
+ // examine stats for each active policy
+ for (NetworkPolicy policy : mNetworkRules.keySet()) {
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
@@ -424,6 +438,15 @@
cancelNotification(policy, TYPE_WARNING);
}
}
+
+ }
+
+ // clear notifications for non-active policies
+ for (NetworkPolicy policy : mNetworkPolicy) {
+ if (!mNetworkRules.containsKey(policy)) {
+ cancelNotification(policy, TYPE_WARNING);
+ cancelNotification(policy, TYPE_LIMIT);
+ }
}
}
@@ -531,7 +554,8 @@
// permission above.
synchronized (mRulesLock) {
ensureActiveMobilePolicyLocked();
- updateIfacesLocked();
+ updateNetworkRulesLocked();
+ updateNotificationsLocked();
}
}
};
@@ -541,7 +565,7 @@
* {@link NetworkPolicy} that need to be enforced. When matches found, set
* remaining quota based on usage cycle and historical stats.
*/
- private void updateIfacesLocked() {
+ private void updateNetworkRulesLocked() {
if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
final NetworkState[] states;
@@ -565,7 +589,7 @@
}
// build list of rules and ifaces to enforce them against
- final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
+ mNetworkRules.clear();
final ArrayList<String> ifaceList = Lists.newArrayList();
for (NetworkPolicy policy : mNetworkPolicy) {
@@ -580,7 +604,7 @@
if (ifaceList.size() > 0) {
final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
- rules.put(policy, ifaces);
+ mNetworkRules.put(policy, ifaces);
}
}
@@ -596,8 +620,8 @@
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
- for (NetworkPolicy policy : rules.keySet()) {
- final String[] ifaces = rules.get(policy);
+ for (NetworkPolicy policy : mNetworkRules.keySet()) {
+ final String[] ifaces = mNetworkRules.get(policy);
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
@@ -670,17 +694,17 @@
if (!mobileDefined) {
Slog.i(TAG, "no policy for active mobile network; generating default policy");
- // default mobile policy has combined 4GB warning, and assume usage
- // cycle starts today today.
+ // build default mobile policy, and assume usage cycle starts today
+ final long warningBytes = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_networkPolicyDefaultWarning)
+ * MB_IN_BYTES;
- // TODO: move this policy definition to overlay or secure setting
final Time time = new Time(Time.TIMEZONE_UTC);
time.setToNow();
final int cycleDay = time.monthDay;
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
- mNetworkPolicy.add(
- new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
+ mNetworkPolicy.add(new NetworkPolicy(template, cycleDay, warningBytes, LIMIT_DISABLED));
writePolicyLocked();
}
}
@@ -859,7 +883,7 @@
mNetworkPolicy.add(policy);
}
- updateIfacesLocked();
+ updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 7ec6b81..6cc01f4 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -60,6 +60,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
@@ -112,6 +113,8 @@
private final TrustedTime mTime;
private final NetworkStatsSettings mSettings;
+ private final PowerManager.WakeLock mWakeLock;
+
private IConnectivityManager mConnManager;
// @VisibleForTesting
@@ -191,6 +194,10 @@
mTime = checkNotNull(time, "missing TrustedTime");
mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
+ final PowerManager powerManager = (PowerManager) context.getSystemService(
+ Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
@@ -408,7 +415,12 @@
// on background handler thread, and verified CONNECTIVITY_INTERNAL
// permission above.
synchronized (mStatsLock) {
- updateIfacesLocked();
+ mWakeLock.acquire();
+ try {
+ updateIfacesLocked();
+ } finally {
+ mWakeLock.release();
+ }
}
}
};
@@ -419,8 +431,12 @@
// on background handler thread, and verified UPDATE_DEVICE_STATS
// permission above.
synchronized (mStatsLock) {
- // TODO: acquire wakelock while performing poll
- performPollLocked(true, false);
+ mWakeLock.acquire();
+ try {
+ performPollLocked(true, false);
+ } finally {
+ mWakeLock.release();
+ }
}
}
};
@@ -433,7 +449,12 @@
final int uid = intent.getIntExtra(EXTRA_UID, 0);
synchronized (mStatsLock) {
// TODO: perform one last stats poll for UID
- removeUidLocked(uid);
+ mWakeLock.acquire();
+ try {
+ removeUidLocked(uid);
+ } finally {
+ mWakeLock.release();
+ }
}
}
};
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/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/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66120a1..f7e0c66 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -61,7 +61,7 @@
/** @hide */
public TelephonyManager(Context context) {
if (sContext == null) {
- sContext = context;
+ sContext = context.getApplicationContext();
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index 4f17e52..27e1887 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -168,15 +168,11 @@
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");
+ Log.v(TAG, "START -- drawText");
+ setPaintDir(paint, dir);
+ canvas.drawText(text, x, y + currentTextSize, this.paint);
+ Log.v(TAG, "END -- drawText");
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
@@ -190,26 +186,6 @@
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) {
paint.setColor(color);
int width = getWidth();
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..4d7f042
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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.Rect;
+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;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout content = new FrameLayout(this);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ content.addView(mTextureView, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER));
+ setContentView(content);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ Canvas c = mTextureView.lockCanvas();
+ try {
+ c.drawColor(0xff00ff00);
+ } finally {
+ mTextureView.unlockCanvasAndPost(c);
+ }
+
+ c = mTextureView.lockCanvas(new Rect(100, 100, 200, 200));
+ try {
+ c.drawColor(0xff0000ff);
+ } finally {
+ mTextureView.unlockCanvasAndPost(c);
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ // Ignored
+ }
+
+ @Override
+ public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ // Ignored
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ // Ignored
+ }
+}