Merge "Catching RemoteViews#apply() layout inflation exceptions in RemoteViewsAdapter"
diff --git a/api/current.txt b/api/current.txt
index d3333f0..634b050 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2256,7 +2256,6 @@
method public abstract void setCustomView(android.view.View);
method public abstract void setCustomView(android.view.View, android.app.ActionBar.LayoutParams);
method public abstract void setCustomView(int);
- method public abstract void setDisplayDisableHomeEnabled(boolean);
method public abstract void setDisplayHomeAsUpEnabled(boolean);
method public abstract void setDisplayOptions(int);
method public abstract void setDisplayOptions(int, int);
@@ -2264,6 +2263,7 @@
method public abstract void setDisplayShowHomeEnabled(boolean);
method public abstract void setDisplayShowTitleEnabled(boolean);
method public abstract void setDisplayUseLogoEnabled(boolean);
+ method public abstract void setHomeButtonEnabled(boolean);
method public abstract void setIcon(int);
method public abstract void setIcon(android.graphics.drawable.Drawable);
method public abstract void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.app.ActionBar.OnNavigationListener);
@@ -2276,7 +2276,6 @@
method public abstract void setTitle(java.lang.CharSequence);
method public abstract void setTitle(int);
method public abstract void show();
- field public static final int DISPLAY_DISABLE_HOME = 32; // 0x20
field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
@@ -8938,6 +8937,8 @@
method public java.lang.String flatten();
method public java.lang.String get(java.lang.String);
method public java.lang.String getAntibanding();
+ method public boolean getAutoExposureLock();
+ method public boolean getAutoWhiteBalanceLock();
method public java.lang.String getColorEffect();
method public int getExposureCompensation();
method public float getExposureCompensationStep();
@@ -8983,6 +8984,8 @@
method public java.lang.String getWhiteBalance();
method public int getZoom();
method public java.util.List<java.lang.Integer> getZoomRatios();
+ method public boolean isAutoExposureLockSupported();
+ method public boolean isAutoWhiteBalanceLockSupported();
method public boolean isSmoothZoomSupported();
method public boolean isZoomSupported();
method public void remove(java.lang.String);
@@ -8990,6 +8993,8 @@
method public void set(java.lang.String, java.lang.String);
method public void set(java.lang.String, int);
method public void setAntibanding(java.lang.String);
+ method public void setAutoExposureLock(boolean);
+ method public void setAutoWhiteBalanceLock(boolean);
method public void setColorEffect(java.lang.String);
method public void setExposureCompensation(int);
method public void setFlashMode(java.lang.String);
@@ -11958,6 +11963,8 @@
public final class NdefRecord implements android.os.Parcelable {
ctor public NdefRecord(short, byte[], byte[], byte[]);
ctor public NdefRecord(byte[]) throws android.nfc.FormatException;
+ method public static android.nfc.NdefRecord createUri(android.net.Uri);
+ method public static android.nfc.NdefRecord createUri(java.lang.String);
method public int describeContents();
method public byte[] getId();
method public byte[] getPayload();
@@ -15750,6 +15757,7 @@
public static final class ContactsContract.CommonDataKinds.Photo implements android.provider.ContactsContract.DataColumnsWithJoins {
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
field public static final java.lang.String PHOTO = "data15";
+ field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
@@ -15889,7 +15897,9 @@
public static final class ContactsContract.Contacts.Photo implements android.provider.BaseColumns android.provider.ContactsContract.DataColumnsWithJoins {
field public static final java.lang.String CONTENT_DIRECTORY = "photo";
+ field public static final java.lang.String DISPLAY_PHOTO = "display_photo";
field public static final java.lang.String PHOTO = "data15";
+ field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns {
@@ -15902,6 +15912,7 @@
field public static final java.lang.String IN_VISIBLE_GROUP = "in_visible_group";
field public static final java.lang.String IS_USER_PROFILE = "is_user_profile";
field public static final java.lang.String LOOKUP_KEY = "lookup";
+ field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id";
field public static final java.lang.String PHOTO_ID = "photo_id";
field public static final java.lang.String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
field public static final java.lang.String PHOTO_URI = "photo_uri";
@@ -15990,6 +16001,13 @@
field public static final int UNDEFINED = 0; // 0x0
}
+ public static final class ContactsContract.DisplayPhoto {
+ field public static final android.net.Uri CONTENT_MAX_DIMENSIONS_URI;
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DISPLAY_MAX_DIM = "display_max_dim";
+ field public static final java.lang.String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
+ }
+
public static abstract interface ContactsContract.FullNameStyle {
field public static final int CHINESE = 3; // 0x3
field public static final int CJK = 2; // 0x2
@@ -16008,6 +16026,8 @@
}
protected static abstract interface ContactsContract.GroupsColumns {
+ field public static final java.lang.String ACTION = "action";
+ field public static final java.lang.String ACTION_URI = "action_uri";
field public static final java.lang.String AUTO_ADD = "auto_add";
field public static final java.lang.String DATA_SET = "data_set";
field public static final java.lang.String DELETED = "deleted";
@@ -16125,6 +16145,10 @@
field public static final java.lang.String CONTENT_DIRECTORY = "data";
}
+ public static final class ContactsContract.RawContacts.DisplayPhoto {
+ field public static final java.lang.String CONTENT_DIRECTORY = "display_photo";
+ }
+
public static final class ContactsContract.RawContacts.Entity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
field public static final java.lang.String CONTENT_DIRECTORY = "entity";
field public static final java.lang.String DATA_ID = "data_id";
@@ -22056,6 +22080,7 @@
method public void buildDrawingCache();
method public void buildDrawingCache(boolean);
method public void buildLayer();
+ method protected boolean canResolveLayoutDirection();
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
method public void cancelLongPress();
@@ -25257,6 +25282,10 @@
method public void setRowCount(int);
method public void setRowOrderPreserved(boolean);
method public void setUseDefaultMargins(boolean);
+ method public static android.widget.GridLayout.Spec spec(int, int, android.widget.GridLayout.Alignment, int);
+ method public static android.widget.GridLayout.Spec spec(int, android.widget.GridLayout.Alignment, int);
+ method public static android.widget.GridLayout.Spec spec(int, int, android.widget.GridLayout.Alignment);
+ method public static android.widget.GridLayout.Spec spec(int, android.widget.GridLayout.Alignment);
field public static final int ALIGN_BOUNDS = 0; // 0x0
field public static final int ALIGN_MARGINS = 1; // 0x1
field public static final android.widget.GridLayout.Alignment BASELINE;
@@ -25275,23 +25304,19 @@
public static abstract class GridLayout.Alignment {
}
- public static class GridLayout.Group {
- ctor public GridLayout.Group(int, int, android.widget.GridLayout.Alignment);
- ctor public GridLayout.Group(int, android.widget.GridLayout.Alignment);
- field public final android.widget.GridLayout.Alignment alignment;
- field public int flexibility;
- }
-
public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
- ctor public GridLayout.LayoutParams(android.widget.GridLayout.Group, android.widget.GridLayout.Group);
+ ctor public GridLayout.LayoutParams(android.widget.GridLayout.Spec, android.widget.GridLayout.Spec);
ctor public GridLayout.LayoutParams();
ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
ctor public GridLayout.LayoutParams(android.widget.GridLayout.LayoutParams);
ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
method public void setGravity(int);
- field public android.widget.GridLayout.Group columnGroup;
- field public android.widget.GridLayout.Group rowGroup;
+ field public android.widget.GridLayout.Spec columnSpec;
+ field public android.widget.GridLayout.Spec rowSpec;
+ }
+
+ public static class GridLayout.Spec {
}
public class GridView extends android.widget.AbsListView {
@@ -26082,7 +26107,7 @@
ctor public ShareActionProvider(android.content.Context);
method public android.view.View onCreateActionView();
method public void setShareHistoryFileName(java.lang.String);
- method public void setShareIntent(android.view.View, android.content.Intent);
+ method public void setShareIntent(android.content.Intent);
field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
}
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index bbf6b14e..e9ee95d 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -17,19 +17,135 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
-#include <cutils/properties.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/route.h>
+#define LOG_TAG "ip-up-vpn"
+#include <cutils/log.h>
+
+#define DIR "/data/misc/vpn/"
+
+static const char *env(const char *name) {
+ const char *value = getenv(name);
+ return value ? value : "";
+}
+
+static int set_address(struct sockaddr *sa, const char *address) {
+ sa->sa_family = AF_INET;
+ return inet_pton(AF_INET, address, &((struct sockaddr_in *)sa)->sin_addr);
+}
+
+/*
+ * The primary goal is to create a file with VPN parameters. Currently they
+ * are interface, addresses, routes, DNS servers, and search domains. Each
+ * parameter occupies one line in the file, and it can be an empty string or
+ * space-separated values. The order and the format must be consistent with
+ * com.android.server.connectivity.Vpn. Here is an example.
+ *
+ * ppp0
+ * 192.168.1.100/24
+ * 0.0.0.0/0
+ * 192.168.1.1 192.168.1.2
+ * example.org
+ *
+ * The secondary goal is to unify the outcome of VPN. The current baseline
+ * is to have an interface configured with the given address and netmask
+ * and maybe add a host route to protect the tunnel. PPP-based VPN already
+ * does this, but others might not. Routes, DNS servers, and search domains
+ * are handled by the framework since they can be overridden by the users.
+ */
int main(int argc, char **argv)
{
- if (argc > 1 && strlen(argv[1]) > 0) {
- char dns[PROPERTY_VALUE_MAX];
- char *dns1 = getenv("DNS1");
- char *dns2 = getenv("DNS2");
+ FILE *state = fopen(DIR ".tmp", "wb");
+ if (!state) {
+ LOGE("Cannot create state: %s", strerror(errno));
+ return 1;
+ }
- snprintf(dns, sizeof(dns), "%s %s", dns1 ? dns1 : "", dns2 ? dns2 : "");
- property_set("vpn.dns", dns);
- property_set("vpn.via", argv[1]);
+ if (argc >= 6) {
+ /* Invoked by pppd. */
+ fprintf(state, "%s\n", argv[1]);
+ fprintf(state, "%s/32\n", argv[4]);
+ fprintf(state, "0.0.0.0/0\n");
+ fprintf(state, "%s %s\n", env("DNS1"), env("DNS2"));
+ fprintf(state, "\n");
+ } else if (argc == 2) {
+ /* Invoked by racoon. */
+ const char *interface = env("INTERFACE");
+ const char *address = env("INTERNAL_ADDR4");
+ const char *routes = env("SPLIT_INCLUDE_CIDR");
+
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ struct rtentry rt;
+ struct ifreq ifr;
+
+ memset(&rt, 0, sizeof(rt));
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* Remove the old host route. There could be more than one. */
+ rt.rt_flags |= RTF_UP | RTF_HOST;
+ if (set_address(&rt.rt_dst, env("REMOTE_ADDR"))) {
+ while (!ioctl(s, SIOCDELRT, &rt));
+ }
+ if (errno != ESRCH) {
+ LOGE("Cannot remove host route: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Create a new host route. */
+ rt.rt_flags |= RTF_GATEWAY;
+ if (!set_address(&rt.rt_gateway, argv[1]) ||
+ (ioctl(s, SIOCADDRT, &rt) && errno != EEXIST)) {
+ LOGE("Cannot create host route: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Bring up the interface. */
+ ifr.ifr_flags = IFF_UP;
+ strncpy(ifr.ifr_name, interface, IFNAMSIZ);
+ if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
+ LOGE("Cannot bring up %s: %s", interface, strerror(errno));
+ return 1;
+ }
+
+ /* Set the address. */
+ if (!set_address(&ifr.ifr_addr, address) ||
+ ioctl(s, SIOCSIFADDR, &ifr)) {
+ LOGE("Cannot set address: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Set the netmask. */
+ if (!set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4")) ||
+ ioctl(s, SIOCSIFNETMASK, &ifr)) {
+ LOGE("Cannot set netmask: %s", strerror(errno));
+ return 1;
+ }
+
+ /* TODO: Send few packets to trigger phase 2? */
+
+ fprintf(state, "%s\n", interface);
+ fprintf(state, "%s/%s\n", address, env("INTERNAL_CIDR4"));
+ fprintf(state, "%s\n", routes[0] ? routes : "0.0.0.0/0");
+ fprintf(state, "%s\n", env("INTERNAL_DNS4_LIST"));
+ fprintf(state, "%s\n", env("DEFAULT_DOMAIN"));
+ } else {
+ LOGE("Cannot parse parameters");
+ return 1;
+ }
+
+ fclose(state);
+ if (chmod(DIR ".tmp", 0444) || rename(DIR ".tmp", DIR "state")) {
+ LOGE("Cannot write state: %s", strerror(errno));
+ return 1;
}
return 0;
}
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 1a5b7f3..dd1c275 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -793,7 +793,9 @@
MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
- MEDIA_MIMETYPE_AUDIO_MPEG
+ MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
+ MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
+ MEDIA_MIMETYPE_VIDEO_VPX
};
for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp
index 543f650..d67329d 100644
--- a/cmds/system_server/system_main.cpp
+++ b/cmds/system_server/system_main.cpp
@@ -52,10 +52,5 @@
LOGW("*** Current priority: %d\n", getpriority(PRIO_PROCESS, 0));
setpriority(PRIO_PROCESS, 0, -1);
- #if HAVE_ANDROID_OS
- //setgid(GID_SYSTEM);
- //setuid(UID_SYSTEM);
- #endif
-
system_init();
}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3ec5edb..36940c2 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -81,6 +81,9 @@
* Set this flag if selecting the 'home' button in the action bar to return
* up by a single level in your UI rather than back to the top level or front page.
*
+ * <p>Setting this option will implicitly enable interaction with the home/up
+ * button. See {@link #setHomeButtonEnabled(boolean)}.
+ *
* @see #setDisplayOptions(int)
* @see #setDisplayOptions(int, int)
*/
@@ -107,18 +110,6 @@
public static final int DISPLAY_SHOW_CUSTOM = 0x10;
/**
- * Disable the 'home' element. This may be combined with
- * {@link #DISPLAY_SHOW_HOME} to create a non-focusable/non-clickable
- * 'home' element. Useful for a level of your app's navigation hierarchy
- * where clicking 'home' doesn't do anything.
- *
- * @see #setDisplayOptions(int)
- * @see #setDisplayOptions(int, int)
- * @see #setDisplayDisableHomeEnabled(boolean)
- */
- public static final int DISPLAY_DISABLE_HOME = 0x20;
-
- /**
* Set the action bar into custom navigation mode, supplying a view
* for custom navigation.
*
@@ -405,21 +396,6 @@
public abstract void setDisplayShowCustomEnabled(boolean showCustom);
/**
- * Set whether the 'home' affordance on the action bar should be disabled.
- * If set, the 'home' element will not be focusable or clickable, useful if
- * the user is at the top level of the app's navigation hierarchy.
- *
- * <p>To set several display options at once, see the setDisplayOptions methods.
- *
- * @param disableHome true to disable the 'home' element.
- *
- * @see #setDisplayOptions(int)
- * @see #setDisplayOptions(int, int)
- * @see #DISPLAY_DISABLE_HOME
- */
- public abstract void setDisplayDisableHomeEnabled(boolean disableHome);
-
- /**
* Set the ActionBar's background.
*
* @param d Background drawable
@@ -632,6 +608,22 @@
public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
/**
+ * Enable or disable the "home" button in the corner of the action bar. (Note that this
+ * is the application home/up affordance on the action bar, not the systemwide home
+ * button.)
+ *
+ * <p>This defaults to true for packages targeting < API 14. For packages targeting
+ * API 14 or greater, the application should call this method to enable interaction
+ * with the home/up affordance.
+ *
+ * <p>Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable
+ * the home button.
+ *
+ * @param enabled true to enable the home button, false to disable the home button.
+ */
+ public abstract void setHomeButtonEnabled(boolean enabled);
+
+ /**
* Listener interface for ActionBar navigation events.
*/
public interface OnNavigationListener {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ee04729..8994b17 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -932,6 +932,10 @@
ucd.info = info;
queueOrSendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
}
+
+ public void scheduleTrimMemory(int level) {
+ queueOrSendMessage(H.TRIM_MEMORY, level);
+ }
}
private final class H extends Handler {
@@ -975,6 +979,7 @@
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
+ public static final int TRIM_MEMORY = 140;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -1018,6 +1023,7 @@
case SLEEPING: return "SLEEPING";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
+ case TRIM_MEMORY: return "TRIM_MEMORY";
}
}
return "(unknown)";
@@ -1158,6 +1164,8 @@
break;
case UPDATE_PACKAGE_COMPATIBILITY_INFO:
handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
+ case TRIM_MEMORY:
+ handleTrimMemory(msg.arg1);
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
}
@@ -3529,6 +3537,9 @@
BinderInternal.forceGc("mem");
}
+ final void handleTrimMemory(int level) {
+ }
+
private final void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index dc0f529..16181e0 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -478,6 +478,13 @@
updatePackageCompatibilityInfo(pkg, compat);
return true;
}
+
+ case SCHEDULE_TRIM_MEMORY_TRANSACTION: {
+ data.enforceInterface(IApplicationThread.descriptor);
+ int level = data.readInt();
+ scheduleTrimMemory(level);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -989,4 +996,12 @@
mRemote.transact(UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
}
+
+ public void scheduleTrimMemory(int level) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeInt(level);
+ mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ }
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 05a68a8..94c2c86 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -119,6 +119,7 @@
throws RemoteException;
void setCoreSettings(Bundle coreSettings) throws RemoteException;
void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
+ void scheduleTrimMemory(int level) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -162,4 +163,5 @@
int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
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;
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index dce0a97..436fdf8 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -28,6 +28,7 @@
import android.util.Log;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
@@ -533,6 +534,16 @@
Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw ex;
} finally {
+ // Send the EOD marker indicating that there is no more data
+ // forthcoming from this agent.
+ try {
+ FileOutputStream out = new FileOutputStream(data.getFileDescriptor());
+ byte[] buf = new byte[4];
+ out.write(buf);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to finalize backup stream!");
+ }
+
Binder.restoreCallingIdentity(ident);
try {
callbackBinder.opComplete(token);
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index dad60b0..92b98fd 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -51,4 +51,16 @@
* The system will perform a gc for you after returning from this method.
*/
void onLowMemory();
+
+ /** @hide */
+ static final int TRIM_MEMORY_COMPLETE = 80;
+
+ /** @hide */
+ static final int TRIM_MEMORY_MODERATE = 60;
+
+ /** @hide */
+ static final int TRIM_MEMORY_BACKGROUND = 40;
+
+ /** @hide */
+ static final int TRIM_MEMORY_INVISIBLE = 20;
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8a42693..7d67e11 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -720,8 +720,20 @@
* onAutoFocus will be called immediately with a fake value of
* <code>success</code> set to <code>true</code>.
*
+ * The auto-focus routine may lock auto-exposure and auto-white balance
+ * after it completes. To check for the state of these locks, use the
+ * {@link android.hardware.Camera.Parameters#getAutoExposureLock()} and
+ * {@link android.hardware.Camera.Parameters#getAutoWhiteBalanceLock()}
+ * methods. If such locking is undesirable, use
+ * {@link android.hardware.Camera.Parameters#setAutoExposureLock(boolean)}
+ * and
+ * {@link android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)}
+ * to release the locks.
+ *
* @param success true if focus was successful, false if otherwise
* @param camera the Camera service object
+ * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
+ * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
*/
void onAutoFocus(boolean success, Camera camera);
};
@@ -747,8 +759,21 @@
* {@link android.hardware.Camera.Parameters#FLASH_MODE_OFF}, flash may be
* fired during auto-focus, depending on the driver and camera hardware.<p>
*
+ * The auto-focus routine may lock auto-exposure and auto-white balance
+ * after it completes. To check for the state of these locks, use the
+ * {@link android.hardware.Camera.Parameters#getAutoExposureLock()} and
+ * {@link android.hardware.Camera.Parameters#getAutoWhiteBalanceLock()}
+ * methods after the {@link AutoFocusCallback#onAutoFocus(boolean, Camera)}
+ * callback is invoked. If such locking is undesirable, use
+ * {@link android.hardware.Camera.Parameters#setAutoExposureLock(boolean)}
+ * and
+ * {@link android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)}
+ * to release the locks.
+ *
* @param cb the callback to run
* @see #cancelAutoFocus()
+ * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
+ * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
*/
public final void autoFocus(AutoFocusCallback cb)
{
@@ -763,7 +788,13 @@
* this function will return the focus position to the default.
* If the camera does not support auto-focus, this is a no-op.
*
+ * Canceling auto-focus will return the auto-exposure lock and auto-white
+ * balance lock to their state before {@link #autoFocus(AutoFocusCallback)}
+ * was called.
+ *
* @see #autoFocus(Camera.AutoFocusCallback)
+ * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
+ * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
*/
public final void cancelAutoFocus()
{
@@ -2562,8 +2593,6 @@
* routine is free to run normally.
*
* @see #getAutoExposureLock()
- *
- * @hide
*/
public void setAutoExposureLock(boolean toggle) {
set(KEY_AUTO_EXPOSURE_LOCK, toggle ? TRUE : FALSE);
@@ -2583,7 +2612,6 @@
*
* @see #setAutoExposureLock(boolean)
*
- * @hide
*/
public boolean getAutoExposureLock() {
String str = get(KEY_AUTO_EXPOSURE_LOCK);
@@ -2598,7 +2626,6 @@
* @return true if auto-exposure lock is supported.
* @see #setAutoExposureLock(boolean)
*
- * @hide
*/
public boolean isAutoExposureLockSupported() {
String str = get(KEY_AUTO_EXPOSURE_LOCK_SUPPORTED);
@@ -2645,8 +2672,6 @@
* auto-white balance routine is free to run normally.
*
* @see #getAutoWhiteBalanceLock()
- *
- * @hide
*/
public void setAutoWhiteBalanceLock(boolean toggle) {
set(KEY_AUTO_WHITEBALANCE_LOCK, toggle ? TRUE : FALSE);
@@ -2668,7 +2693,6 @@
*
* @see #setAutoWhiteBalanceLock(boolean)
*
- * @hide
*/
public boolean getAutoWhiteBalanceLock() {
String str = get(KEY_AUTO_WHITEBALANCE_LOCK);
@@ -2683,7 +2707,6 @@
* @return true if auto-white balance lock is supported.
* @see #setAutoWhiteBalanceLock(boolean)
*
- * @hide
*/
public boolean isAutoWhiteBalanceLockSupported() {
String str = get(KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 19894a0..f2f0e82 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -52,11 +52,26 @@
public class LinkProperties implements Parcelable {
String mIfaceName;
- private Collection<LinkAddress> mLinkAddresses;
- private Collection<InetAddress> mDnses;
- private Collection<RouteInfo> mRoutes;
+ private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
+ private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
+ private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
private ProxyProperties mHttpProxy;
+ public static class CompareAddressesResult {
+ public ArrayList<LinkAddress> removed = new ArrayList<LinkAddress>();
+ public ArrayList<LinkAddress> added = new ArrayList<LinkAddress>();
+
+ @Override
+ public String toString() {
+ String retVal = "removedAddresses=[";
+ for (LinkAddress addr : removed) retVal += addr.toString() + ",";
+ retVal += "] addedAddresses=[";
+ for (LinkAddress addr : added) retVal += addr.toString() + ",";
+ retVal += "]";
+ return retVal;
+ }
+ }
+
public LinkProperties() {
clear();
}
@@ -121,9 +136,9 @@
public void clear() {
mIfaceName = null;
- mLinkAddresses = new ArrayList<LinkAddress>();
- mDnses = new ArrayList<InetAddress>();
- mRoutes = new ArrayList<RouteInfo>();
+ mLinkAddresses.clear();
+ mDnses.clear();
+ mRoutes.clear();
mHttpProxy = null;
}
@@ -155,6 +170,63 @@
return ifaceName + linkAddresses + routes + dns + proxy;
}
+ /**
+ * Compares this {@code LinkProperties} interface name against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalInterfaceName(LinkProperties target) {
+ return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
+ }
+
+ /**
+ * Compares this {@code LinkProperties} interface name against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalAddresses(LinkProperties target) {
+ Collection<InetAddress> targetAddresses = target.getAddresses();
+ Collection<InetAddress> sourceAddresses = getAddresses();
+ return (sourceAddresses.size() == targetAddresses.size()) ?
+ sourceAddresses.containsAll(targetAddresses) : false;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} DNS addresses against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalDnses(LinkProperties target) {
+ Collection<InetAddress> targetDnses = target.getDnses();
+ return (mDnses.size() == targetDnses.size()) ?
+ mDnses.containsAll(targetDnses) : false;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} Routes against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalRoutes(LinkProperties target) {
+ Collection<RouteInfo> targetRoutes = target.getRoutes();
+ return (mRoutes.size() == targetRoutes.size()) ?
+ mRoutes.containsAll(targetRoutes) : false;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} HttpProxy against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalHttpProxy(LinkProperties target) {
+ return getHttpProxy() == null ? target.getHttpProxy() == null :
+ getHttpProxy().equals(target.getHttpProxy());
+ }
@Override
/**
@@ -176,30 +248,41 @@
if (!(obj instanceof LinkProperties)) return false;
- boolean sameAddresses;
- boolean sameDnses;
- boolean sameRoutes;
-
LinkProperties target = (LinkProperties) obj;
- Collection<InetAddress> targetAddresses = target.getAddresses();
- Collection<InetAddress> sourceAddresses = getAddresses();
- sameAddresses = (sourceAddresses.size() == targetAddresses.size()) ?
- sourceAddresses.containsAll(targetAddresses) : false;
+ return isIdenticalInterfaceName(target) &&
+ isIdenticalAddresses(target) &&
+ isIdenticalDnses(target) &&
+ isIdenticalRoutes(target) &&
+ isIdenticalHttpProxy(target);
+ }
- Collection<InetAddress> targetDnses = target.getDnses();
- sameDnses = (mDnses.size() == targetDnses.size()) ?
- mDnses.containsAll(targetDnses) : false;
-
- Collection<RouteInfo> targetRoutes = target.getRoutes();
- sameRoutes = (mRoutes.size() == targetRoutes.size()) ?
- mRoutes.containsAll(targetRoutes) : false;
-
- return
- sameAddresses && sameDnses && sameRoutes
- && TextUtils.equals(getInterfaceName(), target.getInterfaceName())
- && (getHttpProxy() == null ? target.getHttpProxy() == null :
- getHttpProxy().equals(target.getHttpProxy()));
+ /**
+ * Return two lists, a list of addresses that would be removed from
+ * mLinkAddresses and a list of addresses that would be added to
+ * mLinkAddress which would then result in target and mLinkAddresses
+ * being the same list.
+ *
+ * @param target is a new list of addresses
+ * @return the removed and added lists.
+ */
+ public CompareAddressesResult compareAddresses(LinkProperties target) {
+ /*
+ * Duplicate the LinkAddresses into removed, we will be removing
+ * address which are common between mLinkAddresses and target
+ * leaving the addresses that are different. And address which
+ * are in target but not in mLinkAddresses are placed in the
+ * addedAddresses.
+ */
+ CompareAddressesResult result = new CompareAddressesResult();
+ result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
+ result.added.clear();
+ for (LinkAddress newAddress : target.getLinkAddresses()) {
+ if (! result.removed.remove(newAddress)) {
+ result.added.add(newAddress);
+ }
+ }
+ return result;
}
@Override
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 0eb8cd8..b668f30 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -334,8 +334,6 @@
/**
* Creates an NDEF record of well known type URI.
- * TODO: Make a public API
- * @hide
*/
public static NdefRecord createUri(Uri uri) {
return createUri(uri.toString());
@@ -343,8 +341,6 @@
/**
* Creates an NDEF record of well known type URI.
- * TODO: Make a public API
- * @hide
*/
public static NdefRecord createUri(String uriString) {
byte prefix = 0x0;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5b1f563..3362575 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -86,6 +86,12 @@
public static final int WIFI_UID = 1010;
/**
+ * Defines the UID/GID for the mediaserver process.
+ * @hide
+ */
+ public static final int MEDIA_UID = 1013;
+
+ /**
* Defines the GID for the group that allows write access to the SD card.
* @hide
*/
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 60900e1..2c4b8631 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -172,7 +172,10 @@
@Override
public String toString() {
- return mPath;
+ return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescription="
+ + mDescription + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize
+ + ", mMtpReserveSpace=" + mMtpReserveSpace + ", mPath=" + mPath + ", mRemovable="
+ + mRemovable + ", mStorageId=" + mStorageId + "]";
}
public static final Parcelable.Creator<StorageVolume> CREATOR =
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index ec67683..0dd9a4d 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -17,6 +17,7 @@
package android.provider;
import android.accounts.Account;
+import android.app.Activity;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@@ -749,11 +750,25 @@
public static final String PHOTO_ID = "photo_id";
/**
+ * Photo file ID of the full-size photo. If present, this will be used to populate
+ * {@link #PHOTO_URI}. The ID can also be used with
+ * {@link ContactsContract.DisplayPhoto#CONTENT_URI} to create a URI to the photo.
+ * If this is present, {@link #PHOTO_ID} is also guaranteed to be populated.
+ *
+ * <P>Type: INTEGER</P>
+ */
+ public static final String PHOTO_FILE_ID = "photo_file_id";
+
+ /**
* A URI that can be used to retrieve the contact's full-size photo.
+ * If PHOTO_FILE_ID is not null, this will be populated with a URI based off
+ * {@link ContactsContract.DisplayPhoto#CONTENT_URI}. Otherwise, this will
+ * be populated with the same value as {@link #PHOTO_THUMBNAIL_URI}.
* A photo can be referred to either by a URI (this field) or by ID
- * (see {@link #PHOTO_ID}). If PHOTO_ID is not null, PHOTO_URI and
- * PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa).
- * Thus using PHOTO_URI is a more robust method of retrieving contact photos.
+ * (see {@link #PHOTO_ID}). If either PHOTO_FILE_ID or PHOTO_ID is not null,
+ * PHOTO_URI and PHOTO_THUMBNAIL_URI shall not be null (but not necessarily
+ * vice versa). Thus using PHOTO_URI is a more robust method of retrieving
+ * contact photos.
*
* <P>Type: TEXT</P>
*/
@@ -766,7 +781,7 @@
* PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa).
* If the content provider does not differentiate between full-size photos
* and thumbnail photos, PHOTO_THUMBNAIL_URI and {@link #PHOTO_URI} can contain
- * the same value, but either both shell be null or both not null.
+ * the same value, but either both shall be null or both not null.
*
* <P>Type: TEXT</P>
*/
@@ -1690,10 +1705,15 @@
/**
* A <i>read-only</i> sub-directory of a single contact that contains
- * the contact's primary photo.
+ * the contact's primary photo. The photo may be stored in up to two ways -
+ * the default "photo" is a thumbnail-sized image stored directly in the data
+ * row, while the "display photo", if present, is a larger version stored as
+ * a file.
* <p>
* Usage example:
- *
+ * <dl>
+ * <dt>Retrieving the thumbnail-sized photo</dt>
+ * <dd>
* <pre>
* public InputStream openPhoto(long contactId) {
* Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
@@ -1716,10 +1736,29 @@
* return null;
* }
* </pre>
+ * </dd>
+ * <dt>Retrieving the larger photo version</dt>
+ * <dd>
+ * <pre>
+ * public InputStream openDisplayPhoto(long contactId) {
+ * Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ * Uri displayPhotoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.DISPLAY_PHOTO);
+ * try {
+ * AssetFileDescriptor fd =
+ * getContentResolver().openAssetFile(displayPhotoUri, "r");
+ * return fd.createInputStream();
+ * } catch (FileNotFoundException e) {
+ * return null;
+ * }
+ * }
+ * </pre>
+ * </dd>
+ * </dl>
*
* </p>
- * <p>You should also consider using the convenience method
+ * <p>You may also consider using the convenience method
* {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri)}
+ * to retrieve the raw photo contents of the thumbnail-sized photo.
* </p>
* <p>
* This directory can be used either with a {@link #CONTENT_URI} or
@@ -1738,6 +1777,19 @@
public static final String CONTENT_DIRECTORY = "photo";
/**
+ * The directory twig for retrieving the full-size display photo.
+ */
+ public static final String DISPLAY_PHOTO = "display_photo";
+
+ /**
+ * Full-size photo file ID of the raw contact.
+ * See {@link ContactsContract.DisplayPhoto}.
+ * <p>
+ * Type: NUMBER
+ */
+ public static final String PHOTO_FILE_ID = DATA14;
+
+ /**
* Thumbnail photo of the raw contact. This is the raw bytes of an image
* that could be inflated using {@link android.graphics.BitmapFactory}.
* <p>
@@ -2498,6 +2550,56 @@
}
/**
+ * <p>
+ * A sub-directory of a single raw contact that represents its primary
+ * display photo. To access this directory append
+ * {@link RawContacts.DisplayPhoto#CONTENT_DIRECTORY} to the raw contact URI.
+ * The resulting URI represents an image file, and should be interacted with
+ * using ContentProvider.openAssetFile.
+ * <p>
+ * <p>
+ * Note that this sub-directory also supports opening the photo as an asset file
+ * in write mode. Callers can create or replace the primary photo associated
+ * with this raw contact by opening the asset file and writing the full-size
+ * photo contents into it. When the file is closed, the image will be parsed,
+ * sized down if necessary for the full-size display photo and thumbnail
+ * dimensions, and stored.
+ * </p>
+ * <p>
+ * Usage example:
+ * <pre>
+ * public void writeDisplayPhoto(long rawContactId, byte[] photo) {
+ * Uri rawContactPhotoUri = Uri.withAppendedPath(
+ * ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
+ * RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
+ * try {
+ * AssetFileDescriptor fd =
+ * getContentResolver().openAssetFile(rawContactPhotoUri, "rw");
+ * OutputStream os = fd.createOutputStream();
+ * os.write(photo);
+ * os.close();
+ * fd.close();
+ * } catch (IOException e) {
+ * // Handle error cases.
+ * }
+ * }
+ * </pre>
+ * </p>
+ */
+ public static final class DisplayPhoto {
+ /**
+ * No public constructor since this is a utility class
+ */
+ private DisplayPhoto() {
+ }
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "display_photo";
+ }
+
+ /**
* TODO: javadoc
* @param cursor
* @return
@@ -3192,6 +3294,50 @@
}
/**
+ * <p>
+ * Constants for the photo files table, which tracks metadata for hi-res photos
+ * stored in the file system.
+ * </p>
+ *
+ * @hide
+ */
+ public static final class PhotoFiles implements BaseColumns, PhotoFilesColumns {
+ /**
+ * No public constructor since this is a utility class
+ */
+ private PhotoFiles() {
+ }
+ }
+
+ /**
+ * Columns in the PhotoFiles table.
+ *
+ * @see ContactsContract.PhotoFiles
+ *
+ * @hide
+ */
+ protected interface PhotoFilesColumns {
+
+ /**
+ * The height, in pixels, of the photo this entry is associated with.
+ * <P>Type: NUMBER</P>
+ */
+ public static final String HEIGHT = "height";
+
+ /**
+ * The width, in pixels, of the photo this entry is associated with.
+ * <P>Type: NUMBER</P>
+ */
+ public static final String WIDTH = "width";
+
+ /**
+ * The size, in bytes, of the photo stored on disk.
+ * <P>Type: NUMBER</P>
+ */
+ public static final String FILESIZE = "filesize";
+ }
+
+ /**
* Columns in the Data table.
*
* @see ContactsContract.Data
@@ -5891,7 +6037,7 @@
/**
* <p>
- * A data kind representing an photo for the contact.
+ * A data kind representing a photo for the contact.
* </p>
* <p>
* Some sync adapters will choose to download photos in a separate
@@ -5911,10 +6057,17 @@
* <th>Alias</th><th colspan='2'>Data column</th>
* </tr>
* <tr>
+ * <td>NUMBER</td>
+ * <td>{@link #PHOTO_FILE_ID}</td>
+ * <td>{@link #DATA14}</td>
+ * <td>ID of the hi-res photo file.</td>
+ * </tr>
+ * <tr>
* <td>BLOB</td>
* <td>{@link #PHOTO}</td>
* <td>{@link #DATA15}</td>
- * <td>By convention, binary data is stored in DATA15.</td>
+ * <td>By convention, binary data is stored in DATA15. The thumbnail of the
+ * photo is stored in this column.</td>
* </tr>
* </table>
*/
@@ -5928,6 +6081,14 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
/**
+ * Photo file ID for the display photo of the raw contact.
+ * See {@link ContactsContract.DisplayPhoto}.
+ * <p>
+ * Type: NUMBER
+ */
+ public static final String PHOTO_FILE_ID = DATA14;
+
+ /**
* Thumbnail photo of the raw contact. This is the raw bytes of an image
* that could be inflated using {@link android.graphics.BitmapFactory}.
* <p>
@@ -6251,6 +6412,28 @@
public static final String NOTES = "notes";
/**
+ * The Activity action to open the group in the source app (e.g.
+ * {@link Intent#ACTION_VIEW}). Can be NULL if the group does not have a dedicated viewer.
+ * This is used in conjunction with {@link #ACTION_URI}: In order to show an "Open in
+ * (sourceapp)"-button, both of these fields must be set
+ * <p>
+ * Type: TEXT
+ */
+ public static final String ACTION = "action";
+
+
+ /**
+ * Uri to open the group in the source app.
+ * Can be NULL if the group does not have a dedicated viewer.
+ * This is used in conjunction with {@link #ACTION}: In order to show an "Open in
+ * (sourceapp)"-button, both of these fields must be set
+ * <p>
+ * Type: TEXT
+ */
+ public static final String ACTION_URI = "action_uri";
+
+
+ /**
* The ID of this group if it is a System Group, i.e. a group that has a special meaning
* to the sync adapter, null otherwise.
* <P>Type: TEXT</P>
@@ -7047,6 +7230,66 @@
}
/**
+ * Helper class for accessing full-size photos by photo file ID.
+ * <p>
+ * Usage example:
+ * <dl>
+ * <dt>Retrieving a full-size photo by photo file ID (see
+ * {@link ContactsContract.ContactsColumns#PHOTO_FILE_ID})
+ * </dt>
+ * <dd>
+ * <pre>
+ * public InputStream openDisplayPhoto(long photoFileId) {
+ * Uri displayPhotoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoKey);
+ * try {
+ * AssetFileDescriptor fd = getContentResolver().openAssetFile(displayPhotoUri, "r");
+ * return fd.createInputStream();
+ * } catch (FileNotFoundException e) {
+ * return null;
+ * }
+ * }
+ * </pre>
+ * </dd>
+ * </dl>
+ * </p>
+ */
+ public static final class DisplayPhoto {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private DisplayPhoto() {}
+
+ /**
+ * The content:// style URI for this class, which allows access to full-size photos,
+ * given a key.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "display_photo");
+
+ /**
+ * This URI allows the caller to query for the maximum dimensions of a display photo
+ * or thumbnail. Requests to this URI can be performed on the UI thread because
+ * they are always unblocking.
+ */
+ public static final Uri CONTENT_MAX_DIMENSIONS_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "photo_dimensions");
+
+ /**
+ * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
+ * contain this column, populated with the maximum height and width (in pixels)
+ * that will be stored for a display photo. Larger photos will be down-sized to
+ * fit within a square of this many pixels.
+ */
+ public static final String DISPLAY_MAX_DIM = "display_max_dim";
+
+ /**
+ * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
+ * contain this column, populated with the height and width (in pixels) for photo
+ * thumbnails.
+ */
+ public static final String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
+ }
+
+ /**
* Contains helper classes used to create or manage {@link android.content.Intent Intents}
* that involve contacts.
*/
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 63c420a..f345a6a 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -660,7 +660,6 @@
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
if (mBluetoothService.attemptAutoPair(address)) return;
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 8e4725f..32ca226 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -181,7 +181,7 @@
*
* @hide
* @deprecated No longer in use, the default engine is determined by
- * the sort order defined in {@link EngineInfoComparator}. Note that
+ * the sort order defined in {@link TtsEngines}. Note that
* this doesn't "break" anything because there is no guarantee that
* the engine specified below is installed on a given build, let
* alone be the default.
@@ -504,36 +504,39 @@
}
private int initTts() {
- String defaultEngine = getDefaultEngine();
- String engine = defaultEngine;
- if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
- engine = mRequestedEngine;
+ // Step 1: Try connecting to the engine that was requested.
+ if (mRequestedEngine != null && mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
+ if (connectToEngine(mRequestedEngine)) {
+ mCurrentEngine = mRequestedEngine;
+ return SUCCESS;
+ }
}
- // Try requested engine
- if (connectToEngine(engine)) {
- mCurrentEngine = engine;
- return SUCCESS;
- }
-
- // Fall back to user's default engine if different from the already tested one
- if (!engine.equals(defaultEngine)) {
+ // Step 2: Try connecting to the user's default engine.
+ final String defaultEngine = getDefaultEngine();
+ if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) {
if (connectToEngine(defaultEngine)) {
- mCurrentEngine = engine;
+ mCurrentEngine = defaultEngine;
return SUCCESS;
}
}
+ // Step 3: Try connecting to the highest ranked engine in the
+ // system.
final String highestRanked = mEnginesHelper.getHighestRankedEngineName();
- // Fall back to the hardcoded default if different from the two above
- if (!defaultEngine.equals(highestRanked)
- && !engine.equals(highestRanked)) {
+ if (highestRanked != null && !highestRanked.equals(mRequestedEngine) &&
+ !highestRanked.equals(defaultEngine)) {
if (connectToEngine(highestRanked)) {
- mCurrentEngine = engine;
+ mCurrentEngine = highestRanked;
return SUCCESS;
}
}
+ // NOTE: The API currently does not allow the caller to query whether
+ // they are actually connected to any engine. This might fail for various
+ // reasons like if the user disables all her TTS engines.
+
+ mCurrentEngine = null;
dispatchOnInit(ERROR);
return ERROR;
}
@@ -963,7 +966,7 @@
/**
* Synthesizes the given text to a file using the specified parameters.
*
- * @param text Thetext that should be synthesized
+ * @param text The text that should be synthesized
* @param params Parameters for the request. Can be null.
* Supported parameter names:
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
@@ -1073,7 +1076,9 @@
*
* @deprecated This doesn't inform callers when the TTS engine has been
* initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
- * can be used with the appropriate engine name.
+ * can be used with the appropriate engine name. Also, there is no
+ * guarantee that the engine specified will be loaded. If it isn't
+ * installed or disabled, the user / system wide defaults will apply.
*
* @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
*
diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java
index 47f7358..5601dc5 100644
--- a/core/java/android/view/ActionProvider.java
+++ b/core/java/android/view/ActionProvider.java
@@ -28,7 +28,9 @@
* {@link android.app.ActionBar} as a substitute for the menu item when the item is
* displayed as an action item. Also the provider is responsible for performing a
* default action if a menu item placed on the overflow menu of the ActionBar is
- * selected and none of the menu item callbacks has handled the selection.
+ * selected and none of the menu item callbacks has handled the selection. For this
+ * case the provider can also optionally provide a sub-menu for accomplishing the
+ * task at hand.
* </p>
* <p>
* There are two ways for using an action provider for creating and handling of action views:
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 74dc100..8cd683e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9066,11 +9066,20 @@
// Set resolved depending on layout direction
switch (getLayoutDirection()) {
case LAYOUT_DIRECTION_INHERIT:
+ // We cannot do the resolution if there is no parent
+ if (mParent == null) return;
+
// If this is root view, no need to look at parent's layout dir.
- if (mParent != null &&
- mParent instanceof ViewGroup &&
- ((ViewGroup) mParent).getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
- mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+ if (mParent instanceof ViewGroup) {
+ ViewGroup viewGroup = ((ViewGroup) mParent);
+
+ // Check if the parent view group can resolve
+ if (! viewGroup.canResolveLayoutDirection()) {
+ return;
+ }
+ if (viewGroup.getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+ mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+ }
}
break;
case LAYOUT_DIRECTION_RTL:
@@ -9132,6 +9141,15 @@
recomputePadding();
}
+ protected boolean canResolveLayoutDirection() {
+ switch (getLayoutDirection()) {
+ case LAYOUT_DIRECTION_INHERIT:
+ return (mParent != null);
+ default:
+ return true;
+ }
+ }
+
/**
* Reset the resolved layout direction.
*
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 0294e3f..88583df 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -120,6 +120,7 @@
private static final int AUTO_LOGIN = 140;
private static final int CLIENT_CERT_REQUEST = 141;
private static final int SEARCHBOX_IS_SUPPORTED_CALLBACK = 142;
+ private static final int SEARCHBOX_DISPATCH_COMPLETE_CALLBACK= 143;
// Message triggered by the client to resume execution
private static final int NOTIFY = 200;
@@ -821,6 +822,13 @@
searchBox.handleIsSupportedCallback(supported);
break;
}
+ case SEARCHBOX_DISPATCH_COMPLETE_CALLBACK: {
+ SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox();
+ Boolean success = (Boolean) msg.obj;
+ searchBox.handleDispatchCompleteCallback(msg.getData().getString("function"),
+ msg.getData().getInt("id"), success);
+ break;
+ }
}
}
@@ -1641,4 +1649,13 @@
msg.obj = new Boolean(isSupported);
sendMessage(msg);
}
+
+ void onSearchboxDispatchCompleteCallback(String function, int id, boolean success) {
+ Message msg = obtainMessage(SEARCHBOX_DISPATCH_COMPLETE_CALLBACK);
+ msg.obj = Boolean.valueOf(success);
+ msg.getData().putString("function", function);
+ msg.getData().putInt("id", id);
+
+ sendMessage(msg);
+ }
}
diff --git a/core/java/android/webkit/SearchBox.java b/core/java/android/webkit/SearchBox.java
index 5075302..6512c4b 100644
--- a/core/java/android/webkit/SearchBox.java
+++ b/core/java/android/webkit/SearchBox.java
@@ -68,11 +68,15 @@
* Notify the search page of any changes to the searchbox. Such as
* a change in the typed query (onchange), the user commiting a given query
* (onsubmit), or a change in size of a suggestions dropdown (onresize).
+ *
+ * @param listener an optional listener to notify of the success of the operation,
+ * indicating if the javascript function existed and could be called or not.
+ * It will be called on the UI thread.
*/
- void onchange();
- void onsubmit();
- void onresize();
- void oncancel();
+ void onchange(SearchBoxListener listener);
+ void onsubmit(SearchBoxListener listener);
+ void onresize(SearchBoxListener listener);
+ void oncancel(SearchBoxListener listener);
/**
* Add and remove listeners to the given Searchbox. Listeners are notified
@@ -91,8 +95,12 @@
* Listeners (if any) will be called on the thread that created the
* webview.
*/
- interface SearchBoxListener {
- void onSuggestionsReceived(String query, List<String> suggestions);
+ public abstract class SearchBoxListener {
+ public void onSuggestionsReceived(String query, List<String> suggestions) {}
+ public void onChangeComplete(boolean called) {}
+ public void onSubmitComplete(boolean called) {}
+ public void onResizeComplete(boolean called) {}
+ public void onCancelComplete(boolean called) {}
}
interface IsSupportedCallback {
diff --git a/core/java/android/webkit/SearchBoxImpl.java b/core/java/android/webkit/SearchBoxImpl.java
index 61fb2ce..9942d25 100644
--- a/core/java/android/webkit/SearchBoxImpl.java
+++ b/core/java/android/webkit/SearchBoxImpl.java
@@ -16,10 +16,12 @@
package android.webkit;
+import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewCore.EventHub;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
@@ -69,7 +71,7 @@
private static final String SET_VERBATIM_SCRIPT
= "if (window.chrome && window.chrome.searchBox) {"
- + " window.chrome.searchBox.verbatim = %s;"
+ + " window.chrome.searchBox.verbatim = %1$s;"
+ "}";
private static final String SET_SELECTION_SCRIPT
@@ -89,13 +91,21 @@
+ "}";
private static final String DISPATCH_EVENT_SCRIPT
- = "if (window.chrome && window.chrome.searchBox &&"
- + " window.chrome.searchBox.on%1$s) { window.chrome.searchBox.on%1$s(); }";
+ = "if (window.chrome && window.chrome.searchBox && window.chrome.searchBox.on%1$s) {"
+ + " window.chrome.searchBox.on%1$s();"
+ + " window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, true);"
+ + "} else {"
+ + " window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, false);"
+ + "}";
+
+ private static final String EVENT_CHANGE = "change";
+ private static final String EVENT_SUBMIT = "submit";
+ private static final String EVENT_RESIZE = "resize";
+ private static final String EVENT_CANCEL = "cancel";
private static final String IS_SUPPORTED_SCRIPT
= "if (window.searchBoxJavaBridge_) {"
- + " if (window.chrome && window.chrome.searchBox && "
- + " window.chrome.searchBox.onsubmit) {"
+ + " if (window.chrome && window.chrome.sv) {"
+ " window.searchBoxJavaBridge_.isSupportedCallback(true);"
+ " } else {"
+ " window.searchBoxJavaBridge_.isSupportedCallback(false);"
@@ -105,11 +115,14 @@
private final WebViewCore mWebViewCore;
private final CallbackProxy mCallbackProxy;
private IsSupportedCallback mSupportedCallback;
+ private int mNextEventId = 1;
+ private final HashMap<Integer, SearchBoxListener> mEventCallbacks;
SearchBoxImpl(WebViewCore webViewCore, CallbackProxy callbackProxy) {
mListeners = new ArrayList<SearchBoxListener>();
mWebViewCore = webViewCore;
mCallbackProxy = callbackProxy;
+ mEventCallbacks = new HashMap<Integer, SearchBoxListener>();
}
@Override
@@ -141,27 +154,36 @@
}
@Override
- public void onchange() {
- dispatchEvent("change");
+ public void onchange(SearchBoxListener callback) {
+ dispatchEvent(EVENT_CHANGE, callback);
}
@Override
- public void onsubmit() {
- dispatchEvent("submit");
+ public void onsubmit(SearchBoxListener callback) {
+ dispatchEvent(EVENT_SUBMIT, callback);
}
@Override
- public void onresize() {
- dispatchEvent("resize");
+ public void onresize(SearchBoxListener callback) {
+ dispatchEvent(EVENT_RESIZE, callback);
}
@Override
- public void oncancel() {
- dispatchEvent("cancel");
+ public void oncancel(SearchBoxListener callback) {
+ dispatchEvent(EVENT_CANCEL, callback);
}
- private void dispatchEvent(String eventName) {
- final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName);
+ private void dispatchEvent(String eventName, SearchBoxListener callback) {
+ int eventId;
+ if (callback != null) {
+ synchronized(this) {
+ eventId = mNextEventId++;
+ mEventCallbacks.put(eventId, callback);
+ }
+ } else {
+ eventId = 0;
+ }
+ final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName, eventId);
dispatchJs(js);
}
@@ -202,9 +224,35 @@
}
}
+ // Called by Javascript through the Java bridge.
+ public void dispatchCompleteCallback(String function, int id, boolean successful) {
+ mCallbackProxy.onSearchboxDispatchCompleteCallback(function, id, successful);
+ }
+
+ public void handleDispatchCompleteCallback(String function, int id, boolean successful) {
+ if (id != 0) {
+ SearchBoxListener listener;
+ synchronized(this) {
+ listener = mEventCallbacks.get(id);
+ mEventCallbacks.remove(id);
+ }
+ if (listener != null) {
+ if (TextUtils.equals(EVENT_CHANGE, function)) {
+ listener.onChangeComplete(successful);
+ } else if (TextUtils.equals(EVENT_SUBMIT, function)) {
+ listener.onSubmitComplete(successful);
+ } else if (TextUtils.equals(EVENT_RESIZE, function)) {
+ listener.onResizeComplete(successful);
+ } else if (TextUtils.equals(EVENT_CANCEL, function)) {
+ listener.onCancelComplete(successful);
+ }
+ }
+ }
+ }
+
// This is used as a hackish alternative to javascript escaping.
// There appears to be no such functionality in the core framework.
- private String jsonSerialize(String query) {
+ private static String jsonSerialize(String query) {
JSONStringer stringer = new JSONStringer();
try {
stringer.array().value(query).endArray();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7ba86a5..3ae10fe 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -9089,6 +9089,52 @@
}
}
+ /**
+ * Begin collecting per-tile profiling data
+ *
+ * @hide only used by profiling tests
+ */
+ public void tileProfilingStart() {
+ nativeTileProfilingStart();
+ }
+ /**
+ * Return per-tile profiling data
+ *
+ * @hide only used by profiling tests
+ */
+ public float tileProfilingStop() {
+ return nativeTileProfilingStop();
+ }
+
+ /** @hide only used by profiling tests */
+ public void tileProfilingClear() {
+ nativeTileProfilingClear();
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingNumFrames() {
+ return nativeTileProfilingNumFrames();
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingNumTilesInFrame(int frame) {
+ return nativeTileProfilingNumTilesInFrame(frame);
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingGetX(int frame, int tile) {
+ return nativeTileProfilingGetX(frame, tile);
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingGetY(int frame, int tile) {
+ return nativeTileProfilingGetY(frame, tile);
+ }
+ /** @hide only used by profiling tests */
+ public boolean tileProfilingGetReady(int frame, int tile) {
+ return nativeTileProfilingGetReady(frame, tile);
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingGetLevel(int frame, int tile) {
+ return nativeTileProfilingGetLevel(frame, tile);
+ }
+
private native int nativeCacheHitFramePointer();
private native boolean nativeCacheHitIsPlugin();
private native Rect nativeCacheHitNodeBounds();
@@ -9211,6 +9257,15 @@
private native void nativeStopGL();
private native Rect nativeSubtractLayers(Rect content);
private native int nativeTextGeneration();
+ private native void nativeTileProfilingStart();
+ private native float nativeTileProfilingStop();
+ private native void nativeTileProfilingClear();
+ private native int nativeTileProfilingNumFrames();
+ private native int nativeTileProfilingNumTilesInFrame(int frame);
+ private native int nativeTileProfilingGetX(int frame, int tile);
+ private native int nativeTileProfilingGetY(int frame, int tile);
+ private native boolean nativeTileProfilingGetReady(int frame, int tile);
+ private native int nativeTileProfilingGetLevel(int frame, int tile);
// Never call this version except by updateCachedTextfield(String) -
// we always want to pass in our generation number.
private native void nativeUpdateCachedTextfield(String updatedText,
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c652e55..5414b79 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -248,7 +248,7 @@
/* Get the BrowserFrame component. This is used for subwindow creation and
* is called only from BrowserFrame in the WebCore thread. */
- /* package */ BrowserFrame getBrowserFrame() {
+ /* package */ synchronized BrowserFrame getBrowserFrame() {
return mBrowserFrame;
}
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 83f80ff..32c44d8 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -126,7 +126,7 @@
*/
// This cannot be done by a simple comparator since an Activity weight
// is computed from history. Note that Activity implements Comparable.
- public void sort(Intent intent, List<Activity> activities,
+ public void sort(Intent intent, List<ActivityResolveInfo> activities,
List<HistoricalRecord> historicalRecords);
}
@@ -215,7 +215,7 @@
/**
* List of activities that can handle the current intent.
*/
- private final List<Activity> mActivitys = new ArrayList<Activity>();
+ private final List<ActivityResolveInfo> mActivites = new ArrayList<ActivityResolveInfo>();
/**
* List with historical choice records.
@@ -311,9 +311,6 @@
* @return The model.
*/
public static ActivityChooserModel get(Context context, String historyFileName) {
- if (historyFileName == null) {
- return new ActivityChooserModel(context, historyFileName);
- }
synchronized (sRegistryLock) {
ActivityChooserModel dataModel = sDataModelRegistry.get(historyFileName);
if (dataModel == null) {
@@ -380,7 +377,7 @@
*/
public int getActivityCount() {
synchronized (mInstanceLock) {
- return mActivitys.size();
+ return mActivites.size();
}
}
@@ -389,12 +386,12 @@
*
* @return The activity.
*
- * @see Activity
+ * @see ActivityResolveInfo
* @see #setIntent(Intent)
*/
public ResolveInfo getActivity(int index) {
synchronized (mInstanceLock) {
- return mActivitys.get(index).resolveInfo;
+ return mActivites.get(index).resolveInfo;
}
}
@@ -406,10 +403,10 @@
* @return The index if found, -1 otherwise.
*/
public int getActivityIndex(ResolveInfo activity) {
- List<Activity> activities = mActivitys;
+ List<ActivityResolveInfo> activities = mActivites;
final int activityCount = activities.size();
for (int i = 0; i < activityCount; i++) {
- Activity currentActivity = activities.get(i);
+ ActivityResolveInfo currentActivity = activities.get(i);
if (currentActivity.resolveInfo == activity) {
return i;
}
@@ -433,8 +430,8 @@
* @see HistoricalRecord
*/
public Intent chooseActivity(int index) {
- Activity chosenActivity = mActivitys.get(index);
- Activity defaultActivity = mActivitys.get(0);
+ ActivityResolveInfo chosenActivity = mActivites.get(index);
+ ActivityResolveInfo defaultActivity = mActivites.get(0);
ComponentName chosenName = new ComponentName(
chosenActivity.resolveInfo.activityInfo.packageName,
@@ -460,8 +457,8 @@
*/
public ResolveInfo getDefaultActivity() {
synchronized (mInstanceLock) {
- if (!mActivitys.isEmpty()) {
- return mActivitys.get(0).resolveInfo;
+ if (!mActivites.isEmpty()) {
+ return mActivites.get(0).resolveInfo;
}
}
return null;
@@ -478,8 +475,8 @@
* @param index The index of the activity to set as default.
*/
public void setDefaultActivity(int index) {
- Activity newDefaultActivity = mActivitys.get(index);
- Activity oldDefaultActivity = mActivitys.get(0);
+ ActivityResolveInfo newDefaultActivity = mActivites.get(index);
+ ActivityResolveInfo oldDefaultActivity = mActivites.get(0);
final float weight;
if (oldDefaultActivity != null) {
@@ -572,8 +569,8 @@
*/
private void sortActivities() {
synchronized (mInstanceLock) {
- if (mActivitySorter != null && !mActivitys.isEmpty()) {
- mActivitySorter.sort(mIntent, mActivitys,
+ if (mActivitySorter != null && !mActivites.isEmpty()) {
+ mActivitySorter.sort(mIntent, mActivites,
Collections.unmodifiableList(mHistoricalRecords));
notifyChanged();
}
@@ -661,14 +658,14 @@
* Loads the activities.
*/
private void loadActivitiesLocked() {
- mActivitys.clear();
+ mActivites.clear();
if (mIntent != null) {
List<ResolveInfo> resolveInfos =
mContext.getPackageManager().queryIntentActivities(mIntent, 0);
final int resolveInfoCount = resolveInfos.size();
for (int i = 0; i < resolveInfoCount; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
- mActivitys.add(new Activity(resolveInfo));
+ mActivites.add(new ActivityResolveInfo(resolveInfo));
}
sortActivities();
} else {
@@ -797,7 +794,7 @@
/**
* Represents an activity.
*/
- public final class Activity implements Comparable<Activity> {
+ public final class ActivityResolveInfo implements Comparable<ActivityResolveInfo> {
/**
* The {@link ResolveInfo} of the activity.
@@ -814,7 +811,7 @@
*
* @param resolveInfo activity {@link ResolveInfo}.
*/
- public Activity(ResolveInfo resolveInfo) {
+ public ActivityResolveInfo(ResolveInfo resolveInfo) {
this.resolveInfo = resolveInfo;
}
@@ -834,14 +831,14 @@
if (getClass() != obj.getClass()) {
return false;
}
- Activity other = (Activity) obj;
+ ActivityResolveInfo other = (ActivityResolveInfo) obj;
if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) {
return false;
}
return true;
}
- public int compareTo(Activity another) {
+ public int compareTo(ActivityResolveInfo another) {
return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
}
@@ -862,18 +859,18 @@
private final class DefaultSorter implements ActivitySorter {
private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f;
- private final Map<String, Activity> mPackageNameToActivityMap =
- new HashMap<String, Activity>();
+ private final Map<String, ActivityResolveInfo> mPackageNameToActivityMap =
+ new HashMap<String, ActivityResolveInfo>();
- public void sort(Intent intent, List<Activity> activities,
+ public void sort(Intent intent, List<ActivityResolveInfo> activities,
List<HistoricalRecord> historicalRecords) {
- Map<String, Activity> packageNameToActivityMap =
+ Map<String, ActivityResolveInfo> packageNameToActivityMap =
mPackageNameToActivityMap;
packageNameToActivityMap.clear();
final int activityCount = activities.size();
for (int i = 0; i < activityCount; i++) {
- Activity activity = activities.get(i);
+ ActivityResolveInfo activity = activities.get(i);
activity.weight = 0.0f;
String packageName = activity.resolveInfo.activityInfo.packageName;
packageNameToActivityMap.put(packageName, activity);
@@ -884,9 +881,11 @@
for (int i = lastShareIndex; i >= 0; i--) {
HistoricalRecord historicalRecord = historicalRecords.get(i);
String packageName = historicalRecord.activity.getPackageName();
- Activity activity = packageNameToActivityMap.get(packageName);
- activity.weight += historicalRecord.weight * nextRecordWeight;
- nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT;
+ ActivityResolveInfo activity = packageNameToActivityMap.get(packageName);
+ if (activity != null) {
+ activity.weight += historicalRecord.weight * nextRecordWeight;
+ nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT;
+ }
}
Collections.sort(activities);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 2fe8162..f500b39 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -16,10 +16,7 @@
package android.widget;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -27,12 +24,20 @@
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.os.Debug;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ActivityChooserModel;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListPopupWindow;
+import android.widget.PopupWindow;
+import android.widget.TextView;
import com.android.internal.R;
@@ -56,11 +61,6 @@
* </li>
* </ul>
* </p>
- * </p>
- * This view is backed by a {@link ActivityChooserModel}. Calling {@link #showPopup()}
- * while this view is attached to the view hierarchy will show a popup with
- * activities while if the view is not attached it will show a dialog.
- * </p>
*
* @hide
*/
@@ -92,29 +92,21 @@
private final ImageButton mDefaultActionButton;
/**
- * The header for handlers list.
+ * Observer for the model data.
*/
- private final View mListHeaderView;
+ private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
- /**
- * The footer for handlers list.
- */
- private final View mListFooterView;
-
- /**
- * The title of the header view.
- */
- private TextView mListHeaderViewTitle;
-
- /**
- * The title for expanding the activities list.
- */
- private final String mListHeaderViewTitleSelectDefault;
-
- /**
- * The title if no activity exist.
- */
- private final String mListHeaderViewTitleNoActivities;
+ @Override
+ public void onChanged() {
+ super.onChanged();
+ mAdapter.notifyDataSetChanged();
+ }
+ @Override
+ public void onInvalidated() {
+ super.onInvalidated();
+ mAdapter.notifyDataSetInvalidated();
+ }
+ };
/**
* Popup window for showing the activity overflow list.
@@ -122,11 +114,6 @@
private ListPopupWindow mListPopupWindow;
/**
- * Alert dialog for showing the activity overflow list.
- */
- private AlertDialog mAlertDialog;
-
- /**
* Listener for the dismissal of the popup/alert.
*/
private PopupWindow.OnDismissListener mOnDismissListener;
@@ -147,16 +134,6 @@
private boolean mIsAttachedToWindow;
/**
- * Flag whether this view is showing an alert dialog.
- */
- private boolean mIsShowingAlertDialog;
-
- /**
- * Flag whether this view is showing a popup window.
- */
- private boolean mIsShowingPopuWindow;
-
- /**
* Create a new instance.
*
* @param context The application environment.
@@ -195,8 +172,7 @@
Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
R.styleable.ActivityChooserView_expandActivityOverflowButtonDrawable);
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.activity_chooser_view, this, true);
mCallbacks = new Callbacks();
@@ -211,15 +187,6 @@
mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
mExpandActivityOverflowButton.setBackgroundDrawable(expandActivityOverflowButtonDrawable);
- mListHeaderView = inflater.inflate(R.layout.activity_chooser_list_header, null);
- mListFooterView = inflater.inflate(R.layout.activity_chooser_list_footer, null);
-
- mListHeaderViewTitle = (TextView) mListHeaderView.findViewById(R.id.title);
- mListHeaderViewTitleSelectDefault = context.getString(
- R.string.activity_chooser_view_select_default);
- mListHeaderViewTitleNoActivities = context.getString(
- R.string.activity_chooser_view_no_activities);
-
mAdapter = new ActivityChooserViewAdapter();
mAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
@@ -262,7 +229,7 @@
* @return True if the popup was shown, false if already showing.
*/
public boolean showPopup() {
- if (isShowingPopup()) {
+ if (isShowingPopup() || !mIsAttachedToWindow) {
return false;
}
mIsSelectingDefaultActivity = false;
@@ -276,38 +243,29 @@
* @param maxActivityCount The max number of activities to display.
*/
private void showPopupUnchecked(int maxActivityCount) {
+ if (mAdapter.getDataModel() == null) {
+ throw new IllegalStateException("No data model. Did you call #setDataModel?");
+ }
+
mAdapter.setMaxActivityCount(maxActivityCount);
- if (mIsSelectingDefaultActivity) {
- if (mAdapter.getActivityCount() > 0) {
- mListHeaderViewTitle.setText(mListHeaderViewTitleSelectDefault);
+
+ final int activityCount = mAdapter.getActivityCount();
+ if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
+ && activityCount > maxActivityCount + 1) {
+ mAdapter.setShowFooterView(true);
+ } else {
+ mAdapter.setShowFooterView(false);
+ }
+
+ ListPopupWindow popupWindow = getListPopupWindow();
+ if (!popupWindow.isShowing()) {
+ if (mIsSelectingDefaultActivity) {
+ mAdapter.setShowDefaultActivity(true);
} else {
- mListHeaderViewTitle.setText(mListHeaderViewTitleNoActivities);
+ mAdapter.setShowDefaultActivity(false);
}
- mAdapter.setHeaderView(mListHeaderView);
- } else {
- mAdapter.setHeaderView(null);
- }
-
- if (mAdapter.getActivityCount() > maxActivityCount + 1) {
- mAdapter.setFooterView(mListFooterView);
- } else {
- mAdapter.setFooterView(null);
- }
-
- if (!mIsAttachedToWindow || mIsShowingAlertDialog) {
- AlertDialog alertDialog = getAlertDilalog();
- if (!alertDialog.isShowing()) {
- alertDialog.setCustomTitle(this);
- alertDialog.show();
- mIsShowingAlertDialog = true;
- }
- } else {
- ListPopupWindow popupWindow = getListPopupWindow();
- if (!popupWindow.isShowing()) {
- popupWindow.setContentWidth(mAdapter.measureContentWidth());
- popupWindow.show();
- mIsShowingPopuWindow = true;
- }
+ popupWindow.setContentWidth(mAdapter.measureContentWidth());
+ popupWindow.show();
}
}
@@ -317,12 +275,7 @@
* @return True if dismissed, false if already dismissed.
*/
public boolean dismissPopup() {
- if (!isShowingPopup()) {
- return false;
- }
- if (mIsShowingAlertDialog) {
- getAlertDilalog().dismiss();
- } else if (mIsShowingPopuWindow) {
+ if (isShowingPopup()) {
getListPopupWindow().dismiss();
}
return true;
@@ -334,12 +287,7 @@
* @return True if the popup is shown.
*/
public boolean isShowingPopup() {
- if (mIsShowingAlertDialog) {
- return getAlertDilalog().isShowing();
- } else if (mIsShowingPopuWindow) {
- return getListPopupWindow().isShowing();
- }
- return false;
+ return getListPopupWindow().isShowing();
}
@Override
@@ -347,6 +295,7 @@
super.onAttachedToWindow();
ActivityChooserModel dataModel = mAdapter.getDataModel();
if (dataModel != null) {
+ dataModel.registerObserver(mModelDataSetOberver);
dataModel.readHistoricalData();
}
mIsAttachedToWindow = true;
@@ -357,6 +306,7 @@
super.onDetachedFromWindow();
ActivityChooserModel dataModel = mAdapter.getDataModel();
if (dataModel != null) {
+ dataModel.unregisterObserver(mModelDataSetOberver);
dataModel.persistHistoricalData();
}
mIsAttachedToWindow = false;
@@ -371,13 +321,11 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mActivityChooserContent.layout(left, top, right, bottom);
- if (mIsShowingPopuWindow) {
- if (isShown()) {
- showPopupUnchecked(mAdapter.getMaxActivityCount());
- } else {
- dismissPopup();
- }
+ mActivityChooserContent.layout(0, 0, right - left, bottom - top);
+ if (getListPopupWindow().isShowing()) {
+ showPopupUnchecked(mAdapter.getMaxActivityCount());
+ } else {
+ dismissPopup();
}
}
@@ -429,22 +377,6 @@
}
/**
- * Gets the alert dialog which is lazily initialized.
- *
- * @return The popup.
- */
- private AlertDialog getAlertDilalog() {
- if (mAlertDialog == null) {
- Builder builder = new Builder(getContext());
- builder.setAdapter(mAdapter, null);
- mAlertDialog = builder.create();
- mAlertDialog.getListView().setOnItemClickListener(mCallbacks);
- mAlertDialog.setOnDismissListener(mCallbacks);
- }
- return mAlertDialog;
- }
-
- /**
* Updates the buttons state.
*/
private void updateButtons() {
@@ -469,24 +401,23 @@
* Interface implementation to avoid publishing them in the APIs.
*/
private class Callbacks implements AdapterView.OnItemClickListener,
- View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener,
- DialogInterface.OnDismissListener {
+ View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
// AdapterView#OnItemClickListener
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
final int itemViewType = adapter.getItemViewType(position);
switch (itemViewType) {
- case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_HEADER: {
- /* do nothing */
- } break;
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
} break;
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
dismissPopup();
if (mIsSelectingDefaultActivity) {
- mAdapter.getDataModel().setDefaultActivity(position);
+ // The item at position zero is the default already.
+ if (position > 0) {
+ mAdapter.getDataModel().setDefaultActivity(position);
+ }
} else {
// The first item in the model is default action => adjust index
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1);
@@ -530,16 +461,6 @@
// PopUpWindow.OnDismissListener#onDismiss
public void onDismiss() {
- mIsShowingPopuWindow = false;
- notifyOnDismissListener();
- }
-
- // DialogInterface.OnDismissListener#onDismiss
- @Override
- public void onDismiss(DialogInterface dialog) {
- mIsShowingAlertDialog = false;
- AlertDialog alertDialog = (AlertDialog) dialog;
- alertDialog.setCustomTitle(null);
notifyOnDismissListener();
}
@@ -559,59 +480,35 @@
public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
- private static final int ITEM_VIEW_TYPE_HEADER = 0;
+ private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
- private static final int ITEM_VIEW_TYPE_ACTIVITY = 1;
-
- private static final int ITEM_VIEW_TYPE_FOOTER = 2;
+ private static final int ITEM_VIEW_TYPE_FOOTER = 1;
private static final int ITEM_VIEW_TYPE_COUNT = 3;
- private final DataSetObserver mDataSetOberver = new DataSetObserver() {
-
- @Override
- public void onChanged() {
- super.onChanged();
- notifyDataSetChanged();
- }
- @Override
- public void onInvalidated() {
- super.onInvalidated();
- notifyDataSetInvalidated();
- }
- };
-
private ActivityChooserModel mDataModel;
private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
- private ResolveInfo mDefaultActivity;
+ private boolean mShowDefaultActivity;
- private View mHeaderView;
-
- private View mFooterView;
+ private boolean mShowFooterView;
public void setDataModel(ActivityChooserModel dataModel) {
+ ActivityChooserModel oldDataModel = mAdapter.getDataModel();
+ if (oldDataModel != null && isShown()) {
+ oldDataModel.unregisterObserver(mModelDataSetOberver);
+ }
mDataModel = dataModel;
- mDataModel.registerObserver(mDataSetOberver);
+ if (dataModel != null && isShown()) {
+ dataModel.registerObserver(mModelDataSetOberver);
+ }
notifyDataSetChanged();
}
@Override
- public void notifyDataSetChanged() {
- if (mDataModel.getActivityCount() > 0) {
- mDefaultActivity = mDataModel.getDefaultActivity();
- } else {
- mDefaultActivity = null;
- }
- super.notifyDataSetChanged();
- }
-
- @Override
public int getItemViewType(int position) {
- if (mHeaderView != null && position == 0) {
- return ITEM_VIEW_TYPE_HEADER;
- } else if (mFooterView != null && position == getCount() - 1) {
+ if (mShowFooterView && position == getCount() - 1) {
return ITEM_VIEW_TYPE_FOOTER;
} else {
return ITEM_VIEW_TYPE_ACTIVITY;
@@ -626,14 +523,11 @@
public int getCount() {
int count = 0;
int activityCount = mDataModel.getActivityCount();
- if (activityCount > 0) {
+ if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
activityCount--;
}
count = Math.min(activityCount, mMaxActivityCount);
- if (mHeaderView != null) {
- count++;
- }
- if (mFooterView != null) {
+ if (mShowFooterView) {
count++;
}
return count;
@@ -642,16 +536,13 @@
public Object getItem(int position) {
final int itemViewType = getItemViewType(position);
switch (itemViewType) {
- case ITEM_VIEW_TYPE_HEADER:
- return mHeaderView;
case ITEM_VIEW_TYPE_FOOTER:
- return mFooterView;
+ return null;
case ITEM_VIEW_TYPE_ACTIVITY:
- int targetIndex = (mHeaderView == null) ? position : position - 1;
- if (mDefaultActivity != null) {
- targetIndex++;
+ if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
+ position++;
}
- return mDataModel.getActivity(targetIndex);
+ return mDataModel.getActivity(position);
default:
throw new IllegalArgumentException();
}
@@ -661,27 +552,19 @@
return position;
}
- @Override
- public boolean isEnabled(int position) {
- final int itemViewType = getItemViewType(position);
- switch (itemViewType) {
- case ITEM_VIEW_TYPE_HEADER:
- return false;
- case ITEM_VIEW_TYPE_FOOTER:
- case ITEM_VIEW_TYPE_ACTIVITY:
- return true;
- default:
- throw new IllegalArgumentException();
- }
- }
-
public View getView(int position, View convertView, ViewGroup parent) {
final int itemViewType = getItemViewType(position);
switch (itemViewType) {
- case ITEM_VIEW_TYPE_HEADER:
- return mHeaderView;
case ITEM_VIEW_TYPE_FOOTER:
- return mFooterView;
+ if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
+ convertView = LayoutInflater.from(getContext()).inflate(
+ R.layout.activity_chooser_view_list_item, parent, false);
+ convertView.setId(ITEM_VIEW_TYPE_FOOTER);
+ TextView titleView = (TextView) convertView.findViewById(R.id.title);
+ titleView.setText(mContext.getString(
+ R.string.activity_chooser_view_see_all));
+ }
+ return convertView;
case ITEM_VIEW_TYPE_ACTIVITY:
if (convertView == null || convertView.getId() != R.id.list_item) {
convertView = LayoutInflater.from(getContext()).inflate(
@@ -695,6 +578,12 @@
// Set the title.
TextView titleView = (TextView) convertView.findViewById(R.id.title);
titleView.setText(activity.loadLabel(packageManager));
+ // Highlight the default.
+ if (mShowDefaultActivity && position == 0) {
+ convertView.setActivated(true);
+ } else {
+ convertView.setActivated(false);
+ }
return convertView;
default:
throw new IllegalArgumentException();
@@ -702,7 +591,7 @@
}
public int measureContentWidth() {
- // The user may have specified some of the target not to be show but we
+ // The user may have specified some of the target not to be shown but we
// want to measure all of them since after expansion they should fit.
final int oldMaxActivityCount = mMaxActivityCount;
mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED;
@@ -733,19 +622,12 @@
}
public ResolveInfo getDefaultActivity() {
- return mDefaultActivity;
+ return mDataModel.getDefaultActivity();
}
- public void setHeaderView(View headerView) {
- if (mHeaderView != headerView) {
- mHeaderView = headerView;
- notifyDataSetChanged();
- }
- }
-
- public void setFooterView(View footerView) {
- if (mFooterView != footerView) {
- mFooterView = footerView;
+ public void setShowFooterView(boolean showFooterView) {
+ if (mShowFooterView != showFooterView) {
+ mShowFooterView = showFooterView;
notifyDataSetChanged();
}
}
@@ -761,5 +643,12 @@
public ActivityChooserModel getDataModel() {
return mDataModel;
}
+
+ public void setShowDefaultActivity(boolean showDefaultActivity) {
+ if (mShowDefaultActivity != showDefaultActivity) {
+ mShowDefaultActivity = showDefaultActivity;
+ notifyDataSetChanged();
+ }
+ }
}
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 3b16994..1b713c3 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -375,6 +375,7 @@
com.android.internal.R.styleable.TextAppearance);
mDateTextSize = dateTextAppearance.getDimensionPixelSize(
R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
+ dateTextAppearance.recycle();
int weekDayTextAppearanceResId = attributesArray.getResourceId(
R.styleable.CalendarView_weekDayTextAppearance,
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index c2759e5..b9eb5ff 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -53,12 +53,12 @@
* container and grid index {@code N} is fixed to its trailing edge
* (after padding is taken into account).
*
- * <h4>Row and Column Groups</h4>
+ * <h4>Row and Column Specs</h4>
*
* Children occupy one or more contiguous cells, as defined
- * by their {@link GridLayout.LayoutParams#rowGroup rowGroup} and
- * {@link GridLayout.LayoutParams#columnGroup columnGroup} layout parameters.
- * Each group specifies the set of rows or columns that are to be
+ * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
+ * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
+ * Each spec defines the set of rows or columns that are to be
* occupied; and how children should be aligned within the resulting group of cells.
* Although cells do not normally overlap in a GridLayout, GridLayout does
* not prevent children being defined to occupy the same cell or group of cells.
@@ -92,7 +92,7 @@
*
* <h4>Excess Space Distribution</h4>
*
- * A child's ability to stretch is controlled using the {@link Group#flexibility flexibility}
+ * A child's ability to stretch is controlled using the flexibility
* properties of its row and column groups.
* <p>
* <p>
@@ -167,8 +167,7 @@
// Misc constants
private static final String TAG = GridLayout.class.getName();
- private static final boolean DEBUG = false;
- private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
+ static final boolean DEBUG = false;
private static final int PRF = 1;
// Defaults
@@ -178,8 +177,9 @@
private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
private static final boolean DEFAULT_ORDER_PRESERVED = false;
private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
- // todo remove this
- private static final int DEFAULT_CONTAINER_MARGIN = 20;
+ 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
@@ -278,12 +278,12 @@
/**
* Returns the current number of rows. This is either the last value that was set
* with {@link #setRowCount(int)} or, if no such value was set, the maximum
- * value of each the upper bounds defined in {@link LayoutParams#rowGroup}.
+ * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
*
* @return the current number of rows
*
* @see #setRowCount(int)
- * @see LayoutParams#rowGroup
+ * @see LayoutParams#rowSpec
*
* @attr ref android.R.styleable#GridLayout_rowCount
*/
@@ -299,7 +299,7 @@
* @param rowCount the number of rows
*
* @see #getRowCount()
- * @see LayoutParams#rowGroup
+ * @see LayoutParams#rowSpec
*
* @attr ref android.R.styleable#GridLayout_rowCount
*/
@@ -310,12 +310,12 @@
/**
* Returns the current number of columns. This is either the last value that was set
* with {@link #setColumnCount(int)} or, if no such value was set, the maximum
- * value of each the upper bounds defined in {@link LayoutParams#columnGroup}.
+ * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
*
* @return the current number of columns
*
* @see #setColumnCount(int)
- * @see LayoutParams#columnGroup
+ * @see LayoutParams#columnSpec
*
* @attr ref android.R.styleable#GridLayout_columnCount
*/
@@ -331,7 +331,7 @@
* @param columnCount the number of columns.
*
* @see #getColumnCount()
- * @see LayoutParams#columnGroup
+ * @see LayoutParams#columnSpec
*
* @attr ref android.R.styleable#GridLayout_columnCount
*/
@@ -381,6 +381,10 @@
*/
public void setUseDefaultMargins(boolean useDefaultMargins) {
mUseDefaultMargins = useDefaultMargins;
+ if (useDefaultMargins) {
+ int padding = DEFAULT_CONTAINER_PADDING;
+ setPadding(padding, padding, padding, padding);
+ }
requestLayout();
}
@@ -518,6 +522,14 @@
return result;
}
+ private static int sum(int[] a) {
+ int result = 0;
+ for (int i = 0, N = a.length; i < N; i++) {
+ result += a[i];
+ }
+ return result;
+ }
+
private static <T> T[] append(T[] a, T[] b) {
T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
System.arraycopy(a, 0, result, 0, a.length);
@@ -526,16 +538,10 @@
}
private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
- // In the absence of any other information, calculate a default gap such
- // that, in a grid of identical components, the heights and the vertical
- // gaps are in the proportion of the golden ratio.
- // To effect this with equal margins at each edge, set each of the
- // four margin values to half this amount.
- return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2);
+ return DEFAULT_MARGIN;
}
private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
- // todo remove DEFAULT_CONTAINER_MARGIN. Use padding? Seek advice on Themes/Styles, etc.
return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
}
@@ -543,9 +549,9 @@
if (!mUseDefaultMargins) {
return 0;
}
- Group group = horizontal ? p.columnGroup : p.rowGroup;
+ Spec spec = horizontal ? p.columnSpec : p.rowSpec;
Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
- Interval span = group.span;
+ Interval span = spec.span;
boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
return getDefaultMargin(c, isAtEdge, horizontal, leading);
@@ -593,12 +599,12 @@
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams1(c);
- final Group colGroup = lp.columnGroup;
- final Interval cols = colGroup.span;
+ final Spec colSpec = lp.columnSpec;
+ final Interval cols = colSpec.span;
final int colSpan = cols.size();
- final Group rowGroup = lp.rowGroup;
- final Interval rows = rowGroup.span;
+ final Spec rowSpec = lp.rowSpec;
+ final Interval rows = rowSpec.span;
final int rowSpan = rows.size();
if (horizontal) {
@@ -623,8 +629,8 @@
maxSize = max(maxSize, colSpan);
}
- lp.setColumnGroupSpan(new Interval(col, col + colSpan));
- lp.setRowGroupSpan(new Interval(row, row + rowSpan));
+ lp.setColumnSpecSpan(new Interval(col, col + colSpan));
+ lp.setRowSpecSpan(new Interval(row, row + rowSpan));
if (horizontal) {
col = col + colSpan;
@@ -737,7 +743,7 @@
}
// Draw margins
- paint.setColor(Color.YELLOW);
+ paint.setColor(Color.MAGENTA);
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
drawRectangle(canvas,
@@ -872,11 +878,11 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group columnGroup = lp.columnGroup;
- Group rowGroup = lp.rowGroup;
+ Spec columnSpec = lp.columnSpec;
+ Spec rowSpec = lp.rowSpec;
- Interval colSpan = columnGroup.span;
- Interval rowSpan = rowGroup.span;
+ Interval colSpan = columnSpec.span;
+ Interval rowSpan = rowSpec.span;
int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
@@ -890,8 +896,8 @@
int pWidth = getMeasurement(c, true);
int pHeight = getMeasurement(c, false);
- Alignment hAlign = columnGroup.alignment;
- Alignment vAlign = rowGroup.alignment;
+ Alignment hAlign = columnSpec.alignment;
+ Alignment vAlign = rowSpec.alignment;
int dx, dy;
@@ -961,7 +967,7 @@
public boolean countValid = false;
public boolean countWasExplicitySet = false;
- PackedMap<Group, Bounds> groupBounds;
+ PackedMap<Spec, Bounds> groupBounds;
public boolean groupBoundsValid = false;
PackedMap<Interval, MutableInt> forwardLinks;
@@ -998,9 +1004,9 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams params = getLayoutParams(c);
- Group g = horizontal ? params.columnGroup : params.rowGroup;
- count = max(count, g.span.min);
- count = max(count, g.span.max);
+ Spec spec = horizontal ? params.columnSpec : params.rowSpec;
+ count = max(count, spec.span.min);
+ count = max(count, spec.span.max);
}
return count == -1 ? UNDEFINED : count;
}
@@ -1027,17 +1033,17 @@
invalidateStructure();
}
- private PackedMap<Group, Bounds> createGroupBounds() {
- Assoc<Group, Bounds> assoc = Assoc.of(Group.class, Bounds.class);
+ private PackedMap<Spec, Bounds> createGroupBounds() {
+ Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
if (isGone(c)) {
- assoc.put(Group.GONE, Bounds.GONE);
+ assoc.put(Spec.GONE, Bounds.GONE);
} else {
LayoutParams lp = getLayoutParams(c);
- Group group = horizontal ? lp.columnGroup : lp.rowGroup;
- Bounds bounds = group.alignment.getBounds();
- assoc.put(group, bounds);
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Bounds bounds = spec.alignment.getBounds();
+ assoc.put(spec, bounds);
}
}
return assoc.pack();
@@ -1052,12 +1058,12 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- groupBounds.getValue(i).include(c, g, GridLayout.this, this);
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
}
}
- private PackedMap<Group, Bounds> getGroupBounds() {
+ private PackedMap<Spec, Bounds> getGroupBounds() {
if (groupBounds == null) {
groupBounds = createGroupBounds();
}
@@ -1071,7 +1077,7 @@
// Add values computed by alignment - taking the max of all alignments in each span
private PackedMap<Interval, MutableInt> createLinks(boolean min) {
Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
- Group[] keys = getGroupBounds().keys;
+ Spec[] keys = getGroupBounds().keys;
for (int i = 0, N = keys.length; i < N; i++) {
Interval span = min ? keys[i].span : keys[i].span.inverse();
result.put(span, new MutableInt());
@@ -1092,8 +1098,7 @@
MutableInt valueHolder = links.getValue(i);
if (min) {
valueHolder.value = max(valueHolder.value, size);
- }
- else {
+ } else {
valueHolder.value = -max(-valueHolder.value, size);
}
}
@@ -1236,8 +1241,8 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- Interval span = g.span;
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Interval span = spec.span;
leadingEdgeCount[span.min]++;
trailingEdgeCount[span.max]++;
}
@@ -1436,8 +1441,8 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- Interval span = g.span;
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Interval span = spec.span;
int index = leading ? span.min : span.max;
margins[index] = max(margins[index], getMargin(c, horizontal, leading));
}
@@ -1514,6 +1519,12 @@
}
private void setParentConstraints(int min, int max) {
+ if (mAlignmentMode != ALIGN_MARGINS) {
+ int margins = sum(getLeadingMargins()) + sum(getTrailingMargins());
+ min -= margins;
+ max -= margins;
+ }
+
parentMin.value = min;
parentMax.value = -max;
locationsValid = false;
@@ -1529,7 +1540,7 @@
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED: {
- return getMeasure(0, MAX_SIZE);
+ return getMeasure(0, MAX_SIZE);
}
case MeasureSpec.EXACTLY: {
return getMeasure(size, size);
@@ -1584,14 +1595,14 @@
* GridLayout supports both row and column spanning and arbitrary forms of alignment within
* each cell group. The fundamental parameters associated with each cell group are
* gathered into their vertical and horizontal components and stored
- * in the {@link #rowGroup} and {@link #columnGroup} layout parameters.
- * {@link Group Groups} are immutable structures and may be shared between the layout
+ * 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.
* <p>
- * The row and column groups contain the leading and trailing indices along each axis
+ * 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.
* <p>
- * The {@link Group#alignment alignment} fields of the row and column groups together specify
+ * The alignment properties of the row and column specs together specify
* both aspects of alignment within the cell group. It is also possible to specify a child's
* alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
* method.
@@ -1620,10 +1631,10 @@
* {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
* {@code false}; otherwise {@link #UNDEFINED}, to
* indicate that a default value should be computed on demand. </li>
- * <li>{@link #rowGroup}{@code .span} = {@code [0, 1]} </li>
- * <li>{@link #rowGroup}{@code .alignment} = {@link #BASELINE} </li>
- * <li>{@link #columnGroup}{@code .span} = {@code [0, 1]} </li>
- * <li>{@link #columnGroup}{@code .alignment} = {@link #LEFT} </li>
+ * <li>{@link #rowSpec}{@code .span} = {@code [0, 1]} </li>
+ * <li>{@link #rowSpec}{@code .alignment} = {@link #BASELINE} </li>
+ * <li>{@link #columnSpec}{@code .span} = {@code [0, 1]} </li>
+ * <li>{@link #columnSpec}{@code .alignment} = {@link #LEFT} </li>
* </ul>
*
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
@@ -1678,48 +1689,48 @@
// Instance variables
/**
- * The group that specifies the vertical characteristics of the cell group
+ * The spec that specifies the vertical characteristics of the cell group
* described by these layout parameters.
*/
- public Group rowGroup;
+ public Spec rowSpec;
/**
- * The group that specifies the horizontal characteristics of the cell group
+ * The spec that specifies the horizontal characteristics of the cell group
* described by these layout parameters.
*/
- public Group columnGroup;
+ public Spec columnSpec;
// Constructors
private LayoutParams(
int width, int height,
int left, int top, int right, int bottom,
- Group rowGroup, Group columnGroup) {
+ Spec rowSpec, Spec columnSpec) {
super(width, height);
setMargins(left, top, right, bottom);
- this.rowGroup = rowGroup;
- this.columnGroup = columnGroup;
+ this.rowSpec = rowSpec;
+ this.columnSpec = columnSpec;
}
/**
- * Constructs a new LayoutParams instance for this <code>rowGroup</code>
- * and <code>columnGroup</code>. All other fields are initialized with
+ * Constructs a new LayoutParams instance for this <code>rowSpec</code>
+ * and <code>columnSpec</code>. All other fields are initialized with
* default values as defined in {@link LayoutParams}.
*
- * @param rowGroup the rowGroup
- * @param columnGroup the columnGroup
+ * @param rowSpec the rowSpec
+ * @param columnSpec the columnSpec
*/
- public LayoutParams(Group rowGroup, Group columnGroup) {
+ public LayoutParams(Spec rowSpec, Spec columnSpec) {
this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
- rowGroup, columnGroup);
+ rowSpec, columnSpec);
}
/**
* Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
*/
public LayoutParams() {
- this(new Group(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT),
- new Group(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT));
+ this(new Spec(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT, Spec.DEFAULT_FLEXIBILITY),
+ new Spec(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT, Spec.DEFAULT_FLEXIBILITY));
}
// Copying constructors
@@ -1743,8 +1754,8 @@
*/
public LayoutParams(LayoutParams that) {
super(that);
- this.columnGroup = new Group(that.columnGroup);
- this.rowGroup = new Group(that.rowGroup);
+ this.columnSpec = new Spec(that.columnSpec);
+ this.rowSpec = new Spec(that.rowSpec);
}
// AttributeSet constructors
@@ -1836,14 +1847,14 @@
int column = a.getInt(COLUMN, DEFAULT_COLUMN);
int columnSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
Interval hSpan = new Interval(column, column + columnSpan);
- int hFlexibility = a.getInt(COLUMN_FLEXIBILITY, Group.DEFAULT_FLEXIBILITY);
- this.columnGroup = new Group(hSpan, getColAlignment(gravity, width), hFlexibility);
+ int hFlexibility = a.getInt(COLUMN_FLEXIBILITY, Spec.DEFAULT_FLEXIBILITY);
+ this.columnSpec = new Spec(hSpan, getColAlignment(gravity, width), hFlexibility);
int row = a.getInt(ROW, DEFAULT_ROW);
int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
Interval vSpan = new Interval(row, row + rowSpan);
- int vFlexibility = a.getInt(ROW_FLEXIBILITY, Group.DEFAULT_FLEXIBILITY);
- this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height), vFlexibility);
+ int vFlexibility = a.getInt(ROW_FLEXIBILITY, Spec.DEFAULT_FLEXIBILITY);
+ this.rowSpec = new Spec(vSpan, getRowAlignment(gravity, height), vFlexibility);
} finally {
a.recycle();
}
@@ -1858,8 +1869,8 @@
* @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
*/
public void setGravity(int gravity) {
- columnGroup = columnGroup.copyWriteAlignment(getColAlignment(gravity, width));
- rowGroup = rowGroup.copyWriteAlignment(getRowAlignment(gravity, height));
+ columnSpec = columnSpec.copyWriteAlignment(getColAlignment(gravity, width));
+ rowSpec = rowSpec.copyWriteAlignment(getRowAlignment(gravity, height));
}
@Override
@@ -1868,12 +1879,12 @@
this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
}
- private void setRowGroupSpan(Interval span) {
- rowGroup = rowGroup.copyWriteSpan(span);
+ private void setRowSpecSpan(Interval span) {
+ rowSpec = rowSpec.copyWriteSpan(span);
}
- private void setColumnGroupSpan(Interval span) {
- columnGroup = columnGroup.copyWriteSpan(span);
+ private void setColumnSpecSpan(Interval span) {
+ columnSpec = columnSpec.copyWriteSpan(span);
}
}
@@ -2019,14 +2030,14 @@
}
/*
- For each Group (with a given alignment) we need to store the amount of space required
+ For each group (with a given alignment) we need to store the amount of space required
before the alignment point and the amount of space required after it. One side of this
calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
simple optimisations are possible.
The general algorithm therefore is to create a Map (actually a PackedMap) from
- Group to Bounds and to loop through all Views in the group taking the maximum
+ group to Bounds and to loop through all Views in the group taking the maximum
of the values for each View.
*/
private static class Bounds {
@@ -2067,11 +2078,11 @@
return before - alignment.getAlignmentValue(c, size);
}
- protected void include(View c, Group group, GridLayout gridLayout, Axis axis) {
- this.flexibility &= group.flexibility;
+ protected void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
+ this.flexibility &= spec.flexibility;
int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
// todo test this works correctly when the returned value is UNDEFINED
- int before = group.alignment.getAlignmentValue(c, size);
+ int before = spec.alignment.getAlignmentValue(c, size);
include(before, size - before);
}
@@ -2176,16 +2187,13 @@
}
/**
- * A group specifies either the horizontal or vertical characteristics of a group of
+ * A spec defines either the horizontal or vertical characteristics of a group of
* cells.
- * <p>
- * Groups are immutable and so may be shared between views with the same
- * {@code span} and {@code alignment}.
*/
- public static class Group {
+ public static class Spec {
private static final int DEFAULT_FLEXIBILITY = UNDEFINED_FLEXIBILITY;
- private static final Group GONE = new Group(Interval.GONE, Alignment.GONE);
+ private static final Spec GONE = new Spec(Interval.GONE, Alignment.GONE);
/**
* The grid indices of the leading and trailing edges of this cell group for the
@@ -2200,7 +2208,7 @@
* For row groups, this specifies the vertical alignment.
* For column groups, this specifies the horizontal alignment.
*/
- public final Alignment alignment;
+ final Alignment alignment;
/**
* The flexibility field tells GridLayout how to derive minimum and maximum size
@@ -2212,82 +2220,48 @@
*
* @see GridLayout#CAN_STRETCH
*/
- public int flexibility = DEFAULT_FLEXIBILITY;
+ final int flexibility;
- /**
- * Construct a new Group, {@code group}, where:
- * <ul>
- * <li> {@code group.span = span} </li>
- * <li> {@code group.alignment = alignment} </li>
- * </ul>
- *
- * @param span the span
- * @param alignment the alignment
- */
- private Group(Interval span, Alignment alignment) {
- this.span = span;
- this.alignment = alignment;
- }
-
- private Group(Interval span, Alignment alignment, int flexibility) {
+ private Spec(Interval span, Alignment alignment, int flexibility) {
this.span = span;
this.alignment = alignment;
this.flexibility = flexibility;
}
+ private Spec(Interval span, Alignment alignment) {
+ this(span, alignment, DEFAULT_FLEXIBILITY);
+ }
+
/* Copying constructor */
- private Group(Group that) {
- this.span = that.span;
- this.alignment = that.alignment;
- this.flexibility = that.flexibility;
+ private Spec(Spec that) {
+ this(that.span, that.alignment, that.flexibility);
+ }
+
+ Spec(int start, int size, Alignment alignment, int flexibility) {
+ this(new Interval(start, start + size), alignment, flexibility);
+ }
+
+ private Spec copyWriteSpan(Interval span) {
+ return new Spec(span, alignment, flexibility);
+ }
+
+ private Spec copyWriteAlignment(Alignment alignment) {
+ return new Spec(span, alignment, flexibility);
+ }
+
+ private Spec copyWriteFlexibility(int flexibility) {
+ return new Spec(span, alignment, flexibility);
}
/**
- * Construct a new Group, {@code group}, where:
- * <ul>
- * <li> {@code group.span = [start, start + size]} </li>
- * <li> {@code group.alignment = alignment} </li>
- * </ul>
- *
- * @param start the start
- * @param size the size
- * @param alignment the alignment
- */
- public Group(int start, int size, Alignment alignment) {
- this(new Interval(start, start + size), alignment);
- }
-
- /**
- * Construct a new Group, {@code group}, where:
- * <ul>
- * <li> {@code group.span = [start, start + 1]} </li>
- * <li> {@code group.alignment = alignment} </li>
- * </ul>
- *
- * @param start the start index
- * @param alignment the alignment
- */
- public Group(int start, Alignment alignment) {
- this(start, 1, alignment);
- }
-
- private Group copyWriteSpan(Interval span) {
- return new Group(span, alignment, flexibility);
- }
-
- private Group copyWriteAlignment(Alignment alignment) {
- return new Group(span, alignment, flexibility);
- }
-
- /**
- * Returns {@code true} if the {@link #getClass class}, {@link #alignment} and {@code span}
- * properties of this Group and the supplied parameter are pairwise equal,
+ * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
+ * properties of this Spec and the supplied parameter are pairwise equal,
* {@code false} otherwise.
*
- * @param that the object to compare this group with
+ * @param that the object to compare this spec with
*
* @return {@code true} if the specified object is equal to this
- * {@code Group}; {@code false} otherwise
+ * {@code Spec}; {@code false} otherwise
*/
@Override
public boolean equals(Object that) {
@@ -2298,12 +2272,12 @@
return false;
}
- Group group = (Group) that;
+ Spec spec = (Spec) that;
- if (!alignment.equals(group.alignment)) {
+ if (!alignment.equals(spec.alignment)) {
return false;
}
- if (!span.equals(group.span)) {
+ if (!span.equals(spec.span)) {
return false;
}
@@ -2319,12 +2293,93 @@
}
/**
+ * Temporary backward compatibility class for Launcher - to avoid
+ * dependent multi-project commit. This class will be deleted after
+ * AppsCustomizePagedView is updated to new API.
+ *
+ * @hide
+ */
+ @Deprecated
+ public static class Group extends Spec {
+ /**
+ * @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);
+ }
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + size]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * <li> {@code spec.flexibility = flexibility} </li>
+ * </ul>
+ *
+ * @param start the start
+ * @param size the size
+ * @param alignment the alignment
+ * @param flexibility the flexibility
+ */
+ public static Spec spec(int start, int size, Alignment alignment, int flexibility) {
+ return new Spec(start, size, alignment, flexibility);
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + 1]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * <li> {@code spec.flexibility = flexibility} </li>
+ * </ul>
+ *
+ * @param start the start
+ * @param alignment the alignment
+ * @param flexibility the flexibility
+ */
+ public static Spec spec(int start, Alignment alignment, int flexibility) {
+ return spec(start, 1, alignment, flexibility);
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + size]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * </ul>
+ *
+ * @param start the start
+ * @param size the size
+ * @param alignment the alignment
+ */
+ public static Spec spec(int start, int size, Alignment alignment) {
+ return spec(start, size, alignment, Spec.DEFAULT_FLEXIBILITY);
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + 1]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * </ul>
+ *
+ * @param start the start index
+ * @param alignment the alignment
+ */
+ public static Spec spec(int start, Alignment alignment) {
+ return spec(start, 1, alignment);
+ }
+
+ /**
* Alignments specify where a view should be placed within a cell group and
* what size it should be.
* <p>
- * The {@link LayoutParams} class contains a {@link LayoutParams#rowGroup rowGroup}
- * and a {@link LayoutParams#columnGroup columnGroup} each of which contains an
- * {@link Group#alignment alignment}. Overall placement of the view in the cell
+ * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
+ * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
+ * {@code alignment}. Overall placement of the view in the cell
* group is specified by the two alignments which act along each axis independently.
* <p>
* The GridLayout class defines the most common alignments used in general layout:
@@ -2425,8 +2480,8 @@
/**
* Indicates that a view should be <em>centered</em> with the other views in its cell group.
- * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and {@link
- * LayoutParams#columnGroup columnGroups}.
+ * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
+ * LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment CENTER = new Alignment() {
public int getAlignmentValue(View view, int viewSize) {
@@ -2437,7 +2492,7 @@
/**
* Indicates that a view should be aligned with the <em>baselines</em>
* of the other views in its cell group.
- * This constant may only be used as an alignment in {@link LayoutParams#rowGroup rowGroups}.
+ * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
*
* @see View#getBaseline()
*/
@@ -2488,8 +2543,8 @@
/**
* Indicates that a view should expanded to fit the boundaries of its cell group.
- * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and
- * {@link LayoutParams#columnGroup columnGroups}.
+ * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
+ * {@link LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment FILL = new Alignment() {
public int getAlignmentValue(View view, int viewSize) {
@@ -2513,42 +2568,30 @@
/**
* Indicates that a view requests precisely the size specified by its layout parameters.
*
- * @see Group#flexibility
- *
- * @hide
+ * @see Spec#flexibility
*/
- public static final int FIXED = 0;
+ private static final int NONE = 0;
/**
* Indicates that a view's size should lie between its minimum and the size specified by
* its layout parameters.
*
- * @see Group#flexibility
- *
- * @hide
+ * @see Spec#flexibility
*/
- public static final int CAN_SHRINK = 1;
+ private static final int CAN_SHRINK = 1;
/**
* Indicates that a view's size should be greater than or equal to the size specified by
* its layout parameters.
*
- * @see Group#flexibility
+ * @see Spec#flexibility
*/
public static final int CAN_STRETCH = 2;
/**
- * Indicates that a view will ignore its measurement, and can take any size that is greater
- * than its minimum.
- *
- * @see Group#flexibility
- */
- private static final int CAN_SHRINK_OR_STRETCH = CAN_SHRINK | CAN_STRETCH;
-
- /**
* A default value for flexibility.
*
- * @see Group#flexibility
+ * @see Spec#flexibility
*/
private static final int UNDEFINED_FLEXIBILITY = UNDEFINED | CAN_SHRINK | CAN_STRETCH;
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index f48261d..2e0cc62 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -16,21 +16,25 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.ActionProvider;
+import android.view.Menu;
import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
+import com.android.internal.R;
+
/**
* This is a provider for a share action. It is responsible for creating views
- * that enable data sharing and also to perform a default action for showing
- * a share dialog.
+ * that enable data sharing and also to show a sub menu with sharing activities
+ * if the hosting item is placed on the overflow menu.
* <p>
* Here is how to use the action provider with custom backing file in a {@link MenuItem}:
* </p>
@@ -48,15 +52,13 @@
* // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
* // line if using the default share history file is desired.
* mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
- * // Get the action view and hold onto it to set the share intent.
- * mActionView = menuItem.getActionView();
* . . .
* }
*
* // Somewhere in the application.
* public void doShare(Intent shareIntent) {
* // When you want to share set the share intent.
- * mShareActionProvider.setShareIntent(mActionView, shareIntent);
+ * mShareActionProvider.setShareIntent(shareIntent);
* }
* </pre>
* </code>
@@ -71,11 +73,34 @@
public class ShareActionProvider extends ActionProvider {
/**
+ * The default for the maximal number of activities shown in the sub-menu.
+ */
+ private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4;
+
+ /**
+ * The the maximum number activities shown in the sub-menu.
+ */
+ private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT;
+
+ /**
+ * Listener for handling menu item clicks.
+ */
+ private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener =
+ new ShareMenuItemOnMenuItemClickListener();
+
+ /**
* The default name for storing share history.
*/
public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+ /**
+ * Context for accessing resources.
+ */
private final Context mContext;
+
+ /**
+ * The name of the file with share history data.
+ */
private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME;
/**
@@ -93,24 +118,59 @@
*/
@Override
public View onCreateActionView() {
+ // Create the view and set its data model.
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
activityChooserView.setActivityChooserModel(dataModel);
+
+ // Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
+
return activityChooserView;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public boolean hasSubMenu() {
return true;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onPrepareSubMenu(SubMenu subMenu) {
- // TODO Implement me
+ // Clear since the order of items may change.
+ subMenu.clear();
+
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+ PackageManager packageManager = mContext.getPackageManager();
+
+ final int expandedActivityCount = dataModel.getActivityCount();
+ final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount);
+
+ // Populate the sub-menu with a sub set of the activities.
+ for (int i = 0; i < collapsedActivityCount; i++) {
+ ResolveInfo activity = dataModel.getActivity(i);
+ subMenu.add(0, i, i, activity.loadLabel(packageManager))
+ .setIcon(activity.loadIcon(packageManager))
+ .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);
+ }
}
/**
@@ -145,18 +205,29 @@
* </code>
* </p>
*
- * @param actionView An action view created by {@link #onCreateActionView()}.
* @param shareIntent The share intent.
*
* @see Intent#ACTION_SEND
* @see Intent#ACTION_SEND_MULTIPLE
*/
- public void setShareIntent(View actionView, Intent shareIntent) {
- if (actionView instanceof ActivityChooserView) {
- ActivityChooserView activityChooserView = (ActivityChooserView) actionView;
- activityChooserView.getDataModel().setIntent(shareIntent);
- } else {
- throw new IllegalArgumentException("actionView not instance of ActivityChooserView");
+ public void setShareIntent(Intent shareIntent) {
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
+ mShareHistoryFileName);
+ dataModel.setIntent(shareIntent);
+ }
+
+ /**
+ * Reusable listener for handling share item clicks.
+ */
+ private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
+ mShareHistoryFileName);
+ final int itemId = item.getItemId();
+ Intent launchIntent = dataModel.chooseActivity(itemId);
+ mContext.startActivity(launchIntent);
+ return true;
}
}
}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 519acf5..243c605 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -36,6 +36,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Handler;
import android.view.ActionMode;
import android.view.LayoutInflater;
@@ -155,6 +156,13 @@
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
mContentHeight = mActionView.getContentHeight();
+
+ // Older apps get the home button interaction enabled by default.
+ // Newer apps need to enable it explicitly.
+ if (mContext.getApplicationInfo().targetSdkVersion <
+ Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ setHomeButtonEnabled(true);
+ }
}
public void onConfigurationChanged(Configuration newConfig) {
@@ -266,8 +274,8 @@
}
@Override
- public void setDisplayDisableHomeEnabled(boolean disableHome) {
- setDisplayOptions(disableHome ? DISPLAY_DISABLE_HOME : 0, DISPLAY_DISABLE_HOME);
+ public void setHomeButtonEnabled(boolean enable) {
+ mActionView.setHomeButtonEnabled(enable);
}
@Override
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 9c06d69..80f68ac 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -544,6 +544,17 @@
}
setCallback(mPopupPresenterCallback);
+
+ boolean preserveIconSpacing = false;
+ final int count = subMenu.size();
+ for (int i = 0; i < count; i++) {
+ MenuItem childItem = subMenu.getItem(i);
+ if (childItem.isVisible() && childItem.getIcon() != null) {
+ preserveIconSpacing = true;
+ break;
+ }
+ }
+ setForceShowIcon(preserveIconSpacing);
}
@Override
diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
index 56128d4..d1b1dae 100644
--- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
@@ -179,8 +179,10 @@
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
mOpenSubMenuId = 0;
- mOpenSubMenu.dismiss();
- mOpenSubMenu = null;
+ if (mOpenSubMenu != null) {
+ mOpenSubMenu.dismiss();
+ mOpenSubMenu = null;
+ }
}
@Override
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 0c3c605..a1e16d4 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
@@ -50,6 +51,8 @@
private LayoutInflater mInflater;
+ private boolean mForceShowIcon;
+
public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
@@ -99,6 +102,10 @@
setEnabled(itemData.isEnabled());
}
+ public void setForceShowIcon(boolean forceShow) {
+ mPreserveIconSpacing = mForceShowIcon = forceShow;
+ }
+
public void setTitle(CharSequence title) {
if (title != null) {
mTitleView.setText(title);
@@ -189,12 +196,12 @@
}
public void setIcon(Drawable icon) {
- final boolean showIcon = mItemData.shouldShowIcon();
+ final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
if (!showIcon && !mPreserveIconSpacing) {
return;
}
- if (mIconView == null && icon == null) {
+ if (mIconView == null && icon == null && !mPreserveIconSpacing) {
return;
}
@@ -213,6 +220,19 @@
}
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mIconView != null && mPreserveIconSpacing) {
+ // Enforce minimum icon spacing
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+ if (lp.height > 0 && iconLp.width <= 0) {
+ iconLp.width = lp.height;
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
private void insertIconView() {
LayoutInflater inflater = getInflater();
mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon,
@@ -241,7 +261,7 @@
}
public boolean showsIcon() {
- return false;
+ return mForceShowIcon;
}
private LayoutInflater getInflater() {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index b0b49213..164d581 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -799,7 +799,7 @@
if (itemImpl == null || !itemImpl.isEnabled()) {
return false;
}
-
+
boolean invoked = itemImpl.invoke();
if (itemImpl.hasCollapsibleActionView()) {
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 0a7313c..541d101 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -320,11 +320,6 @@
}
void setSubMenu(SubMenuBuilder subMenu) {
- if ((mMenu != null) && (mMenu instanceof SubMenu)) {
- throw new UnsupportedOperationException(
- "Attempt to add a sub-menu to a sub-menu.");
- }
-
mSubMenu = subMenu;
subMenu.setHeaderTitle(getTitle());
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 4ecc828..6265618 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -19,15 +19,16 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.Parcelable;
-import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.ListPopupWindow;
import android.widget.PopupWindow;
@@ -58,6 +59,10 @@
private Callback mPresenterCallback;
+ boolean mForceShowIcon;
+
+ private ViewGroup mMeasureParent;
+
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false);
}
@@ -86,6 +91,10 @@
mAnchorView = anchor;
}
+ public void setForceShowIcon(boolean forceShow) {
+ mForceShowIcon = forceShow;
+ }
+
public void show() {
if (!tryShow()) {
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
@@ -170,7 +179,10 @@
itemType = positionType;
itemView = null;
}
- itemView = adapter.getView(i, itemView, null);
+ if (mMeasureParent == null) {
+ mMeasureParent = new FrameLayout(mContext);
+ }
+ itemView = adapter.getView(i, itemView, mMeasureParent);
itemView.measure(widthMeasureSpec, heightMeasureSpec);
width = Math.max(width, itemView.getMeasuredWidth());
}
@@ -228,6 +240,18 @@
if (subMenu.hasVisibleItems()) {
MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
subPopup.setCallback(mPresenterCallback);
+
+ boolean preserveIconSpacing = false;
+ final int count = subMenu.size();
+ for (int i = 0; i < count; i++) {
+ MenuItem childItem = subMenu.getItem(i);
+ if (childItem.isVisible() && childItem.getIcon() != null) {
+ preserveIconSpacing = true;
+ break;
+ }
+ }
+ subPopup.setForceShowIcon(preserveIconSpacing);
+
if (subPopup.tryShow()) {
if (mPresenterCallback != null) {
mPresenterCallback.onOpenSubMenu(subMenu);
@@ -293,6 +317,9 @@
}
MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+ if (mForceShowIcon) {
+ ((ListMenuItemView) convertView).setForceShowIcon(true);
+ }
itemView.initialize(getItem(position), 0);
return convertView;
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 595753a..58043c9 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -434,22 +434,40 @@
}
}
+ public void setHomeButtonEnabled(boolean enable) {
+ mHomeLayout.setEnabled(enable);
+ // Make sure the home button has an accurate content description for accessibility.
+ if (!enable) {
+ mHomeLayout.setContentDescription(null);
+ } else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_up_description));
+ } else {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_home_description));
+ }
+ }
+
public void setDisplayOptions(int options) {
final int flagsChanged = options ^ mDisplayOptions;
mDisplayOptions = options;
- if ((flagsChanged & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
- final boolean disableHome = (options & ActionBar.DISPLAY_DISABLE_HOME) != 0;
- mHomeLayout.setEnabled(!disableHome);
- }
-
if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
final int vis = showHome ? VISIBLE : GONE;
mHomeLayout.setVisibility(vis);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
- mHomeLayout.setUp((options & ActionBar.DISPLAY_HOME_AS_UP) != 0);
+ final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+ mHomeLayout.setUp(setUp);
+
+ // Showing home as up implicitly enables interaction with it.
+ // In honeycomb it was always enabled, so make this transition
+ // a bit easier for developers in the common case.
+ // (It would be silly to show it as up without responding to it.)
+ if (setUp) {
+ setHomeButtonEnabled(true);
+ }
}
if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -487,7 +505,7 @@
}
// Make sure the home button has an accurate content description for accessibility.
- if ((options & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
+ if (!mHomeLayout.isEnabled()) {
mHomeLayout.setContentDescription(null);
} else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
mHomeLayout.setContentDescription(mContext.getResources().getText(
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 2871073..c446cfb 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -16,24 +16,37 @@
package com.android.server;
+import android.os.SystemProperties;
+import android.util.Log;
+
import dalvik.system.SocketTagger;
+
import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.math.BigInteger;
import java.net.SocketException;
import java.nio.charset.Charsets;
+import libcore.io.IoUtils;
+
/**
* Assigns tags to sockets for traffic stats.
*/
public final class NetworkManagementSocketTagger extends SocketTagger {
+ private static final String TAG = "NetworkManagementSocketTagger";
+ private static final boolean LOGD = false;
- private static final boolean LOGI = false;
- private static final boolean ENABLE_TAGGING = false;
+ /**
+ * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth
+ * controls have been enabled.
+ */
+ // TODO: remove when always enabled, or once socket tagging silently fails.
+ public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled";
private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
- @Override protected SocketTags initialValue() {
+ @Override
+ protected SocketTags initialValue() {
return new SocketTags();
}
};
@@ -50,11 +63,12 @@
threadSocketTags.get().statsUid = uid;
}
- @Override public void tag(FileDescriptor fd) throws SocketException {
+ @Override
+ public void tag(FileDescriptor fd) throws SocketException {
final SocketTags options = threadSocketTags.get();
- if (LOGI) {
- System.logI("tagSocket(" + fd.getInt$() + ") with statsTag="
- + options.statsTag + ", statsUid=" + options.statsUid);
+ if (LOGD) {
+ Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=" + options.statsTag
+ + ", statsUid=" + options.statsUid);
}
try {
// TODO: skip tagging when options would be no-op
@@ -82,9 +96,10 @@
internalModuleCtrl(cmd);
}
- @Override public void untag(FileDescriptor fd) throws SocketException {
- if (LOGI) {
- System.logI("untagSocket(" + fd.getInt$() + ")");
+ @Override
+ public void untag(FileDescriptor fd) throws SocketException {
+ if (LOGD) {
+ Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
}
try {
unTagSocketFd(fd);
@@ -125,31 +140,22 @@
*
*/
private void internalModuleCtrl(String cmd) throws IOException {
- if (!ENABLE_TAGGING) return;
+ if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
- final FileOutputStream procOut;
- // TODO: Use something like
- // android.os.SystemProperties.getInt("persist.bandwidth.enable", 0)
- // to see if tagging should happen or not.
+ // TODO: migrate to native library for tagging commands
+ FileOutputStream procOut = null;
try {
procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl");
- } catch (FileNotFoundException e) {
- if (LOGI) {
- System.logI("Can't talk to kernel module:" + e);
- }
- return;
- }
- try {
procOut.write(cmd.getBytes(Charsets.US_ASCII));
} finally {
- procOut.close();
+ IoUtils.closeQuietly(procOut);
}
}
/**
* Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned
* base-10 format like {@code 2147483647}. Currently strips signed bit to
- * avoid using {@link java.math.BigInteger}.
+ * avoid using {@link BigInteger}.
*/
public static String tagToKernel(int tag) {
// TODO: eventually write in hex, since that's what proc exports
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a61217a..23c6da7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -623,16 +623,9 @@
}
/* enable debugging; set suspend=y to pause during VM init */
-#ifdef HAVE_ANDROID_OS
/* use android ADB transport */
opt.optionString =
"-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
-#else
- /* use TCP socket; address=0 means start at port 8000 and probe up */
- LOGI("Using TCP socket for JDWP\n");
- opt.optionString =
- "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0";
-#endif
mOptions.add(opt);
char enableDPBuf[sizeof("-Xdeadlockpredict:") + PROPERTY_VALUE_MAX];
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 258ffa5..ea35006 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -116,7 +116,7 @@
bool forcePurgeable = false) {
int sampleSize = 1;
SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
- SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+ SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
bool doDither = true;
bool isMutable = false;
bool isPurgeable = forcePurgeable ||
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index d54981e..c22b071 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -44,7 +44,6 @@
// Returns an ASCII decimal number read from the specified file, -1 on error.
static jlong readNumber(char const* filename) {
-#ifdef HAVE_ANDROID_OS
char buf[80];
int fd = open(filename, O_RDONLY);
if (fd < 0) {
@@ -62,9 +61,6 @@
close(fd);
buf[len] = '\0';
return atoll(buf);
-#else // Simulator
- return -1;
-#endif
}
static const char* mobile_iface_list[] = {
@@ -101,7 +97,6 @@
// Returns the sum of numbers from the specified path under /sys/class/net/*,
// -1 if no such file exists.
static jlong readTotal(char const* suffix) {
-#ifdef HAVE_ANDROID_OS
char filename[PATH_MAX] = "/sys/class/net/";
DIR *dir = opendir(filename);
if (dir == NULL) {
@@ -123,9 +118,6 @@
closedir(dir);
return total;
-#else // Simulator
- return -1;
-#endif
}
// Mobile stats get accessed a lot more often than total stats.
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 2297834..a4432c3 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -278,7 +278,6 @@
jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
-#ifdef HAVE_ANDROID_OS
/* pulled out of bionic */
extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
@@ -414,7 +413,6 @@
fprintf(fp, "END\n");
}
-#endif /*HAVE_ANDROID_OS*/
/*
* Dump the native heap, writing human-readable output to the specified
@@ -449,13 +447,9 @@
return;
}
-#ifdef HAVE_ANDROID_OS
LOGD("Native heap dump starting...\n");
dumpNativeHeap(fp);
LOGD("Native heap dump complete.\n");
-#else
- fprintf(fp, "Native heap dump not available on this platform\n");
-#endif
fclose(fp);
}
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index 89dce89..8d65cbc 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -28,11 +28,8 @@
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
-
-#if HAVE_ANDROID_OS
#include <sys/ioctl.h>
#include <linux/msdos_fs.h>
-#endif
namespace android {
@@ -53,7 +50,6 @@
jstring file, jint mode,
jint uid, jint gid)
{
- #if HAVE_ANDROID_OS
const jchar* str = env->GetStringCritical(file, 0);
String8 file8;
if (str) {
@@ -70,15 +66,11 @@
}
}
return chmod(file8.string(), mode) == 0 ? 0 : errno;
- #else
- return ENOSYS;
- #endif
}
jint android_os_FileUtils_getPermissions(JNIEnv* env, jobject clazz,
jstring file, jintArray outArray)
{
- #if HAVE_ANDROID_OS
const jchar* str = env->GetStringCritical(file, 0);
String8 file8;
if (str) {
@@ -107,9 +99,6 @@
}
env->ReleasePrimitiveArrayCritical(outArray, array, 0);
return 0;
- #else
- return ENOSYS;
- #endif
}
jint android_os_FileUtils_setUMask(JNIEnv* env, jobject clazz, jint mask)
@@ -119,7 +108,6 @@
jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path)
{
- #if HAVE_ANDROID_OS
if (path == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return -1;
@@ -137,9 +125,6 @@
env->ReleaseStringUTFChars(path, pathStr);
return result;
- #else
- return -1;
- #endif
}
jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) {
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index 9ae4a63..dc16990 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -70,16 +70,11 @@
static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
{
-#ifdef HAVE_ANDROID_OS
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
-#else
- sync();
-#endif
}
static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)
{
-#ifdef HAVE_ANDROID_OS
if (reason == NULL) {
android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
@@ -88,9 +83,6 @@
env->ReleaseStringUTFChars(reason, chars); // In case it fails.
}
jniThrowIOException(env, errno);
-#else
- sync();
-#endif
}
static JNINativeMethod method_table[] = {
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 2b09442..8f84b81 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1115,7 +1115,7 @@
LOGV("... uuid = %s", uuid);
dbus_message_ref(msg); // increment refcount because we pass to java
- env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
+ env->CallVoidMethod(nat->me, method_onAgentAuthorize,
env->NewStringUTF(object_path), env->NewStringUTF(uuid),
int(msg));
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 0fbe0e7..2c7bb84 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -58,9 +58,6 @@
static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
{
-#ifndef HAVE_ANDROID_OS
- return false;
-#else /* HAVE_ANDROID_OS */
int len;
char key[PROPERTY_KEY_MAX];
char buf[PROPERTY_VALUE_MAX];
@@ -93,7 +90,6 @@
len = property_get(key, buf, "");
int logLevel = toLevel(buf);
return (logLevel >= 0 && level >= logLevel) ? true : false;
-#endif /* HAVE_ANDROID_OS */
}
/*
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index d1ba2d1..47d343a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -352,20 +352,12 @@
jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
{
- #if HAVE_ANDROID_OS
return setuid(uid) == 0 ? 0 : errno;
- #else
- return ENOSYS;
- #endif
}
jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
{
- #if HAVE_ANDROID_OS
return setgid(uid) == 0 ? 0 : errno;
- #else
- return ENOSYS;
- #endif
}
static int pid_compare(const void* v1, const void* v2)
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index 86fd9cb..7e5dede 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -27,13 +27,11 @@
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
-#ifdef HAVE_ANDROID_OS
#include <linux/capability.h>
#include <linux/prctl.h>
#include <sys/prctl.h>
extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
-#endif
namespace android {
@@ -168,7 +166,6 @@
static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
jobject clazz, jlong permitted, jlong effective)
{
-#ifdef HAVE_ANDROID_OS
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata;
int err;
@@ -190,15 +187,11 @@
jniThrowIOException(env, errno);
return;
}
-#endif /* HAVE_ANDROID_OS */
}
static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
jobject clazz, jint pid)
{
-#ifndef HAVE_ANDROID_OS
- return (jlong)0;
-#else
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata;
int err;
@@ -217,7 +210,6 @@
}
return (jlong) capdata.permitted;
-#endif /* HAVE_ANDROID_OS */
}
static jint com_android_internal_os_ZygoteInit_selectReadable (
diff --git a/core/res/res/layout/activity_chooser_list_footer.xml b/core/res/res/layout/activity_chooser_list_footer.xml
deleted file mode 100644
index c05ba1a..0000000
--- a/core/res/res/layout/activity_chooser_list_footer.xml
+++ /dev/null
@@ -1,42 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/list_footer"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="vertical">
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="2dip"
- android:background="@android:color/holo_blue_light" />
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="48dip"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:duplicateParentState="true"
- android:singleLine="true"
- android:text="@string/activity_chooser_view_see_all" />
-
-</LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_list_header.xml b/core/res/res/layout/activity_chooser_list_header.xml
deleted file mode 100644
index 0fb256f..0000000
--- a/core/res/res/layout/activity_chooser_list_header.xml
+++ /dev/null
@@ -1,41 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/list_header"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="?android:attr/dropdownListPreferredItemHeight"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:duplicateParentState="true"
- android:singleLine="true" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="2dip"
- android:src="@drawable/divider_strong_holo" />
-
-</LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml
index ccf49fc..902b3c0 100644
--- a/core/res/res/layout/activity_chooser_view.xml
+++ b/core/res/res/layout/activity_chooser_view.xml
@@ -25,11 +25,11 @@
<ImageButton android:id="@+id/default_activity_button"
android:layout_width="32dip"
android:layout_height="32dip"
- android:layout_marginLeft="16dip" />
+ android:layout_marginRight="8dip" />
<ImageButton android:id="@+id/expand_activities_button"
android:layout_width="32dip"
android:layout_height="32dip"
- android:layout_marginLeft="16dip" />
+ android:layout_marginLeft="8dip" />
</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 61b7e70..f90044e 100644
--- a/core/res/res/layout/activity_chooser_view_list_item.xml
+++ b/core/res/res/layout/activity_chooser_view_list_item.xml
@@ -18,26 +18,35 @@
android:id="@+id/list_item"
android:layout_width="match_parent"
android:layout_height="?android:attr/dropdownListPreferredItemHeight"
- android:gravity="center_vertical"
android:paddingLeft="16dip"
- android:paddingRight="16dip">
+ android:paddingRight="16dip"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:orientation="vertical" >
- <ImageView
- android:id="@+id/icon"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="8dip"
- android:duplicateParentState="true" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:duplicateParentState="true" >
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:singleLine="true"
- android:duplicateParentState="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="8dip"
+ android:duplicateParentState="true" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
+ android:duplicateParentState="true"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/list_menu_item_icon.xml b/core/res/res/layout/list_menu_item_icon.xml
index 6ff14dd..a885211 100644
--- a/core/res/res/layout/list_menu_item_icon.xml
+++ b/core/res/res/layout/list_menu_item_icon.xml
@@ -19,6 +19,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginRight="8dip"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="-8dip"
+ android:scaleType="center"
android:duplicateParentState="true" />
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index fef017d..1a12c01 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -18,7 +18,6 @@
android:layout_width="match_parent"
android:layout_height="?android:attr/dropdownListPreferredItemHeight"
android:minWidth="196dip"
- android:paddingLeft="16dip"
android:paddingRight="16dip">
<!-- Icon will be inserted here. -->
@@ -29,6 +28,7 @@
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
+ android:layout_marginLeft="16dip"
android:duplicateParentState="true">
<TextView
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 0f04a67..bcf1991 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,6 +22,15 @@
<!-- Do not translate. These are all of the drawable resources that should be preloaded by
the zygote process before it starts forking application processes. -->
<array name="preloaded_drawables">
+ <item>@drawable/spinner_black_16</item>
+ <item>@drawable/spinner_black_20</item>
+ <item>@drawable/spinner_black_48</item>
+ <item>@drawable/spinner_black_76</item>
+ <item>@drawable/spinner_white_16</item>
+ <item>@drawable/spinner_white_48</item>
+ <item>@drawable/spinner_white_76</item>
+ <item>@drawable/toast_frame</item>
+ <item>@drawable/toast_frame_holo</item>
<item>@drawable/btn_check_on_selected</item>
<item>@drawable/btn_check_on_pressed_holo_light</item>
<item>@drawable/btn_check_on_pressed_holo_dark</item>
@@ -109,6 +118,11 @@
<item>@drawable/btn_default_disabled_holo_dark</item>
<item>@drawable/btn_default_disabled_focused_holo_light</item>
<item>@drawable/btn_default_disabled_focused_holo_dark</item>
+ <item>@drawable/btn_dropdown_disabled</item>
+ <item>@drawable/btn_dropdown_disabled_focused</item>
+ <item>@drawable/btn_dropdown_normal</item>
+ <item>@drawable/btn_dropdown_pressed</item>
+ <item>@drawable/btn_dropdown_selected</item>
<item>@drawable/btn_toggle_on_pressed_holo_light</item>
<item>@drawable/btn_toggle_on_pressed_holo_dark</item>
<item>@drawable/btn_toggle_on_normal_holo_light</item>
@@ -141,6 +155,10 @@
<item>@drawable/edit_text_holo_light</item>
<item>@drawable/edit_text_holo_dark</item>
<item>@drawable/edit_text</item>
+ <item>@drawable/expander_close_holo_dark</item>
+ <item>@drawable/expander_close_holo_light</item>
+ <item>@drawable/expander_ic_maximized</item>
+ <item>@drawable/expander_ic_minimized</item>
<item>@drawable/expander_group</item>
<item>@drawable/expander_group_holo_dark</item>
<item>@drawable/expander_group_holo_light</item>
@@ -157,6 +175,8 @@
<item>@drawable/menu_background_fill_parent_width</item>
<item>@drawable/menu_submenu_background</item>
<item>@drawable/menu_selector</item>
+ <item>@drawable/overscroll_edge</item>
+ <item>@drawable/overscroll_glow</item>
<item>@drawable/panel_background</item>
<item>@drawable/popup_bottom_bright</item>
<item>@drawable/popup_bottom_dark</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cfc5041..9613712 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3349,7 +3349,7 @@
<!-- The row span: the difference between the bottom and top
boundaries delimiting the group of cells occupied by this view.
The default is one.
- See {@link android.widget.GridLayout.Group}. -->
+ See {@link android.widget.GridLayout.Spec}. -->
<attr name="layout_rowSpan" format="integer" min="1" />
<!-- The column boundary delimiting the left of the group of cells
occupied by this view. -->
@@ -3357,23 +3357,21 @@
<!-- The column span: the difference between the right and left
boundaries delimiting the group of cells occupied by this view.
The default is one.
- See {@link android.widget.GridLayout.Group}. -->
+ See {@link android.widget.GridLayout.Spec}. -->
<attr name="layout_columnSpan" format="integer" min="1" />
<!-- Gravity specifies how a component should be placed in its group of cells.
The default is LEFT | BASELINE.
See {@link android.widget.GridLayout.LayoutParams#setGravity(int)}. -->
<attr name="layout_gravity" />
<!-- A value specifying how much deficit or excess width this component can accomodate.
- The default is FIXED.
- See {@link android.widget.GridLayout.Group#flexibility}.-->
+ The default is FIXED. -->
<attr name="layout_columnFlexibility" >
<!-- If possible, width should be greater than or equal to the specified width.
See {@link android.widget.GridLayout#CAN_STRETCH}. -->
<enum name="canStretch" value="2" />
</attr>
<!-- A value specifying how much deficit or excess height this component can accomodate.
- The default is FIXED.
- See {@link android.widget.GridLayout.Group#flexibility}.-->
+ The default is FIXED. -->
<attr name="layout_rowFlexibility" >
<!-- If possible, height should be greater than or equal to the specified height.
See {@link android.widget.GridLayout#CAN_STRETCH}. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a5e5f70..0f6e5cf 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -133,4 +133,7 @@
<!-- Size of right margin on Unsecure unlock LockScreen -->
<dimen name="keyguard_lockscreen_status_line_font_right_margin">45dip</dimen>
+ <!-- Minimum popup width for selecting an activity in ActivityChooserDialog/ActivityChooserView. -->
+ <dimen name="activity_chooser_popup_min_width">200dip</dimen>
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 70c204e..d0e3f14 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3036,9 +3036,10 @@
<!-- Title for a button to expand the list of activities in ActivityChooserView [CHAR LIMIT=25] -->
<string name="activity_chooser_view_see_all">See all...</string>
- <!-- Title for a message that there are no activities in ActivityChooserView [CHAR LIMIT=25] -->
- <string name="activity_chooser_view_no_activities">No activities</string>
- <!-- Title for a message that prompts selection of a default share handler in ActivityChooserView [CHAR LIMIT=25] -->
- <string name="activity_chooser_view_select_default">Select default</string>
+ <!-- Title default for a dialog showing possible activities in ActivityChooserView [CHAR LIMIT=25] -->
+ <string name="activity_chooser_view_dialog_title_default">Select activity</string>
+
+ <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] -->
+ <string name="share_action_provider_share_with">Share with...</string>
</resources>
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index a109dc8..78d12ef 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -503,7 +503,7 @@
<ul>
<li><code>V</code> — Verbose (lowest priority)</li>
<li><code>D</code> — Debug</li>
- <li><code>I</code> — Info</li>
+ <li><code>I</code> — Info (default priority)</li>
<li><code>W</code> — Warning</li>
<li><code>E</code> — Error</li>
<li><code>F</code> — Fatal</li>
@@ -520,7 +520,7 @@
<p>To reduce the log output to a manageable level, you can restrict log output using <em>filter expressions</em>. Filter expressions let you indicate to the system the tags-priority combinations that you are interested in — the system suppresses other messages for the specified tags. </p>
-<p>A filter expression follows this format <code>tag:priority ...</code>, where <code>tag</code> indicates the tag of interest and <code>priority</code> indicates the <em>minimum</em> level of priority to report for that tag. Messages for that tag at or above the specified priority are written to the log. You can supply any number of <code>tag:priority</code> specifications in a single filter expression. The series of specifications is whitespace-delimited. </p>
+<p>A filter expression follows this format <code>tag:priority ...</code>, where <code>tag</code> indicates the tag of interest and <code>priority</code> indicates the <em>minimum</em> level of priority to report for that tag. Messages for that tag at or above the specified priority are written to the log. You can supply any number of <code>tag:priority</code> specifications in a single filter expression. The series of specifications is whitespace-delimited. The default output is to show all log messages with the Info priority (*:I).</p>
<p>Here's an example of a filter expression that suppresses all log messages except those with the tag "ActivityManager", at priority "Info" or above, and all log messages with tag "MyApp", with priority "Debug" or above:</p>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 3ec174e..f7dbe30 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -256,8 +256,7 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/renderscript/index.html">
<span class="en">RenderScript</span>
- </a>
- <span class="new">new!</span></div>
+ </a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/renderscript/graphics.html">
<span class="en">3D Graphics</span>
@@ -304,11 +303,9 @@
<!--<li><a style="color:gray;">Localization</a></li> -->
<li><a href="<?cs var:toroot ?>guide/topics/appwidgets/index.html">
<span class="en">App Widgets</span></a>
- <span class="new">updated</span>
</li>
<li><a href="<?cs var:toroot?>guide/topics/wireless/bluetooth.html">
<span class="en">Bluetooth</span></a>
- <span class="new">updated</span>
</li>
<li><a href="<?cs var:toroot?>guide/topics/nfc/index.html">
<span class="en">Near Field Communication</span>
@@ -316,7 +313,6 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot?>guide/topics/usb/index.html">
<span class="en">USB</span></a>
- <span class="new">new!</span>
</div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/usb/accessory.html">Accessory</a></li>
@@ -341,7 +337,6 @@
</li>
<li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
<span class="en">Device Administration</span></a>
- <span class="new">updated</span>
</li>
<li class="toggle-list">
<div>
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 3fcfa89..362ee16 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -74,6 +74,6 @@
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on May 6, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p>
</div>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index e980ca5..97df84f 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
ndk=true
-ndk.win_download=android-ndk-r5c-windows.zip
-ndk.win_bytes=61627716
-ndk.win_checksum=2c7423842fa0f46871eab118495d4b45
+ndk.win_download=android-ndk-r6-windows.zip
+ndk.win_bytes=67642809
+ndk.win_checksum=9c7d5ccc02151a3e5e950c70dc05ac6d
-ndk.mac_download=android-ndk-r5c-darwin-x86.tar.bz2
-ndk.mac_bytes=50714712
-ndk.mac_checksum=183bfbbd85cf8e4c0bd7531e8803e75d
+ndk.mac_download=android-ndk-r6-darwin-x86.tar.bz2
+ndk.mac_bytes=52682746
+ndk.mac_checksum=a154905e49a6246abd823b75b6eda738
-ndk.linux_download=android-ndk-r5c-linux-x86.tar.bz2
-ndk.linux_bytes=44539890
-ndk.linux_checksum=7659dfdc97026ed1d913e224d0531f61
+ndk.linux_download=android-ndk-r6-linux-x86.tar.bz2
+ndk.linux_bytes=46425290
+ndk.linux_checksum=ff0a43085fe206696d5cdcef3f4f4637
page.title=Android NDK
@jd:body
@@ -62,6 +62,58 @@
<div class="toggleable open">
<a href="#" onclick="return toggleDiv(this)"><img src=
"{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
+ Android NDK, Revision 6</a> <em>(July 2011)</em>
+
+ <div class="toggleme">
+ <p>This release of the NDK includes support for the x86 ABI and other minor changes.
+ For detailed information describing the changes in this release, read the
+ <code>CHANGES.HTML</code> document included in the NDK package.
+ </p>
+ <dl>
+ <dt>General notes:</dt>
+ <dd>
+ <ul>
+ <li>Adds support for the x86 ABI, which allows you to generate machine code
+ that runs on compatible x86-based Android devices. Major features for x86
+ include x86-specific toolchains, system headers, libraries and
+ debugging support. For all of the details regarding x86 support,
+ see <code>docs/CPU-X86.html</code> in the NDK package.
+
+ <p>By default, code is generated for ARM-based devices, but you can add x86 to your
+ <code>APP_ABI</code> definition in your <code>Application.mk</code> file to build
+ for x86 platforms. For example, the following line instructs <code>ndk-build</code>
+ to build your code for three distinct ABIs:</p>
+
+ <pre>APP_ABI := armeabi armeabi-v7a x86</pre>
+
+ <p>Unless you rely on ARM-based assembly sources, you shouldn't need to touch
+ your <code>Android.mk</code> files to build x86 machine code.</p>
+
+ </li>
+
+ <li>You can build a standalone x86 toolchain using the <code>--toolchain=x86-4.4.3</code>
+ option when calling <code>make-standalone-toolchain.sh</code>. See
+ <code>docs/STANDALONE-TOOLCHAIN.html</code> for more details.
+ </li>
+ <li>The new <code>ndk-stack</code> tool lets you translate stack traces in
+ <code>logcat</code> that are generated by native code. The tool translates
+ instruction addresses into a readable format that contains things such
+ as the function, source file, and line number corresponding to each stack frame.
+ For more information and a usage example, see <code>docs/NDK-STACK.html</code>.
+ </li>
+ </ul>
+ </dd>
+ <dt>Other changes:</dt>
+ <dd><code>arm-eabi-4.4.0</code>, which had been deprecated since NDK r5, has been
+ removed from the NDK distribution.</dd>
+
+ </dl>
+ </div>
+ </div>
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)"><img src=
+ "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px">
Android NDK, Revision 5c</a> <em>(June 2011)</em>
<div class="toggleme">
diff --git a/docs/html/sdk/ndk/overview.jd b/docs/html/sdk/ndk/overview.jd
index 2562a25..93c664d 100644
--- a/docs/html/sdk/ndk/overview.jd
+++ b/docs/html/sdk/ndk/overview.jd
@@ -53,11 +53,7 @@
<li>ARMv7-A (including Thumb-2 and VFPv3-D16 instructions, with optional support for
NEON/VFPv3-D32 instructions)</li>
- </ul>
- <p>Future releases of the NDK will also support:</p>
-
- <ul>
<li>x86 instructions (see CPU-ARCH-ABIS.HTML for more information)</li>
</ul>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 0607aad..0539adb 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -77,7 +77,7 @@
<ul>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>sdk/android-3.1.html">
- <span class="en">Android 3.1 Platform</span></a> <span class="new">new!</span></div>
+ <span class="en">Android 3.1 Platform</span></a></div>
<ul>
<li><a href="<?cs var:toroot ?>sdk/android-3.1-highlights.html">Platform Highlights</a></li>
<li><a href="<?cs var:toroot ?>sdk/api_diff/12/changes.html">API Differences Report »</a></li>
@@ -91,7 +91,7 @@
<li><a href="<?cs var:toroot ?>sdk/api_diff/11/changes.html">API Differences Report »</a></li>
</ul>
</li>
- <li><a href="<?cs var:toroot ?>sdk/android-2.3.4.html">Android 2.3.4 Platform</span></a> <span class="new">new!</span></li>
+ <li><a href="<?cs var:toroot ?>sdk/android-2.3.4.html">Android 2.3.4 Platform</span></a></li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>sdk/android-2.3.3.html">
<span class="en">Android 2.3.3 Platform</span></a></div>
@@ -137,8 +137,8 @@
<li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r12</a> <span
class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li>
- <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Compatibility Library, r2</a> <span
-class="new">new!</span></li>
+ <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Compatibility Library,
+r2</a></li>
</ul>
</li>
<li>
@@ -175,7 +175,7 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5c <span
+ <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6 <span
class="new">new!</span></a>
</li>
<li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 3c65147..02ad703 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -184,6 +184,11 @@
uint32_t flags = 0);
};
+struct CodecProfileLevel {
+ OMX_U32 mProfile;
+ OMX_U32 mLevel;
+};
+
} // namespace android
#endif // ANDROID_IOMX_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7f3c497..a042ddb 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -336,11 +336,6 @@
OMXCodec &operator=(const OMXCodec &);
};
-struct CodecProfileLevel {
- OMX_U32 mProfile;
- OMX_U32 mLevel;
-};
-
struct CodecCapabilities {
String8 mComponentName;
Vector<CodecProfileLevel> mProfileLevels;
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
deleted file mode 100644
index bc67156..0000000
--- a/include/media/stagefright/ShoutcastSource.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SHOUTCAST_SOURCE_H_
-
-#define SHOUTCAST_SOURCE_H_
-
-#include <sys/types.h>
-
-#include <media/stagefright/MediaSource.h>
-
-namespace android {
-
-class HTTPStream;
-class MediaBufferGroup;
-
-class ShoutcastSource : public MediaSource {
-public:
- // Assumes ownership of "http".
- ShoutcastSource(HTTPStream *http);
-
- virtual status_t start(MetaData *params = NULL);
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
-protected:
- virtual ~ShoutcastSource();
-
-private:
- HTTPStream *mHttp;
- size_t mMetaDataOffset;
- size_t mBytesUntilMetaData;
-
- MediaBufferGroup *mGroup;
- bool mStarted;
-
- ShoutcastSource(const ShoutcastSource &);
- ShoutcastSource &operator= (const ShoutcastSource &);
-};
-
-} // namespace android
-
-#endif // SHOUTCAST_SOURCE_H_
-
diff --git a/include/private/binder/binder_module.h b/include/private/binder/binder_module.h
index fdf327e..a8dd64f 100644
--- a/include/private/binder/binder_module.h
+++ b/include/private/binder/binder_module.h
@@ -21,126 +21,11 @@
namespace android {
#endif
-#if defined(HAVE_ANDROID_OS)
-
/* obtain structures and constants from the kernel header */
#include <sys/ioctl.h>
#include <linux/binder.h>
-#else
-
-/* Some parts of the simulator need fake versions of this
- * stuff in order to compile. Really this should go away
- * entirely...
- */
-
-#define BINDER_CURRENT_PROTOCOL_VERSION 7
-
-#define BINDER_TYPE_BINDER 1
-#define BINDER_TYPE_WEAK_BINDER 2
-#define BINDER_TYPE_HANDLE 3
-#define BINDER_TYPE_WEAK_HANDLE 4
-#define BINDER_TYPE_FD 5
-
-struct flat_binder_object {
- unsigned long type;
- unsigned long flags;
- union {
- void *binder;
- signed long handle;
- };
- void *cookie;
-};
-
-struct binder_write_read {
- signed long write_size;
- signed long write_consumed;
- unsigned long write_buffer;
- signed long read_size;
- signed long read_consumed;
- unsigned long read_buffer;
-};
-
-struct binder_transaction_data {
- union {
- size_t handle;
- void *ptr;
- } target;
- void *cookie;
- unsigned int code;
-
- unsigned int flags;
- pid_t sender_pid;
- uid_t sender_euid;
- size_t data_size;
- size_t offsets_size;
-
- union {
- struct {
- const void *buffer;
- const void *offsets;
- } ptr;
- uint8_t buf[8];
- } data;
-};
-
-enum transaction_flags {
- TF_ONE_WAY = 0x01,
- TF_ROOT_OBJECT = 0x04,
- TF_STATUS_CODE = 0x08,
- TF_ACCEPT_FDS = 0x10,
-};
-
-
-enum {
- FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
- FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
-};
-
-enum BinderDriverReturnProtocol {
- BR_ERROR,
- BR_OK,
- BR_TRANSACTION,
- BR_REPLY,
- BR_ACQUIRE_RESULT,
- BR_DEAD_REPLY,
- BR_TRANSACTION_COMPLETE,
- BR_INCREFS,
- BR_ACQUIRE,
- BR_RELEASE,
- BR_DECREFS,
- BR_ATTEMPT_ACQUIRE,
- BR_NOOP,
- BR_SPAWN_LOOPER,
- BR_FINISHED,
- BR_DEAD_BINDER,
- BR_CLEAR_DEATH_NOTIFICATION_DONE,
- BR_FAILED_REPLY,
-};
-
-enum BinderDriverCommandProtocol {
- BC_TRANSACTION,
- BC_REPLY,
- BC_ACQUIRE_RESULT,
- BC_FREE_BUFFER,
- BC_INCREFS,
- BC_ACQUIRE,
- BC_RELEASE,
- BC_DECREFS,
- BC_INCREFS_DONE,
- BC_ACQUIRE_DONE,
- BC_ATTEMPT_ACQUIRE,
- BC_REGISTER_LOOPER,
- BC_ENTER_LOOPER,
- BC_EXIT_LOOPER,
- BC_REQUEST_DEATH_NOTIFICATION,
- BC_CLEAR_DEATH_NOTIFICATION,
- BC_DEAD_BINDER_DONE,
-};
-
-#endif
-
#ifdef __cplusplus
} // namespace android
#endif
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 7264ac4..f5288c8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -154,11 +154,7 @@
mBinderContextUserData = userData;
int dummy = 0;
-#if defined(HAVE_ANDROID_OS)
status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
-#else
- status_t result = INVALID_OPERATION;
-#endif
if (result == 0) {
mManagesContexts = true;
} else if (result == -1) {
@@ -304,12 +300,7 @@
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers;
-#if defined(HAVE_ANDROID_OS)
status_t result = ioctl(fd, BINDER_VERSION, &vers);
-#else
- status_t result = -1;
- errno = EPERM;
-#endif
if (result == -1) {
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
@@ -320,14 +311,11 @@
close(fd);
fd = -1;
}
-#if defined(HAVE_ANDROID_OS)
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
-#endif
-
} else {
LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 563d7e4..e232ddd 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -73,7 +73,6 @@
String8 stringLog;
dumpMemoryUsage(stringLog);
LOGD("%s", stringLog.string());
- delete stringLog;
}
void Caches::dumpMemoryUsage(String8 &log) {
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7c10518..47049e2 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -43,7 +43,7 @@
kDebugDisabled = 0,
kDebugMemory = 1,
kDebugCaches = 2,
- kDebugMoreCaches = 3
+ kDebugMoreCaches = kDebugMemory | kDebugCaches
};
// These properties are defined in mega-bytes
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 44e9d89..8798612 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -693,7 +693,9 @@
LOGV("rsContextCreateGL %p", vdev);
Device * dev = static_cast<Device *>(vdev);
Context *rsc = Context::createContext(dev, &sc);
- rsc->setDPI(dpi);
+ if (rsc) {
+ rsc->setDPI(dpi);
+ }
LOGV("rsContextCreateGL ret %p ", rsc);
return rsc;
}
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index c46d6f4..1e602e9 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -83,7 +83,9 @@
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
status_t result;
- int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
+ String8 ashmemName("InputChannel ");
+ ashmemName.append(name);
+ int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
if (serverAshmemFd < 0) {
result = -errno;
LOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 87549fe..7ef30f9 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -481,6 +481,14 @@
return sprintf(buf, "%d %s=%s\n", len, key, value);
}
+// Wire format to the backup manager service is chunked: each chunk is prefixed by
+// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
+void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
+ uint32_t chunk_size_no = htonl(size);
+ writer->WriteEntityData(&chunk_size_no, 4);
+ if (size != 0) writer->WriteEntityData(buffer, size);
+}
+
int write_tarfile(const String8& packageName, const String8& domain,
const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
{
@@ -660,16 +668,16 @@
// Checksum and write the pax block header
calc_tar_checksum(paxHeader);
- writer->WriteEntityData(paxHeader, 512);
+ send_tarfile_chunk(writer, paxHeader, 512);
// Now write the pax data itself
int paxblocks = (paxLen + 511) / 512;
- writer->WriteEntityData(paxData, 512 * paxblocks);
+ send_tarfile_chunk(writer, paxData, 512 * paxblocks);
}
// Checksum and write the 512-byte ustar file header block to the output
calc_tar_checksum(buf);
- writer->WriteEntityData(buf, 512);
+ send_tarfile_chunk(writer, buf, 512);
// Now write the file data itself, for real files. We honor tar's convention that
// only full 512-byte blocks are sent to write().
@@ -699,7 +707,7 @@
memset(buf + nRead, 0, remainder);
nRead += remainder;
}
- writer->WriteEntityData(buf, nRead);
+ send_tarfile_chunk(writer, buf, nRead);
toWrite -= nRead;
}
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b97c3c4..b20a6e9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -32,24 +32,25 @@
* It allows to stream PCM audio buffers to the audio hardware for playback. This is
* achieved by "pushing" the data to the AudioTrack object using one of the
* {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
- *
+ *
* <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
* In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
- * one of the write() methods. These are blocking and return when the data has been transferred
- * from the Java layer to the native layer and queued for playback. The streaming mode
- * is most useful when playing blocks of audio data that for instance are:
+ * one of the {@code write()} methods. These are blocking and return when the data has been
+ * transferred from the Java layer to the native layer and queued for playback. The streaming
+ * mode is most useful when playing blocks of audio data that for instance are:
+ *
* <ul>
* <li>too big to fit in memory because of the duration of the sound to play,</li>
* <li>too big to fit in memory because of the characteristics of the audio data
* (high sampling rate, bits per sample ...)</li>
* <li>received or generated while previously queued audio is playing.</li>
* </ul>
+ *
* The static mode is to be chosen when dealing with short sounds that fit in memory and
- * that need to be played with the smallest latency possible. AudioTrack instances in static mode
- * can play the sound without the need to transfer the audio data from Java to native layer
- * each time the sound is to be played. The static mode will therefore be preferred for UI and
- * game sounds that are played often, and with the smallest overhead possible.
- *
+ * that need to be played with the smallest latency possible. The static mode will
+ * therefore be preferred for UI and game sounds that are played often, and with the
+ * smallest overhead possible.
+ *
* <p>Upon creation, an AudioTrack object initializes its associated audio buffer.
* The size of this buffer, specified during the construction, determines how long an AudioTrack
* can play before running out of data.<br>
@@ -816,6 +817,7 @@
//--------------------
/**
* Starts playing an AudioTrack.
+ *
* @throws IllegalStateException
*/
public void play()
@@ -832,6 +834,7 @@
/**
* Stops playing the audio data.
+ *
* @throws IllegalStateException
*/
public void stop()
@@ -848,7 +851,10 @@
}
/**
- * Pauses the playback of the audio data.
+ * Pauses the playback of the audio data. Data that has not been played
+ * back will not be discarded. Subsequent calls to {@link #play} will play
+ * this data back.
+ *
* @throws IllegalStateException
*/
public void pause()
@@ -871,9 +877,9 @@
//--------------------
/**
- * Flushes the audio data currently queued for playback.
+ * Flushes the audio data currently queued for playback. Any data that has
+ * not been played back will be discarded.
*/
-
public void flush() {
if (mState == STATE_INITIALIZED) {
// flush the data in native layer
@@ -883,9 +889,14 @@
}
/**
- * Writes the audio data to the audio hardware for playback.
+ * Writes the audio data to the audio hardware for playback. Will block until
+ * all data has been written to the audio mixer.
+ * Note that the actual playback of this data might occur after this function
+ * returns. This function is thread safe with respect to {@link #stop} calls,
+ * in which case all of the specified data might not be written to the mixer.
+ *
* @param audioData the array that holds the data to play.
- * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
+ * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
* starts.
* @param sizeInBytes the number of bytes to read in audioData after the offset.
* @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
@@ -914,7 +925,12 @@
/**
- * Writes the audio data to the audio hardware for playback.
+ * Writes the audio data to the audio hardware for playback. Will block until
+ * all data has been written to the audio mixer.
+ * Note that the actual playback of this data might occur after this function
+ * returns. This function is thread safe with respect to {@link #stop} calls,
+ * in which case all of the specified data might not be written to the mixer.
+ *
* @param audioData the array that holds the data to play.
* @param offsetInShorts the offset expressed in shorts in audioData where the data to play
* starts.
@@ -988,7 +1004,7 @@
/**
* Sets the send level of the audio track to the attached auxiliary effect
- * {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
+ * {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
* <p>By default the send level is 0, so even if an effect is attached to the player
* this method must be called for the effect to be applied.
* <p>Note that the passed level value is a raw scalar. UI controls should be scaled
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index e8ddd2d..e89be08 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -835,6 +835,9 @@
}
}
+ // For inserts we always use the file URI so we can insert in bulk.
+ // For updates we compute the URI based on the media type.
+ Uri tableUri = mFilesUri;
Uri result = null;
if (rowId == 0) {
if (mMtpObjectHandle != 0) {
@@ -850,7 +853,7 @@
if (mFileInserter != null) {
result = mFileInserter.insert(values);
} else {
- result = mMediaProvider.insert(mFilesUri, values);
+ result = mMediaProvider.insert(tableUri, values);
}
if (result != null) {
@@ -858,8 +861,18 @@
entry.mRowId = rowId;
}
} else {
+ if (!mNoMedia) {
+ if (MediaFile.isVideoFileType(mFileType)) {
+ tableUri = mVideoUri;
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ tableUri = mImagesUri;
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ tableUri = mAudioUri;
+ }
+ }
+
// updated file
- result = ContentUris.withAppendedId(mFilesUri, rowId);
+ result = ContentUris.withAppendedId(tableUri, rowId);
// path should never change, and we want to avoid replacing mixed cased paths
// with squashed lower case paths
values.remove(MediaStore.MediaColumns.DATA);
@@ -909,19 +922,19 @@
if (notifications && !mDefaultNotificationSet) {
if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
- setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, mFilesUri, rowId);
+ setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
mDefaultNotificationSet = true;
}
} else if (ringtones && !mDefaultRingtoneSet) {
if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
- setSettingIfNotSet(Settings.System.RINGTONE, mFilesUri, rowId);
+ setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
}
} else if (alarms && !mDefaultAlarmSet) {
if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
- setSettingIfNotSet(Settings.System.ALARM_ALERT, mFilesUri, rowId);
+ setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
mDefaultAlarmSet = true;
}
}
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 0f3c063..4dbcb90 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -79,7 +79,6 @@
return (MtpDatabase *)env->GetIntField(database, field_context);
}
-#ifdef HAVE_ANDROID_OS
// ----------------------------------------------------------------------------
class MyMtpDatabase : public MtpDatabase {
@@ -1066,42 +1065,32 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-#endif // HAVE_ANDROID_OS
-
// ----------------------------------------------------------------------------
static void
android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
env->SetIntField(thiz, field_context, (int)database);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
-#endif
}
static void
android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
database->cleanup(env);
delete database;
env->SetIntField(thiz, field_context, 0);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
-#endif
}
static jstring
android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
{
-#ifdef HAVE_ANDROID_OS
char date[20];
formatDateTime(seconds, date, sizeof(date));
return env->NewStringUTF(date);
-#else
- return NULL;
-#endif
}
// ----------------------------------------------------------------------------
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 40bbaa3..6b73f6c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -85,8 +85,6 @@
static jfieldID field_objectInfo_dateModified;
static jfieldID field_objectInfo_keywords;
-#ifdef HAVE_ANDROID_OS
-
MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
{
return (MtpDevice*)env->GetIntField(javaDevice, field_context);
@@ -100,15 +98,11 @@
}
}
-#endif // HAVE_ANDROID_OS
-
// ----------------------------------------------------------------------------
static jboolean
android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint fd)
{
-#ifdef HAVE_ANDROID_OS
- LOGD("open\n");
const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
if (deviceNameStr == NULL) {
return false;
@@ -120,27 +114,22 @@
if (device)
env->SetIntField(thiz, field_context, (int)device);
return (device != NULL);
-#endif
}
static void
android_mtp_MtpDevice_close(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
- LOGD("close\n");
MtpDevice* device = get_device_from_object(env, thiz);
if (device) {
device->close();
delete device;
env->SetIntField(thiz, field_context, 0);
}
-#endif
}
static jobject
android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device) {
LOGD("android_mtp_MtpDevice_get_device_info device is null");
@@ -173,15 +162,11 @@
delete deviceInfo;
return info;
-#else
- return NULL;
-#endif
}
static jintArray
android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -196,15 +181,11 @@
delete storageIDs;
return array;
-#else
- return NULL;
-#endif
}
static jobject
android_mtp_MtpDevice_get_storage_info(JNIEnv *env, jobject thiz, jint storageID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -234,16 +215,12 @@
delete storageInfo;
return info;
-#else
- return NULL;
-#endif
}
static jintArray
android_mtp_MtpDevice_get_object_handles(JNIEnv *env, jobject thiz,
jint storageID, jint format, jint objectID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -258,15 +235,11 @@
delete handles;
return array;
-#else
- return NULL;
-#endif
}
static jobject
android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -324,9 +297,6 @@
delete objectInfo;
return info;
-#else
- return NULL;
-#endif
}
struct get_object_callback_data {
@@ -344,7 +314,6 @@
static jbyteArray
android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -361,14 +330,12 @@
if (device->readObject(objectID, get_object_callback, objectSize, &data))
return array;
-#endif
return NULL;
}
static jbyteArray
android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -382,51 +349,41 @@
free(thumbnail);
return array;
-#else
- return NULL;
-#endif
}
static jboolean
android_mtp_MtpDevice_delete_object(JNIEnv *env, jobject thiz, jint object_id)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
return device->deleteObject(object_id);
else
- #endif
return NULL;
}
static jlong
android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
return device->getParent(object_id);
else
-#endif
return -1;
}
static jlong
android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id)
{
- #ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
return device->getStorageID(object_id);
else
-#endif
return -1;
}
static jboolean
android_mtp_MtpDevice_import_file(JNIEnv *env, jobject thiz, jint object_id, jstring dest_path)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device) {
const char *destPathStr = env->GetStringUTFChars(dest_path, NULL);
@@ -438,7 +395,7 @@
env->ReleaseStringUTFChars(dest_path, destPathStr);
return result;
}
-#endif
+
return false;
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 7b3b95b..e17e1e8 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -3,8 +3,6 @@
include frameworks/base/media/libstagefright/codecs/common/Config.mk
-BUILD_WITH_SOFTWARE_DECODERS := false
-
LOCAL_SRC_FILES:= \
ACodec.cpp \
AACExtractor.cpp \
@@ -24,7 +22,6 @@
FileSource.cpp \
FLACExtractor.cpp \
HTTPBase.cpp \
- HTTPStream.cpp \
JPEGSource.cpp \
MP3Extractor.cpp \
MPEG2TSWriter.cpp \
@@ -38,13 +35,11 @@
MediaSourceSplitter.cpp \
MetaData.cpp \
NuCachedSource2.cpp \
- NuHTTPDataSource.cpp \
OMXClient.cpp \
OMXCodec.cpp \
OggExtractor.cpp \
SampleIterator.cpp \
SampleTable.cpp \
- ShoutcastSource.cpp \
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
ThrottledSource.cpp \
@@ -96,26 +91,6 @@
libstagefright_id3 \
libFLAC \
-ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true)
-
-LOCAL_SRC_FILES += \
- ThreadedSource.cpp \
-
-LOCAL_STATIC_LIBRARIES += \
- libstagefright_aacdec \
- libstagefright_amrnbdec \
- libstagefright_amrwbdec \
- libstagefright_avcdec \
- libstagefright_g711dec \
- libstagefright_mp3dec \
- libstagefright_m4vh263dec \
- libstagefright_vorbisdec \
- libstagefright_vpxdec \
- libvpx \
-
-endif
-
-
################################################################################
# The following was shamelessly copied from external/webkit/Android.mk and
@@ -177,10 +152,6 @@
LOCAL_CFLAGS += -Wno-multichar
-ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true)
- LOCAL_CFLAGS += -DHAVE_SOFTWARE_DECODERS
-endif
-
LOCAL_MODULE:= libstagefright
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 77c25d1..788464e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -890,7 +890,11 @@
CHECK(!(mFlags & AUDIO_RUNNING));
if (mVideoSource == NULL) {
- status_t err = startAudioPlayer_l();
+ // We don't want to post an error notification at this point,
+ // the error returned from MediaPlayer::start() will suffice.
+
+ status_t err = startAudioPlayer_l(
+ false /* sendErrorNotification */);
if (err != OK) {
delete mAudioPlayer;
@@ -940,7 +944,7 @@
return OK;
}
-status_t AwesomePlayer::startAudioPlayer_l() {
+status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
CHECK(!(mFlags & AUDIO_RUNNING));
if (mAudioSource == NULL || mAudioPlayer == NULL) {
@@ -958,7 +962,10 @@
true /* sourceAlreadyStarted */);
if (err != OK) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ if (sendErrorNotification) {
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ }
+
return err;
}
@@ -1684,7 +1691,7 @@
if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
status_t err = startAudioPlayer_l();
if (err != OK) {
- LOGE("Startung the audio player failed w/ err %d", err);
+ LOGE("Starting the audio player failed w/ err %d", err);
return;
}
}
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0d24551..f9d8501 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -24,10 +24,11 @@
#include "include/ChromiumHTTPDataSource.h"
#endif
-#include "include/NuHTTPDataSource.h"
-
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
+
#include <cutils/properties.h>
+#include <cutils/qtaguid.h>
namespace android {
@@ -44,14 +45,12 @@
// static
sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
#if CHROMIUM_AVAILABLE
- char value[PROPERTY_VALUE_MAX];
- if (!property_get("media.stagefright.use-chromium", value, NULL)
- || (strcasecmp("false", value) && strcmp("0", value))) {
return new ChromiumHTTPDataSource(flags);
- } else
#endif
{
- return new NuHTTPDataSource(flags);
+ TRESPASS();
+
+ return NULL;
}
}
@@ -135,4 +134,10 @@
return true;
}
+// static
+void HTTPBase::RegisterSocketUser(int s, uid_t uid) {
+ static const uint32_t kTag = 0xdeadbeef;
+ set_qtaguid(s, kTag, uid);
+}
+
} // namespace android
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
deleted file mode 100644
index d526ebd..0000000
--- a/media/libstagefright/HTTPStream.cpp
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "HTTPStream"
-#include <utils/Log.h>
-
-#include "include/HTTPStream.h"
-
-#include <sys/socket.h>
-
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <openssl/ssl.h>
-
-namespace android {
-
-// static
-const char *HTTPStream::kStatusKey = ":status:"; // MUST be lowercase.
-
-HTTPStream::HTTPStream()
- : mState(READY),
- mUIDValid(false),
- mSocket(-1),
- mSSLContext(NULL),
- mSSL(NULL) {
-}
-
-HTTPStream::~HTTPStream() {
- disconnect();
-
- if (mSSLContext != NULL) {
- SSL_CTX_free((SSL_CTX *)mSSLContext);
- mSSLContext = NULL;
- }
-}
-
-void HTTPStream::setUID(uid_t uid) {
- mUIDValid = true;
- mUID = uid;
-}
-
-static bool MakeSocketBlocking(int s, bool blocking) {
- // Make socket non-blocking.
- int flags = fcntl(s, F_GETFL, 0);
- if (flags == -1) {
- return false;
- }
-
- if (blocking) {
- flags &= ~O_NONBLOCK;
- } else {
- flags |= O_NONBLOCK;
- }
-
- return fcntl(s, F_SETFL, flags) != -1;
-}
-
-static status_t MyConnect(
- int s, const struct sockaddr *addr, socklen_t addrlen) {
- status_t result = UNKNOWN_ERROR;
-
- MakeSocketBlocking(s, false);
-
- if (connect(s, addr, addrlen) == 0) {
- result = OK;
- } else if (errno != EINPROGRESS) {
- result = -errno;
- } else {
- for (;;) {
- fd_set rs, ws;
- FD_ZERO(&rs);
- FD_ZERO(&ws);
- FD_SET(s, &rs);
- FD_SET(s, &ws);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 100000ll;
-
- int nfds = ::select(s + 1, &rs, &ws, NULL, &tv);
-
- if (nfds < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- result = -errno;
- break;
- }
-
- if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) {
- result = OK;
- break;
- }
-
- if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
- // Get the pending error.
- int error = 0;
- socklen_t errorLen = sizeof(error);
- if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) {
- // Couldn't get the real error, so report why not.
- result = -errno;
- } else {
- result = -error;
- }
- break;
- }
-
- // Timeout expired. Try again.
- }
- }
-
- MakeSocketBlocking(s, true);
-
- return result;
-}
-
-// Apparently under out linux closing a socket descriptor from one thread
-// will not unblock a pending send/recv on that socket on another thread.
-static ssize_t MySendReceive(
- int s, void *data, size_t size, int flags, bool sendData) {
- ssize_t result = 0;
-
- if (s < 0) {
- return -1;
- }
- while (size > 0) {
- fd_set rs, ws, es;
- FD_ZERO(&rs);
- FD_ZERO(&ws);
- FD_ZERO(&es);
- FD_SET(s, sendData ? &ws : &rs);
- FD_SET(s, &es);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 100000ll;
-
- int nfds = ::select(
- s + 1,
- sendData ? NULL : &rs,
- sendData ? &ws : NULL,
- &es,
- &tv);
-
- if (nfds < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- result = -errno;
- break;
- } else if (nfds == 0) {
- // timeout
-
- continue;
- }
-
- CHECK_EQ(nfds, 1);
-
- ssize_t nbytes =
- sendData ? send(s, data, size, flags) : recv(s, data, size, flags);
-
- if (nbytes < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- result = -errno;
- break;
- } else if (nbytes == 0) {
- result = 0;
- break;
- }
-
- data = (uint8_t *)data + nbytes;
- size -= nbytes;
-
- result = nbytes;
- break;
- }
-
- return result;
-}
-
-static ssize_t MySend(int s, const void *data, size_t size, int flags) {
- return MySendReceive(
- s, const_cast<void *>(data), size, flags, true /* sendData */);
-}
-
-static ssize_t MyReceive(int s, void *data, size_t size, int flags) {
- return MySendReceive(s, data, size, flags, false /* sendData */);
-}
-
-status_t HTTPStream::connect(const char *server, int port, bool https) {
- if (port < 0) {
- port = https ? 443 : 80;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- status_t err = OK;
-
- if (mState == CONNECTED) {
- return ERROR_ALREADY_CONNECTED;
- }
-
- if (port < 0 || port > (int) USHRT_MAX) {
- return UNKNOWN_ERROR;
- }
-
- char service[sizeof("65536")];
- sprintf(service, "%d", port);
- struct addrinfo hints, *ai;
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
- hints.ai_socktype = SOCK_STREAM;
-
- int ret = getaddrinfo(server, service, &hints, &ai);
- if (ret) {
- return ERROR_UNKNOWN_HOST;
- }
-
- CHECK_EQ(mSocket, -1);
-
- mState = CONNECTING;
- status_t res = -1;
- struct addrinfo *tmp;
- for (tmp = ai; tmp; tmp = tmp->ai_next) {
- mSocket = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
- if (mSocket < 0) {
- continue;
- }
-
- if (mUIDValid) {
- RegisterSocketUser(mSocket, mUID);
- }
-
- setReceiveTimeout(30); // Time out reads after 30 secs by default.
-
- int s = mSocket;
-
- mLock.unlock();
-
- res = MyConnect(s, tmp->ai_addr, tmp->ai_addrlen);
-
- mLock.lock();
-
- if (mState != CONNECTING) {
- close(s);
- freeaddrinfo(ai);
- return UNKNOWN_ERROR;
- }
-
- if (res == OK) {
- break;
- }
-
- close(s);
- }
-
- freeaddrinfo(ai);
-
- if (res != OK) {
- close(mSocket);
- mSocket = -1;
-
- mState = READY;
- return res;
- }
-
- if (https) {
- CHECK(mSSL == NULL);
-
- if (mSSLContext == NULL) {
- SSL_library_init();
-
- mSSLContext = SSL_CTX_new(TLSv1_client_method());
-
- if (mSSLContext == NULL) {
- LOGE("failed to create SSL context");
- mState = READY;
- return ERROR_IO;
- }
- }
-
- mSSL = SSL_new((SSL_CTX *)mSSLContext);
-
- if (mSSL == NULL) {
- LOGE("failed to create SSL session");
-
- mState = READY;
- return ERROR_IO;
- }
-
- int res = SSL_set_fd((SSL *)mSSL, mSocket);
-
- if (res == 1) {
- res = SSL_connect((SSL *)mSSL);
- }
-
- if (res != 1) {
- SSL_free((SSL *)mSSL);
- mSSL = NULL;
-
- LOGE("failed to connect over SSL");
- mState = READY;
-
- return ERROR_IO;
- }
- }
-
- mState = CONNECTED;
-
- return OK;
-}
-
-status_t HTTPStream::disconnect() {
- Mutex::Autolock autoLock(mLock);
-
- if (mState != CONNECTED && mState != CONNECTING) {
- return ERROR_NOT_CONNECTED;
- }
-
- if (mSSL != NULL) {
- SSL_shutdown((SSL *)mSSL);
-
- SSL_free((SSL *)mSSL);
- mSSL = NULL;
- }
-
- CHECK(mSocket >= 0);
- close(mSocket);
- mSocket = -1;
-
- mState = READY;
-
- return OK;
-}
-
-status_t HTTPStream::send(const char *data, size_t size) {
- if (mState != CONNECTED) {
- return ERROR_NOT_CONNECTED;
- }
-
- while (size > 0) {
- ssize_t n;
- if (mSSL != NULL) {
- n = SSL_write((SSL *)mSSL, data, size);
-
- if (n < 0) {
- n = -SSL_get_error((SSL *)mSSL, n);
- }
- } else {
- n = MySend(mSocket, data, size, 0);
- }
-
- if (n < 0) {
- disconnect();
-
- return n;
- } else if (n == 0) {
- disconnect();
-
- return ERROR_CONNECTION_LOST;
- }
-
- size -= (size_t)n;
- data += (size_t)n;
- }
-
- return OK;
-}
-
-status_t HTTPStream::send(const char *data) {
- return send(data, strlen(data));
-}
-
-// A certain application spawns a local webserver that sends invalid responses,
-// specifically it terminates header line with only a newline instead of the
-// CRLF (carriage-return followed by newline) required by the HTTP specs.
-// The workaround accepts both behaviours but could potentially break
-// legitimate responses that use a single newline to "fold" headers, which is
-// why it's not yet on by default.
-#define WORKAROUND_FOR_MISSING_CR 1
-
-status_t HTTPStream::receive_line(char *line, size_t size) {
- if (mState != CONNECTED) {
- return ERROR_NOT_CONNECTED;
- }
-
- bool saw_CR = false;
- size_t length = 0;
-
- for (;;) {
- char c;
- ssize_t n;
- if (mSSL != NULL) {
- n = SSL_read((SSL *)mSSL, &c, 1);
-
- if (n < 0) {
- n = -SSL_get_error((SSL *)mSSL, n);
- }
- } else {
- n = MyReceive(mSocket, &c, 1, 0);
- }
-
- if (n < 0) {
- disconnect();
-
- return ERROR_IO;
- } else if (n == 0) {
- disconnect();
-
- return ERROR_CONNECTION_LOST;
- }
-
-#if WORKAROUND_FOR_MISSING_CR
- if (c == '\n') {
- // We have a complete line.
-
- line[saw_CR ? length - 1 : length] = '\0';
- return OK;
- }
-#else
- if (saw_CR && c == '\n') {
- // We have a complete line.
-
- line[length - 1] = '\0';
- return OK;
- }
-#endif
-
- saw_CR = (c == '\r');
-
- if (length + 1 >= size) {
- return ERROR_MALFORMED;
- }
- line[length++] = c;
- }
-}
-
-status_t HTTPStream::receive_header(int *http_status) {
- *http_status = -1;
- mHeaders.clear();
-
- char line[2048];
- status_t err = receive_line(line, sizeof(line));
- if (err != OK) {
- return err;
- }
-
- mHeaders.add(AString(kStatusKey), AString(line));
-
- char *spacePos = strchr(line, ' ');
- if (spacePos == NULL) {
- // Malformed response?
- return UNKNOWN_ERROR;
- }
-
- char *status_start = spacePos + 1;
- char *status_end = status_start;
- while (isdigit(*status_end)) {
- ++status_end;
- }
-
- if (status_end == status_start) {
- // Malformed response, status missing?
- return UNKNOWN_ERROR;
- }
-
- memmove(line, status_start, status_end - status_start);
- line[status_end - status_start] = '\0';
-
- long tmp = strtol(line, NULL, 10);
- if (tmp < 0 || tmp > 999) {
- return UNKNOWN_ERROR;
- }
-
- *http_status = (int)tmp;
-
- for (;;) {
- err = receive_line(line, sizeof(line));
- if (err != OK) {
- return err;
- }
-
- if (*line == '\0') {
- // Empty line signals the end of the header.
- break;
- }
-
- // puts(line);
-
- char *colonPos = strchr(line, ':');
- if (colonPos == NULL) {
- AString key = line;
- key.tolower();
-
- mHeaders.add(key, AString());
- } else {
- char *end_of_key = colonPos;
- while (end_of_key > line && isspace(end_of_key[-1])) {
- --end_of_key;
- }
-
- char *start_of_value = colonPos + 1;
- while (isspace(*start_of_value)) {
- ++start_of_value;
- }
-
- *end_of_key = '\0';
-
- AString key = line;
- key.tolower();
-
- mHeaders.add(key, AString(start_of_value));
- }
- }
-
- return OK;
-}
-
-ssize_t HTTPStream::receive(void *data, size_t size) {
- size_t total = 0;
- while (total < size) {
- ssize_t n;
- if (mSSL != NULL) {
- n = SSL_read((SSL *)mSSL, (char *)data + total, size - total);
-
- if (n < 0) {
- n = -SSL_get_error((SSL *)mSSL, n);
- }
- } else {
- n = MyReceive(mSocket, (char *)data + total, size - total, 0);
- }
-
- if (n < 0) {
- LOGE("recv failed, errno = %d (%s)", (int)n, strerror(-n));
-
- disconnect();
- return (ssize_t)ERROR_IO;
- } else if (n == 0) {
- disconnect();
-
- LOGE("recv failed, server is gone, total received: %d bytes",
- total);
-
- return total == 0 ? (ssize_t)ERROR_CONNECTION_LOST : total;
- }
-
- total += (size_t)n;
- }
-
- return (ssize_t)total;
-}
-
-bool HTTPStream::find_header_value(const AString &key, AString *value) const {
- AString key_lower = key;
- key_lower.tolower();
-
- ssize_t index = mHeaders.indexOfKey(key_lower);
- if (index < 0) {
- value->clear();
- return false;
- }
-
- *value = mHeaders.valueAt(index);
-
- return true;
-}
-
-void HTTPStream::setReceiveTimeout(int seconds) {
- if (seconds < 0) {
- // Disable the timeout.
- seconds = 0;
- }
-
- struct timeval tv;
- tv.tv_usec = 0;
- tv.tv_sec = seconds;
- CHECK_EQ(0, setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)));
-}
-
-// static
-void HTTPStream::RegisterSocketUser(int s, uid_t uid) {
- // Lower bits MUST be 0.
- static const uint64_t kTag = 0xdeadbeef00000000ll;
-
- AString line = StringPrintf("t %d %llu %d", s, kTag, uid);
-
- int fd = open("/proc/net/xt_qtaguid/ctrl", O_WRONLY);
- write(fd, line.c_str(), line.size());
- close(fd);
- fd = -1;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
deleted file mode 100644
index 2949767..0000000
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuHTTPDataSource"
-#include <utils/Log.h>
-
-#include "include/NuHTTPDataSource.h"
-
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-static bool ParseSingleUnsignedLong(
- const char *from, unsigned long *x) {
- char *end;
- *x = strtoul(from, &end, 10);
-
- if (end == from || *end != '\0') {
- return false;
- }
-
- return true;
-}
-
-static bool ParseURL(
- const char *url, String8 *host, unsigned *port,
- String8 *path, bool *https) {
- host->setTo("");
- *port = 0;
- path->setTo("");
-
- size_t hostStart;
- if (!strncasecmp("http://", url, 7)) {
- hostStart = 7;
- *https = false;
- } else if (!strncasecmp("https://", url, 8)) {
- hostStart = 8;
- *https = true;
- } else {
- return false;
- }
-
- const char *slashPos = strchr(&url[hostStart], '/');
-
- if (slashPos == NULL) {
- host->setTo(&url[hostStart]);
- path->setTo("/");
- } else {
- host->setTo(&url[hostStart], slashPos - &url[hostStart]);
- path->setTo(slashPos);
- }
-
- const char *colonPos = strchr(host->string(), ':');
-
- if (colonPos != NULL) {
- unsigned long x;
- if (!ParseSingleUnsignedLong(colonPos + 1, &x) || x >= 65536) {
- return false;
- }
-
- *port = x;
-
- size_t colonOffset = colonPos - host->string();
- String8 tmp(host->string(), colonOffset);
- *host = tmp;
- } else {
- *port = (*https) ? 443 : 80;
- }
-
- return true;
-}
-
-NuHTTPDataSource::NuHTTPDataSource(uint32_t flags)
- : mFlags(flags),
- mState(DISCONNECTED),
- mPort(0),
- mHTTPS(false),
- mOffset(0),
- mContentLength(0),
- mContentLengthValid(false),
- mHasChunkedTransferEncoding(false),
- mChunkDataBytesLeft(0),
- mDecryptHandle(NULL),
- mDrmManagerClient(NULL) {
-}
-
-NuHTTPDataSource::~NuHTTPDataSource() {
- if (mDecryptHandle != NULL) {
- // To release mDecryptHandle
- CHECK(mDrmManagerClient);
- mDrmManagerClient->closeDecryptSession(mDecryptHandle);
- mDecryptHandle = NULL;
- }
-
- if (mDrmManagerClient != NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-}
-
-status_t NuHTTPDataSource::connect(
- const char *uri,
- const KeyedVector<String8, String8> *overrides,
- off64_t offset) {
- String8 headers;
- MakeFullHeaders(overrides, &headers);
-
- return connect(uri, headers, offset);
-}
-
-status_t NuHTTPDataSource::connect(
- const char *uri,
- const String8 &headers,
- off64_t offset) {
- String8 host, path;
- unsigned port;
-
- mUri = uri;
- mContentType = String8("application/octet-stream");
-
- bool https;
- if (!ParseURL(uri, &host, &port, &path, &https)) {
- return ERROR_MALFORMED;
- }
-
- uid_t uid;
- if (getUID(&uid)) {
- mHTTP.setUID(uid);
- }
-
- return connect(host, port, path, https, headers, offset);
-}
-
-static bool IsRedirectStatusCode(int httpStatus) {
- return httpStatus == 301 || httpStatus == 302
- || httpStatus == 303 || httpStatus == 307;
-}
-
-status_t NuHTTPDataSource::connect(
- const char *host, unsigned port, const char *path,
- bool https,
- const String8 &headers,
- off64_t offset) {
- if (!(mFlags & kFlagIncognito)) {
- LOGI("connect to %s:%u%s @%lld", host, port, path, offset);
- } else {
- LOGI("connect to <URL suppressed> @%lld", offset);
- }
-
- bool needsToReconnect = true;
-
- if (mState == CONNECTED && host == mHost && port == mPort
- && https == mHTTPS && offset == mOffset) {
- if (mContentLengthValid && mOffset == mContentLength) {
- LOGI("Didn't have to reconnect, old one's still good.");
- needsToReconnect = false;
- }
- }
-
- mHost = host;
- mPort = port;
- mPath = path;
- mHTTPS = https;
- mHeaders = headers;
-
- status_t err = OK;
-
- mState = CONNECTING;
-
- if (needsToReconnect) {
- mHTTP.disconnect();
- err = mHTTP.connect(host, port, https);
- }
-
- if (err != OK) {
- mState = DISCONNECTED;
- } else if (mState != CONNECTING) {
- err = UNKNOWN_ERROR;
- } else {
- mState = CONNECTED;
-
- mOffset = offset;
- mContentLength = 0;
- mContentLengthValid = false;
-
- String8 request("GET ");
- request.append(mPath);
- request.append(" HTTP/1.1\r\n");
- request.append("Host: ");
- request.append(mHost);
- if (mPort != 80) {
- request.append(StringPrintf(":%u", mPort).c_str());
- }
- request.append("\r\n");
-
- if (offset != 0) {
- char rangeHeader[128];
- sprintf(rangeHeader, "Range: bytes=%lld-\r\n", offset);
- request.append(rangeHeader);
- }
-
- request.append(mHeaders);
- request.append("\r\n");
-
- int httpStatus;
- if ((err = mHTTP.send(request.string(), request.size())) != OK
- || (err = mHTTP.receive_header(&httpStatus)) != OK) {
- mHTTP.disconnect();
- mState = DISCONNECTED;
- return err;
- }
-
- if (IsRedirectStatusCode(httpStatus)) {
- AString value;
- CHECK(mHTTP.find_header_value("Location", &value));
-
- mState = DISCONNECTED;
-
- mHTTP.disconnect();
-
- return connect(value.c_str(), headers, offset);
- }
-
- if (httpStatus < 200 || httpStatus >= 300) {
- mState = DISCONNECTED;
- mHTTP.disconnect();
-
- return ERROR_IO;
- }
-
- mHasChunkedTransferEncoding = false;
-
- {
- AString value;
- if (mHTTP.find_header_value("Transfer-Encoding", &value)) {
- // We don't currently support any transfer encodings but
- // chunked.
-
- if (!strcasecmp(value.c_str(), "chunked")) {
- LOGI("Chunked transfer encoding applied.");
- mHasChunkedTransferEncoding = true;
- mChunkDataBytesLeft = 0;
- } else {
- mState = DISCONNECTED;
- mHTTP.disconnect();
-
- LOGE("We don't support '%s' transfer encoding.", value.c_str());
-
- return ERROR_UNSUPPORTED;
- }
- }
- }
-
- {
- AString value;
- if (mHTTP.find_header_value("Content-Type", &value)) {
- mContentType = String8(value.c_str());
- } else {
- mContentType = String8("application/octet-stream");
- }
- }
-
- applyTimeoutResponse();
-
- if (offset == 0) {
- AString value;
- unsigned long x;
- if (mHTTP.find_header_value(AString("Content-Length"), &value)
- && ParseSingleUnsignedLong(value.c_str(), &x)) {
- mContentLength = (off64_t)x;
- mContentLengthValid = true;
- } else {
- LOGW("Server did not give us the content length!");
- }
- } else {
- if (httpStatus != 206 /* Partial Content */) {
- // We requested a range but the server didn't support that.
- LOGE("We requested a range but the server didn't "
- "support that.");
- return ERROR_UNSUPPORTED;
- }
-
- AString value;
- unsigned long x;
- if (mHTTP.find_header_value(AString("Content-Range"), &value)) {
- const char *slashPos = strchr(value.c_str(), '/');
- if (slashPos != NULL
- && ParseSingleUnsignedLong(slashPos + 1, &x)) {
- mContentLength = x;
- mContentLengthValid = true;
- }
- }
- }
- }
-
- return err;
-}
-
-void NuHTTPDataSource::disconnect() {
- if (mState == CONNECTING || mState == CONNECTED) {
- mHTTP.disconnect();
- }
- mState = DISCONNECTED;
-}
-
-status_t NuHTTPDataSource::initCheck() const {
- return mState == CONNECTED ? OK : NO_INIT;
-}
-
-ssize_t NuHTTPDataSource::internalRead(void *data, size_t size) {
- if (!mHasChunkedTransferEncoding) {
- return mHTTP.receive(data, size);
- }
-
- if (mChunkDataBytesLeft < 0) {
- return 0;
- } else if (mChunkDataBytesLeft == 0) {
- char line[1024];
- status_t err = mHTTP.receive_line(line, sizeof(line));
-
- if (err != OK) {
- return err;
- }
-
- LOGV("line = '%s'", line);
-
- char *end;
- unsigned long n = strtoul(line, &end, 16);
-
- if (end == line || (*end != ';' && *end != '\0')) {
- LOGE("malformed HTTP chunk '%s'", line);
- return ERROR_MALFORMED;
- }
-
- mChunkDataBytesLeft = n;
- LOGV("chunk data size = %lu", n);
-
- if (mChunkDataBytesLeft == 0) {
- mChunkDataBytesLeft = -1;
- return 0;
- }
-
- // fall through
- }
-
- if (size > (size_t)mChunkDataBytesLeft) {
- size = mChunkDataBytesLeft;
- }
-
- ssize_t n = mHTTP.receive(data, size);
-
- if (n < 0) {
- return n;
- }
-
- mChunkDataBytesLeft -= (size_t)n;
-
- if (mChunkDataBytesLeft == 0) {
- char line[1024];
- status_t err = mHTTP.receive_line(line, sizeof(line));
-
- if (err != OK) {
- return err;
- }
-
- if (line[0] != '\0') {
- LOGE("missing HTTP chunk terminator.");
- return ERROR_MALFORMED;
- }
- }
-
- return n;
-}
-
-ssize_t NuHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
- LOGV("readAt offset %ld, size %d", offset, size);
-
- Mutex::Autolock autoLock(mLock);
-
- if (offset != mOffset) {
- String8 host = mHost;
- String8 path = mPath;
- String8 headers = mHeaders;
- status_t err = connect(host, mPort, path, mHTTPS, headers, offset);
-
- if (err != OK) {
- return err;
- }
- }
-
- if (mContentLengthValid) {
- size_t avail =
- (offset >= mContentLength) ? 0 : mContentLength - offset;
-
- if (size > avail) {
- size = avail;
- }
- }
-
- size_t numBytesRead = 0;
- while (numBytesRead < size) {
- int64_t startTimeUs = ALooper::GetNowUs();
-
- ssize_t n =
- internalRead((uint8_t *)data + numBytesRead, size - numBytesRead);
-
- if (n < 0) {
- if (numBytesRead == 0 || mContentLengthValid) {
- return n;
- }
-
- // If there was an error we want to at least return the data
- // we've already successfully read. The next call to read will
- // then return the error.
- n = 0;
- }
-
- int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
- addBandwidthMeasurement(n, delayUs);
-
- numBytesRead += (size_t)n;
-
- if (n == 0) {
- if (mContentLengthValid) {
- // We know the content length and made sure not to read beyond
- // it and yet the server closed the connection on us.
- return ERROR_IO;
- }
-
- break;
- }
- }
-
- mOffset += numBytesRead;
-
- return numBytesRead;
-}
-
-status_t NuHTTPDataSource::getSize(off64_t *size) {
- *size = 0;
-
- if (mState != CONNECTED) {
- return ERROR_IO;
- }
-
- if (mContentLengthValid) {
- *size = mContentLength;
- return OK;
- }
-
- return ERROR_UNSUPPORTED;
-}
-
-uint32_t NuHTTPDataSource::flags() {
- return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-// static
-void NuHTTPDataSource::MakeFullHeaders(
- const KeyedVector<String8, String8> *overrides, String8 *headers) {
- headers->setTo("");
-
- headers->append("User-Agent: stagefright/1.1 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- headers->append(value);
- headers->append(")\r\n");
-
- if (overrides == NULL) {
- return;
- }
-
- for (size_t i = 0; i < overrides->size(); ++i) {
- String8 line;
- line.append(overrides->keyAt(i));
- line.append(": ");
- line.append(overrides->valueAt(i));
- line.append("\r\n");
-
- headers->append(line);
- }
-}
-
-void NuHTTPDataSource::applyTimeoutResponse() {
- AString timeout;
- if (mHTTP.find_header_value("X-SocketTimeout", &timeout)) {
- const char *s = timeout.c_str();
- char *end;
- long tmp = strtol(s, &end, 10);
- if (end == s || *end != '\0') {
- LOGW("Illegal X-SocketTimeout value given.");
- return;
- }
-
- LOGI("overriding default timeout, new timeout is %ld seconds", tmp);
- mHTTP.setReceiveTimeout(tmp);
- }
-}
-
-sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() {
- if (mDrmManagerClient == NULL) {
- mDrmManagerClient = new DrmManagerClient();
- }
-
- if (mDrmManagerClient == NULL) {
- return NULL;
- }
-
- if (mDecryptHandle == NULL) {
- /* Note if redirect occurs, mUri is the redirect uri instead of the
- * original one
- */
- mDecryptHandle = mDrmManagerClient->openDecryptSession(mUri);
- }
-
- if (mDecryptHandle == NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-
- return mDecryptHandle;
-}
-
-void NuHTTPDataSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
- handle = mDecryptHandle;
-
- *client = mDrmManagerClient;
-}
-
-String8 NuHTTPDataSource::getUri() {
- return mUri;
-}
-
-String8 NuHTTPDataSource::getMIMEType() const {
- return mContentType;
-}
-
-} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 3b05752..b7b0dc0f 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,20 +18,11 @@
#define LOG_TAG "OMXCodec"
#include <utils/Log.h>
-#include "include/AACDecoder.h"
#include "include/AACEncoder.h"
-#include "include/AMRNBDecoder.h"
#include "include/AMRNBEncoder.h"
-#include "include/AMRWBDecoder.h"
#include "include/AMRWBEncoder.h"
-#include "include/AVCDecoder.h"
#include "include/AVCEncoder.h"
-#include "include/G711Decoder.h"
-#include "include/M4vH263Decoder.h"
#include "include/M4vH263Encoder.h"
-#include "include/MP3Decoder.h"
-#include "include/VorbisDecoder.h"
-#include "include/VPXDecoder.h"
#include "include/ESDS.h"
@@ -53,10 +44,6 @@
#include <OMX_Audio.h>
#include <OMX_Component.h>
-#if HAVE_SOFTWARE_DECODERS
-#include "include/ThreadedSource.h"
-#endif
-
#include "include/avc_utils.h"
namespace android {
@@ -79,24 +66,6 @@
FACTORY_CREATE_ENCODER(AVCEncoder)
FACTORY_CREATE_ENCODER(M4vH263Encoder)
-#if HAVE_SOFTWARE_DECODERS
-
-#define FACTORY_CREATE(name) \
-static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
- return new name(source); \
-}
-
-FACTORY_CREATE(AMRNBDecoder)
-FACTORY_CREATE(AMRWBDecoder)
-FACTORY_CREATE(AACDecoder)
-FACTORY_CREATE(AVCDecoder)
-FACTORY_CREATE(G711Decoder)
-FACTORY_CREATE(MP3Decoder)
-FACTORY_CREATE(M4vH263Decoder)
-FACTORY_CREATE(VorbisDecoder)
-FACTORY_CREATE(VPXDecoder)
-#endif
-
static sp<MediaSource> InstantiateSoftwareEncoder(
const char *name, const sp<MediaSource> &source,
const sp<MetaData> &meta) {
@@ -122,40 +91,6 @@
return NULL;
}
-static sp<MediaSource> InstantiateSoftwareCodec(
- const char *name, const sp<MediaSource> &source) {
-#if HAVE_SOFTWARE_DECODERS
- struct FactoryInfo {
- const char *name;
- sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
- };
-
- static const FactoryInfo kFactoryInfo[] = {
- FACTORY_REF(AMRNBDecoder)
- FACTORY_REF(AMRWBDecoder)
- FACTORY_REF(AACDecoder)
- FACTORY_REF(AVCDecoder)
- FACTORY_REF(G711Decoder)
- FACTORY_REF(MP3Decoder)
- FACTORY_REF(M4vH263Decoder)
- FACTORY_REF(VorbisDecoder)
- FACTORY_REF(VPXDecoder)
- };
- for (size_t i = 0;
- i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
- if (!strcmp(name, kFactoryInfo[i].name)) {
- if (!strcmp(name, "VPXDecoder")) {
- return new ThreadedSource(
- (*kFactoryInfo[i].CreateFunc)(source));
- }
- return (*kFactoryInfo[i].CreateFunc)(source);
- }
- }
-#endif
-
- return NULL;
-}
-
#undef FACTORY_REF
#undef FACTORY_CREATE
@@ -163,23 +98,17 @@
{ MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
- { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
{ MEDIA_MIMETYPE_AUDIO_G711_ALAW, "OMX.google.g711.alaw.decoder" },
- { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" },
{ MEDIA_MIMETYPE_AUDIO_G711_MLAW, "OMX.google.g711.mlaw.decoder" },
- { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.DECODER" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
@@ -187,14 +116,12 @@
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.google.mpeg4.decoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.DECODER" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.google.h263.decoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.DECODER" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
@@ -203,11 +130,8 @@
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.h264.decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.avc.decoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
{ MEDIA_MIMETYPE_AUDIO_VORBIS, "OMX.google.vorbis.decoder" },
- { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },
{ MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" },
- { MEDIA_MIMETYPE_VIDEO_VPX, "VPXDecoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG2, "OMX.Nvidia.mpeg2v.decode" },
};
@@ -518,14 +442,15 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
componentName = matchingCodecs[i].string();
- sp<MediaSource> softwareCodec = createEncoder?
- InstantiateSoftwareEncoder(componentName, source, meta):
- InstantiateSoftwareCodec(componentName, source);
+ if (createEncoder) {
+ sp<MediaSource> softwareCodec =
+ InstantiateSoftwareEncoder(componentName, source, meta);
- if (softwareCodec != NULL) {
- LOGV("Successfully allocated software codec '%s'", componentName);
+ if (softwareCodec != NULL) {
+ LOGV("Successfully allocated software codec '%s'", componentName);
- return softwareCodec;
+ return softwareCodec;
+ }
}
LOGV("Attempting to allocate OMX node '%s'", componentName);
@@ -4430,12 +4355,9 @@
if (strncmp(componentName, "OMX.", 4)) {
// Not an OpenMax component but a software codec.
-#if HAVE_SOFTWARE_DECODERS
results->push();
CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
caps->mComponentName = componentName;
-#endif
-
continue;
}
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
deleted file mode 100644
index 783f2d0..0000000
--- a/media/libstagefright/ShoutcastSource.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2009 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 "include/HTTPStream.h"
-
-#include <stdlib.h>
-
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/ShoutcastSource.h>
-
-namespace android {
-
-ShoutcastSource::ShoutcastSource(HTTPStream *http)
- : mHttp(http),
- mMetaDataOffset(0),
- mBytesUntilMetaData(0),
- mGroup(NULL),
- mStarted(false) {
- AString metaint;
- if (mHttp->find_header_value("icy-metaint", &metaint)) {
- char *end;
- const char *start = metaint.c_str();
- mMetaDataOffset = strtol(start, &end, 10);
- CHECK(end > start && *end == '\0');
- CHECK(mMetaDataOffset > 0);
-
- mBytesUntilMetaData = mMetaDataOffset;
- }
-}
-
-ShoutcastSource::~ShoutcastSource() {
- if (mStarted) {
- stop();
- }
-
- delete mHttp;
- mHttp = NULL;
-}
-
-status_t ShoutcastSource::start(MetaData *) {
- CHECK(!mStarted);
-
- mGroup = new MediaBufferGroup;
- mGroup->add_buffer(new MediaBuffer(4096)); // XXX
-
- mStarted = true;
-
- return OK;
-}
-
-status_t ShoutcastSource::stop() {
- CHECK(mStarted);
-
- delete mGroup;
- mGroup = NULL;
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> ShoutcastSource::getFormat() {
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- meta->setInt32(kKeySampleRate, 44100);
- meta->setInt32(kKeyChannelCount, 2); // XXX
-
- return meta;
-}
-
-status_t ShoutcastSource::read(
- MediaBuffer **out, const ReadOptions *options) {
- CHECK(mStarted);
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- return ERROR_UNSUPPORTED;
- }
-
- MediaBuffer *buffer;
- status_t err = mGroup->acquire_buffer(&buffer);
- if (err != OK) {
- return err;
- }
-
- *out = buffer;
-
- size_t num_bytes = buffer->size();
- if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) {
- num_bytes = mBytesUntilMetaData;
- }
-
- ssize_t n = mHttp->receive(buffer->data(), num_bytes);
-
- if (n <= 0) {
- return (status_t)n;
- }
-
- buffer->set_range(0, n);
-
- mBytesUntilMetaData -= (size_t)n;
-
- if (mBytesUntilMetaData == 0) {
- unsigned char num_16_byte_blocks = 0;
- n = mHttp->receive((char *)&num_16_byte_blocks, 1);
- CHECK_EQ(n, 1);
-
- char meta[255 * 16];
- size_t meta_size = num_16_byte_blocks * 16;
- size_t meta_length = 0;
- while (meta_length < meta_size) {
- n = mHttp->receive(&meta[meta_length], meta_size - meta_length);
- if (n <= 0) {
- return (status_t)n;
- }
-
- meta_length += (size_t) n;
- }
-
- while (meta_length > 0 && meta[meta_length - 1] == '\0') {
- --meta_length;
- }
-
- if (meta_length > 0) {
- // Technically we should probably attach this meta data to the
- // next buffer. XXX
- buffer->meta_data()->setData('shou', 'shou', meta, meta_length);
- }
-
- mBytesUntilMetaData = mMetaDataOffset;
- }
-
- return OK;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/ThreadedSource.cpp b/media/libstagefright/ThreadedSource.cpp
deleted file mode 100644
index 38c6e2d..0000000
--- a/media/libstagefright/ThreadedSource.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ThreadedSource"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "include/ThreadedSource.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-static const size_t kMaxQueueSize = 2;
-
-ThreadedSource::ThreadedSource(const sp<MediaSource> &source)
- : mSource(source),
- mReflector(new AHandlerReflector<ThreadedSource>(this)),
- mLooper(new ALooper),
- mStarted(false) {
- mLooper->registerHandler(mReflector);
-}
-
-ThreadedSource::~ThreadedSource() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t ThreadedSource::start(MetaData *params) {
- CHECK(!mStarted);
-
- status_t err = mSource->start(params);
-
- if (err != OK) {
- return err;
- }
-
- mFinalResult = OK;
- mSeekTimeUs = -1;
- mDecodePending = false;
-
- Mutex::Autolock autoLock(mLock);
- postDecodeMore_l();
-
- CHECK_EQ(mLooper->start(), (status_t)OK);
-
- mStarted = true;
-
- return OK;
-}
-
-status_t ThreadedSource::stop() {
- CHECK(mStarted);
-
- CHECK_EQ(mLooper->stop(), (status_t)OK);
-
- Mutex::Autolock autoLock(mLock);
- clearQueue_l();
-
- status_t err = mSource->stop();
-
- mStarted = false;
-
- return err;
-}
-
-sp<MetaData> ThreadedSource::getFormat() {
- return mSource->getFormat();
-}
-
-status_t ThreadedSource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
- *buffer = NULL;
-
- Mutex::Autolock autoLock(mLock);
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- int32_t seekComplete = 0;
-
- sp<AMessage> msg = new AMessage(kWhatSeek, mReflector->id());
- msg->setInt64("timeUs", seekTimeUs);
- msg->setInt32("mode", seekMode);
- msg->setPointer("complete", &seekComplete);
- msg->post();
-
- while (!seekComplete) {
- mCondition.wait(mLock);
- }
- }
-
- while (mQueue.empty() && mFinalResult == OK) {
- mCondition.wait(mLock);
- }
-
- if (!mQueue.empty()) {
- *buffer = *mQueue.begin();
- mQueue.erase(mQueue.begin());
-
- if (mFinalResult == OK) {
- postDecodeMore_l();
- }
-
- return OK;
- }
-
- return mFinalResult;
-}
-
-void ThreadedSource::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatSeek:
- {
- CHECK(msg->findInt64("timeUs", &mSeekTimeUs));
- CHECK_GE(mSeekTimeUs, 0ll);
-
- int32_t x;
- CHECK(msg->findInt32("mode", &x));
- mSeekMode = (ReadOptions::SeekMode)x;
-
- int32_t *seekComplete;
- CHECK(msg->findPointer("complete", (void **)&seekComplete));
-
- Mutex::Autolock autoLock(mLock);
- clearQueue_l();
- mFinalResult = OK;
-
- *seekComplete = 1;
- mCondition.signal();
-
- postDecodeMore_l();
- break;
- }
-
- case kWhatDecodeMore:
- {
- {
- Mutex::Autolock autoLock(mLock);
- mDecodePending = false;
-
- if (mQueue.size() == kMaxQueueSize) {
- break;
- }
- }
-
- MediaBuffer *buffer;
- ReadOptions options;
- if (mSeekTimeUs >= 0) {
- options.setSeekTo(mSeekTimeUs, mSeekMode);
- mSeekTimeUs = -1ll;
- }
- status_t err = mSource->read(&buffer, &options);
-
- Mutex::Autolock autoLock(mLock);
-
- if (err != OK) {
- mFinalResult = err;
- } else {
- mQueue.push_back(buffer);
-
- if (mQueue.size() < kMaxQueueSize) {
- postDecodeMore_l();
- }
- }
-
- mCondition.signal();
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void ThreadedSource::postDecodeMore_l() {
- if (mDecodePending) {
- return;
- }
-
- mDecodePending = true;
- (new AMessage(kWhatDecodeMore, mReflector->id()))->post();
-}
-
-void ThreadedSource::clearQueue_l() {
- while (!mQueue.empty()) {
- MediaBuffer *buffer = *mQueue.begin();
- mQueue.erase(mQueue.begin());
-
- buffer->release();
- buffer = NULL;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
deleted file mode 100644
index d2e3eaa..0000000
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2009 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 "AACDecoder.h"
-#define LOG_TAG "AACDecoder"
-
-#include "../../include/ESDS.h"
-
-#include "pvmp4audiodecoder_api.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-AACDecoder::AACDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mConfig(new tPVMP4AudioDecoderExternal),
- mDecoderBuf(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mInputBuffer(NULL) {
-
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t sampleRate;
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
- // We'll always output stereo, regardless of how many channels are
- // present in the input due to decoder limitations.
- mMeta->setInt32(kKeyChannelCount, 2);
- mMeta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- mMeta->setInt64(kKeyDuration, durationUs);
- }
- mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
-
- mInitCheck = initCheck();
-}
-
-status_t AACDecoder::initCheck() {
- memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
- mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
- mConfig->aacPlusEnabled = 1;
-
- // The software decoder doesn't properly support mono output on
- // AACplus files. Always output stereo.
- mConfig->desiredChannels = 2;
-
- UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
- mDecoderBuf = malloc(memRequirements);
-
- status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
- if (err != MP4AUDEC_SUCCESS) {
- LOGE("Failed to initialize MP4 audio decoder");
- return UNKNOWN_ERROR;
- }
-
- uint32_t type;
- const void *data;
- size_t size;
- sp<MetaData> meta = mSource->getFormat();
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
-
- mConfig->pInputBuffer = (UChar *)codec_specific_data;
- mConfig->inputBufferCurrentLength = codec_specific_data_size;
- mConfig->inputBufferMaxLength = 0;
-
- if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
- != MP4AUDEC_SUCCESS) {
- return ERROR_UNSUPPORTED;
- }
- }
- return OK;
-}
-
-AACDecoder::~AACDecoder() {
- if (mStarted) {
- stop();
- }
-
- delete mConfig;
- mConfig = NULL;
-}
-
-status_t AACDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mStarted = true;
- mNumDecodedBuffers = 0;
- mUpsamplingFactor = 2;
-
- return OK;
-}
-
-status_t AACDecoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- free(mDecoderBuf);
- mDecoderBuf = NULL;
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AACDecoder::getFormat() {
- return mMeta;
-}
-
-status_t AACDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumSamplesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- PVMP4AudioDecoderResetBuffer(mDecoderBuf);
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumSamplesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
-
- mConfig->pInputBuffer =
- (UChar *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
- mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
- mConfig->remainderBits = 0;
-
- mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
- mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
- mConfig->repositionFlag = false;
-
- Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
-
- /*
- * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
- * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
- * rate system and the sampling rate in the final output is actually
- * doubled compared with the core AAC decoder sampling rate.
- *
- * Explicit signalling is done by explicitly defining SBR audio object
- * type in the bitstream. Implicit signalling is done by embedding
- * SBR content in AAC extension payload specific to SBR, and hence
- * requires an AAC decoder to perform pre-checks on actual audio frames.
- *
- * Thus, we could not say for sure whether a stream is
- * AAC+/eAAC+ until the first data frame is decoded.
- */
- if (++mNumDecodedBuffers <= 2) {
- LOGV("audio/extended audio object type: %d + %d",
- mConfig->audioObjectType, mConfig->extendedAudioObjectType);
- LOGV("aac+ upsampling factor: %d desired channels: %d",
- mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
-
- CHECK(mNumDecodedBuffers > 0);
-
- if (decoderErr != MP4AUDEC_SUCCESS) {
- // If decoding fails this early, the fields in mConfig may
- // not be valid and we cannot recover.
-
- LOGE("Unable to decode aac content, decoder returned error %d",
- decoderErr);
-
- buffer->release();
- buffer = NULL;
-
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- return ERROR_UNSUPPORTED;
- }
-
- if (mNumDecodedBuffers == 1) {
- mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
- // Check on the sampling rate to see whether it is changed.
- int32_t sampleRate;
- CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
- if (mConfig->samplingRate != sampleRate) {
- mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
- LOGW("Sample rate was %d Hz, but now is %d Hz",
- sampleRate, mConfig->samplingRate);
- buffer->release();
- mInputBuffer->release();
- mInputBuffer = NULL;
- return INFO_FORMAT_CHANGED;
- }
- } else { // mNumDecodedBuffers == 2
- if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC ||
- mConfig->extendedAudioObjectType == MP4AUDIO_LTP) {
- if (mUpsamplingFactor == 2) {
- // The stream turns out to be not aacPlus mode anyway
- LOGW("Disable AAC+/eAAC+ since extended audio object type is %d",
- mConfig->extendedAudioObjectType);
- mConfig->aacPlusEnabled = 0;
- }
- } else {
- if (mUpsamplingFactor == 1) {
- // aacPlus mode does not buy us anything, but to cause
- // 1. CPU load to increase, and
- // 2. a half speed of decoding
- LOGW("Disable AAC+/eAAC+ since upsampling factor is 1");
- mConfig->aacPlusEnabled = 0;
- }
- }
- }
- }
-
- size_t numOutBytes =
- mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
- if (mUpsamplingFactor == 2) {
- if (mConfig->desiredChannels == 1) {
- memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
- }
- numOutBytes *= 2;
- }
-
- if (decoderErr != MP4AUDEC_SUCCESS) {
- LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
-
- memset(buffer->data(), 0, numOutBytes);
-
- // Discard input buffer.
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- // fall through
- }
-
- buffer->set_range(0, numOutBytes);
-
- if (mInputBuffer != NULL) {
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
- mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumSamplesOutput * 1000000) / mConfig->samplingRate);
-
- mNumSamplesOutput += mConfig->frameLength * mUpsamplingFactor;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 359a2ec..20c7bc0 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -143,7 +143,6 @@
unpack_idx.cpp \
window_tables_fxp.cpp \
pvmp4setaudioconfig.cpp \
- AACDecoder.cpp \
LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= -DOSCL_UNUSED_ARG=
diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
deleted file mode 100644
index a11d46b..0000000
--- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AMRNBDecoder"
-#include <utils/Log.h>
-
-#include "AMRNBDecoder.h"
-
-#include "gsmamr_dec.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-static const int32_t kNumSamplesPerFrame = 160;
-static const int32_t kSampleRate = 8000;
-
-AMRNBDecoder::AMRNBDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mState(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mInputBuffer(NULL) {
-}
-
-AMRNBDecoder::~AMRNBDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t AMRNBDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t)));
-
- CHECK_EQ(GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder"), 0);
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mStarted = true;
-
- return OK;
-}
-
-status_t AMRNBDecoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- GSMDecodeFrameExit(&mState);
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AMRNBDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t numChannels;
- int32_t sampleRate;
-
- CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
- CHECK_EQ(numChannels, 1);
-
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
- CHECK_EQ(sampleRate, kSampleRate);
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, numChannels);
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "AMRNBDecoder");
-
- return meta;
-}
-
-status_t AMRNBDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumSamplesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumSamplesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
-
- const uint8_t *inputPtr =
- (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- int32_t numBytesRead =
- AMRDecode(mState,
- (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f),
- (UWord8 *)&inputPtr[1],
- static_cast<int16_t *>(buffer->data()),
- MIME_IETF);
-
- if (numBytesRead == -1 ) {
- LOGE("PV AMR decoder AMRDecode() call failed");
- buffer->release();
- buffer = NULL;
- return ERROR_MALFORMED;
- }
- ++numBytesRead; // Include the frame type header byte.
-
- buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t));
-
- if (static_cast<size_t>(numBytesRead) > mInputBuffer->range_length()) {
- // This is bad, should never have happened, but did. Abort now.
-
- buffer->release();
- buffer = NULL;
-
- return ERROR_MALFORMED;
- }
-
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + numBytesRead,
- mInputBuffer->range_length() - numBytesRead);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumSamplesOutput * 1000000) / kSampleRate);
-
- mNumSamplesOutput += kNumSamplesPerFrame;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 5862abc..23a22ef 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- AMRNBDecoder.cpp \
src/a_refl.cpp \
src/agc.cpp \
src/amrdecode.cpp \
diff --git a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
deleted file mode 100644
index 5b111ef..0000000
--- a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2009 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 "AMRWBDecoder.h"
-
-#include "pvamrwbdecoder.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-static const int32_t kNumSamplesPerFrame = 320;
-static const int32_t kSampleRate = 16000;
-
-AMRWBDecoder::AMRWBDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mState(NULL),
- mDecoderBuf(NULL),
- mDecoderCookie(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mInputBuffer(NULL) {
-}
-
-AMRWBDecoder::~AMRWBDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t AMRWBDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t)));
-
- int32_t memReq = pvDecoder_AmrWbMemRequirements();
- mDecoderBuf = malloc(memReq);
-
- pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie);
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mStarted = true;
-
- return OK;
-}
-
-status_t AMRWBDecoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- free(mDecoderBuf);
- mDecoderBuf = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AMRWBDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t numChannels;
- int32_t sampleRate;
-
- CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
- CHECK_EQ(numChannels, 1);
-
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
- CHECK_EQ(sampleRate, kSampleRate);
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, numChannels);
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "AMRWBDecoder");
-
- return meta;
-}
-
-static size_t getFrameSize(unsigned FT) {
- static const size_t kFrameSizeWB[9] = {
- 132, 177, 253, 285, 317, 365, 397, 461, 477
- };
-
- size_t frameSize = kFrameSizeWB[FT];
-
- // Round up bits to bytes and add 1 for the header byte.
- frameSize = (frameSize + 7) / 8 + 1;
-
- return frameSize;
-}
-
-status_t AMRWBDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumSamplesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumSamplesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
-
- const uint8_t *inputPtr =
- (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- int16 mode = ((inputPtr[0] >> 3) & 0x0f);
- size_t frameSize = getFrameSize(mode);
- CHECK(mInputBuffer->range_length() >= frameSize);
-
- int16 frameType;
- RX_State_wb rx_state;
- mime_unsorting(
- const_cast<uint8_t *>(&inputPtr[1]),
- mInputSampleBuffer,
- &frameType, &mode, 1, &rx_state);
-
- int16_t *outPtr = (int16_t *)buffer->data();
-
- int16_t numSamplesOutput;
- pvDecoder_AmrWb(
- mode, mInputSampleBuffer,
- outPtr,
- &numSamplesOutput,
- mDecoderBuf, frameType, mDecoderCookie);
-
- CHECK_EQ(numSamplesOutput, kNumSamplesPerFrame);
-
- for (int i = 0; i < kNumSamplesPerFrame; ++i) {
- /* Delete the 2 LSBs (14-bit output) */
- outPtr[i] &= 0xfffC;
- }
-
- buffer->set_range(0, numSamplesOutput * sizeof(int16_t));
-
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + frameSize,
- mInputBuffer->range_length() - frameSize);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumSamplesOutput * 1000000) / kSampleRate);
-
- mNumSamplesOutput += kNumSamplesPerFrame;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index ab591d7..c9e1c25 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- AMRWBDecoder.cpp \
src/agc2_amr_wb.cpp \
src/band_pass_6k_7k.cpp \
src/dec_acelp_2p_in_64.cpp \
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
deleted file mode 100644
index 490129f..0000000
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AVCDecoder"
-#include <utils/Log.h>
-
-#include "AVCDecoder.h"
-
-#include "avcdec_api.h"
-#include "avcdec_int.h"
-
-#include <OMX_Component.h>
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-namespace android {
-
-static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
-
-static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
- return reinterpret_cast<int32_t>(malloc(size));
-}
-
-static void Free(void *userData, int32_t ptr) {
- free(reinterpret_cast<void *>(ptr));
-}
-
-AVCDecoder::AVCDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mHandle(new tagAVCHandle),
- mInputBuffer(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mPendingSeekTimeUs(-1),
- mPendingSeekMode(MediaSource::ReadOptions::SEEK_CLOSEST_SYNC),
- mTargetTimeUs(-1),
- mSPSSeen(false),
- mPPSSeen(false) {
- memset(mHandle, 0, sizeof(tagAVCHandle));
- mHandle->AVCObject = NULL;
- mHandle->userData = this;
- mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper;
- mHandle->CBAVC_FrameBind = BindFrameWrapper;
- mHandle->CBAVC_FrameUnbind = UnbindFrame;
- mHandle->CBAVC_Malloc = Malloc;
- mHandle->CBAVC_Free = Free;
-
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- int32_t width, height;
- CHECK(mSource->getFormat()->findInt32(kKeyWidth, &width));
- CHECK(mSource->getFormat()->findInt32(kKeyHeight, &height));
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
- mFormat->setRect(kKeyCropRect, 0, 0, width - 1, height - 1);
- mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- mFormat->setCString(kKeyDecoderComponent, "AVCDecoder");
-
- int64_t durationUs;
- if (mSource->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- mFormat->setInt64(kKeyDuration, durationUs);
- }
-}
-
-AVCDecoder::~AVCDecoder() {
- if (mStarted) {
- stop();
- }
-
- PVAVCCleanUpDecoder(mHandle);
-
- delete mHandle;
- mHandle = NULL;
-}
-
-status_t AVCDecoder::start(MetaData *) {
- CHECK(!mStarted);
-
- uint32_t type;
- const void *data;
- size_t size;
- sp<MetaData> meta = mSource->getFormat();
- if (meta->findData(kKeyAVCC, &type, &data, &size)) {
- // Parse the AVCDecoderConfigurationRecord
-
- const uint8_t *ptr = (const uint8_t *)data;
-
- CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
- uint8_t profile = ptr[1];
- uint8_t level = ptr[3];
-
- // There is decodable content out there that fails the following
- // assertion, let's be lenient for now...
- // CHECK((ptr[4] >> 2) == 0x3f); // reserved
-
- size_t lengthSize = 1 + (ptr[4] & 3);
-
- // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
- // violates it...
- // CHECK((ptr[5] >> 5) == 7); // reserved
-
- size_t numSeqParameterSets = ptr[5] & 31;
-
- ptr += 6;
- size -= 6;
-
- for (size_t i = 0; i < numSeqParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- CHECK(size >= length);
-
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
-
- CHECK(size >= 1);
- size_t numPictureParameterSets = *ptr;
- ++ptr;
- --size;
-
- for (size_t i = 0; i < numPictureParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- CHECK(size >= length);
-
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
- }
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mPendingSeekTimeUs = -1;
- mPendingSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
- mTargetTimeUs = -1;
- mSPSSeen = false;
- mPPSSeen = false;
- mStarted = true;
-
- return OK;
-}
-
-void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) {
- MediaBuffer *buffer = new MediaBuffer(size + 4);
- memcpy(buffer->data(), kStartCode, 4);
- memcpy((uint8_t *)buffer->data() + 4, data, size);
- buffer->set_range(0, size + 4);
-
- mCodecSpecificData.push(buffer);
-}
-
-status_t AVCDecoder::stop() {
- CHECK(mStarted);
-
- for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
- (*mCodecSpecificData.editItemAt(i)).release();
- }
- mCodecSpecificData.clear();
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- mSource->stop();
-
- releaseFrames();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AVCDecoder::getFormat() {
- return mFormat;
-}
-
-static void findNALFragment(
- const MediaBuffer *buffer, const uint8_t **fragPtr, size_t *fragSize) {
- const uint8_t *data =
- (const uint8_t *)buffer->data() + buffer->range_offset();
-
- size_t size = buffer->range_length();
-
- CHECK(size >= 4);
- CHECK(!memcmp(kStartCode, data, 4));
-
- size_t offset = 4;
- while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) {
- ++offset;
- }
-
- *fragPtr = &data[4];
- if (offset + 3 >= size) {
- *fragSize = size - 4;
- } else {
- *fragSize = offset - 4;
- }
-}
-
-MediaBuffer *AVCDecoder::drainOutputBuffer() {
- int32_t index;
- int32_t Release;
- AVCFrameIO Output;
- Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
- AVCDec_Status status = PVAVCDecGetOutput(mHandle, &index, &Release, &Output);
-
- if (status != AVCDEC_SUCCESS) {
- LOGV("PVAVCDecGetOutput returned error %d", status);
- return NULL;
- }
-
- CHECK(index >= 0);
- CHECK(index < (int32_t)mFrames.size());
-
- MediaBuffer *mbuf = mFrames.editItemAt(index);
-
- bool skipFrame = false;
-
- if (mTargetTimeUs >= 0) {
- int64_t timeUs;
- CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
- CHECK(timeUs <= mTargetTimeUs);
-
- if (timeUs < mTargetTimeUs) {
- // We're still waiting for the frame with the matching
- // timestamp and we won't return the current one.
- skipFrame = true;
-
- LOGV("skipping frame at %lld us", timeUs);
- } else {
- LOGV("found target frame at %lld us", timeUs);
-
- mTargetTimeUs = -1;
- }
- }
-
- if (!skipFrame) {
- mbuf->set_range(0, mbuf->size());
- mbuf->add_ref();
-
- return mbuf;
- }
-
- return new MediaBuffer(0);
-}
-
-status_t AVCDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- LOGV("seek requested to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
-
- CHECK(seekTimeUs >= 0);
- mPendingSeekTimeUs = seekTimeUs;
- mPendingSeekMode = mode;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- PVAVCDecReset(mHandle);
- }
-
- if (mInputBuffer == NULL) {
- LOGV("fetching new input buffer.");
-
- bool seeking = false;
-
- if (!mCodecSpecificData.isEmpty()) {
- mInputBuffer = mCodecSpecificData.editItemAt(0);
- mCodecSpecificData.removeAt(0);
- } else {
- for (;;) {
- if (mPendingSeekTimeUs >= 0) {
- LOGV("reading data from timestamp %lld (%.2f secs)",
- mPendingSeekTimeUs, mPendingSeekTimeUs / 1E6);
- }
-
- ReadOptions seekOptions;
- if (mPendingSeekTimeUs >= 0) {
- seeking = true;
-
- seekOptions.setSeekTo(mPendingSeekTimeUs, mPendingSeekMode);
- mPendingSeekTimeUs = -1;
- }
- status_t err = mSource->read(&mInputBuffer, &seekOptions);
- seekOptions.clearSeekTo();
-
- if (err != OK) {
- *out = drainOutputBuffer();
- return (*out == NULL) ? err : (status_t)OK;
- }
-
- if (mInputBuffer->range_length() > 0) {
- break;
- }
-
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- }
-
- if (seeking) {
- int64_t targetTimeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
- }
-
- const uint8_t *fragPtr;
- size_t fragSize;
- findNALFragment(mInputBuffer, &fragPtr, &fragSize);
-
- bool releaseFragment = true;
- status_t err = UNKNOWN_ERROR;
-
- int nalType;
- int nalRefIdc;
- AVCDec_Status res =
- PVAVCDecGetNALType(
- const_cast<uint8_t *>(fragPtr), fragSize,
- &nalType, &nalRefIdc);
-
- if (res != AVCDEC_SUCCESS) {
- LOGV("cannot determine nal type");
- } else if (nalType == AVC_NALTYPE_SPS || nalType == AVC_NALTYPE_PPS
- || (mSPSSeen && mPPSSeen)) {
- switch (nalType) {
- case AVC_NALTYPE_SPS:
- {
- mSPSSeen = true;
-
- res = PVAVCDecSeqParamSet(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res != AVCDEC_SUCCESS) {
- LOGV("PVAVCDecSeqParamSet returned error %d", res);
- break;
- }
-
- AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject;
-
- int32_t width =
- (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16;
-
- int32_t height =
- (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16;
-
- int32_t crop_left, crop_right, crop_top, crop_bottom;
- if (pDecVid->seqParams[0]->frame_cropping_flag)
- {
- crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset;
- crop_right =
- width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1);
-
- if (pDecVid->seqParams[0]->frame_mbs_only_flag)
- {
- crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset;
- crop_bottom =
- height -
- (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
- }
- else
- {
- crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset;
- crop_bottom =
- height -
- (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
- }
- } else {
- crop_bottom = height - 1;
- crop_right = width - 1;
- crop_top = crop_left = 0;
- }
-
- int32_t prevCropLeft, prevCropTop;
- int32_t prevCropRight, prevCropBottom;
- if (!mFormat->findRect(
- kKeyCropRect,
- &prevCropLeft, &prevCropTop,
- &prevCropRight, &prevCropBottom)) {
- prevCropLeft = prevCropTop = 0;
- prevCropRight = width - 1;
- prevCropBottom = height - 1;
- }
-
- int32_t oldWidth, oldHeight;
- CHECK(mFormat->findInt32(kKeyWidth, &oldWidth));
- CHECK(mFormat->findInt32(kKeyHeight, &oldHeight));
-
- if (oldWidth != width || oldHeight != height
- || prevCropLeft != crop_left
- || prevCropTop != crop_top
- || prevCropRight != crop_right
- || prevCropBottom != crop_bottom) {
- mFormat->setRect(
- kKeyCropRect,
- crop_left, crop_top, crop_right, crop_bottom);
-
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
-
- err = INFO_FORMAT_CHANGED;
- } else {
- *out = new MediaBuffer(0);
- err = OK;
- }
- break;
- }
-
- case AVC_NALTYPE_PPS:
- {
- mPPSSeen = true;
-
- res = PVAVCDecPicParamSet(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res != AVCDEC_SUCCESS) {
- LOGV("PVAVCDecPicParamSet returned error %d", res);
- break;
- }
-
- *out = new MediaBuffer(0);
-
- err = OK;
- break;
- }
-
- case AVC_NALTYPE_SLICE:
- case AVC_NALTYPE_IDR:
- {
- res = PVAVCDecodeSlice(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res == AVCDEC_PICTURE_OUTPUT_READY) {
- MediaBuffer *mbuf = drainOutputBuffer();
- if (mbuf == NULL) {
- break;
- }
-
- *out = mbuf;
-
- // Do _not_ release input buffer yet.
-
- releaseFragment = false;
- err = OK;
- break;
- }
-
- if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) {
- *out = new MediaBuffer(0);
-
- err = OK;
- } else {
- LOGV("PVAVCDecodeSlice returned error %d", res);
- }
- break;
- }
-
- case AVC_NALTYPE_SEI:
- {
- res = PVAVCDecSEI(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res != AVCDEC_SUCCESS) {
- break;
- }
-
- *out = new MediaBuffer(0);
-
- err = OK;
- break;
- }
-
- case AVC_NALTYPE_AUD:
- case AVC_NALTYPE_FILL:
- case AVC_NALTYPE_EOSEQ:
- {
- *out = new MediaBuffer(0);
-
- err = OK;
- break;
- }
-
- default:
- {
- LOGE("Should not be here, unknown nalType %d", nalType);
-
- err = ERROR_MALFORMED;
- break;
- }
- }
- } else {
- // We haven't seen SPS or PPS yet.
-
- *out = new MediaBuffer(0);
- err = OK;
- }
-
- if (releaseFragment) {
- size_t offset = mInputBuffer->range_offset();
- if (fragSize + 4 == mInputBuffer->range_length()) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- } else {
- mInputBuffer->set_range(
- offset + fragSize + 4,
- mInputBuffer->range_length() - fragSize - 4);
- }
- }
-
- return err;
-}
-
-// static
-int32_t AVCDecoder::ActivateSPSWrapper(
- void *userData, unsigned int sizeInMbs, unsigned int numBuffers) {
- return static_cast<AVCDecoder *>(userData)->activateSPS(sizeInMbs, numBuffers);
-}
-
-// static
-int32_t AVCDecoder::BindFrameWrapper(
- void *userData, int32_t index, uint8_t **yuv) {
- return static_cast<AVCDecoder *>(userData)->bindFrame(index, yuv);
-}
-
-// static
-void AVCDecoder::UnbindFrame(void *userData, int32_t index) {
-}
-
-int32_t AVCDecoder::activateSPS(
- unsigned int sizeInMbs, unsigned int numBuffers) {
- CHECK(mFrames.isEmpty());
-
- size_t frameSize = (sizeInMbs << 7) * 3;
- for (unsigned int i = 0; i < numBuffers; ++i) {
- MediaBuffer *buffer = new MediaBuffer(frameSize);
- buffer->setObserver(this);
-
- mFrames.push(buffer);
- }
-
- return 1;
-}
-
-int32_t AVCDecoder::bindFrame(int32_t index, uint8_t **yuv) {
- CHECK(index >= 0);
- CHECK(index < (int32_t)mFrames.size());
-
- CHECK(mInputBuffer != NULL);
- int64_t timeUs;
- CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
- mFrames[index]->meta_data()->setInt64(kKeyTime, timeUs);
-
- *yuv = (uint8_t *)mFrames[index]->data();
-
- return 1;
-}
-
-void AVCDecoder::releaseFrames() {
- for (size_t i = 0; i < mFrames.size(); ++i) {
- MediaBuffer *buffer = mFrames.editItemAt(i);
-
- buffer->setObserver(NULL);
- buffer->release();
- }
- mFrames.clear();
-}
-
-void AVCDecoder::signalBufferReturned(MediaBuffer *buffer) {
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk
index 4d4533b..2949a04 100644
--- a/media/libstagefright/codecs/avc/dec/Android.mk
+++ b/media/libstagefright/codecs/avc/dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- AVCDecoder.cpp \
src/avcdec_api.cpp \
src/avc_bitstream.cpp \
src/header.cpp \
diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
index 9f141ac..6a476f6 100644
--- a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
#include "avcdec_api.h"
#include "avcdec_int.h"
@@ -31,6 +32,13 @@
static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
+static const CodecProfileLevel kProfileLevels[] = {
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+};
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -181,6 +189,28 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoProfileLevelQuerySupported:
+ {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+ (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+ if (profileLevel->nPortIndex != 0) { // Input port only
+ LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+ return OMX_ErrorUnsupportedIndex;
+ }
+
+ size_t index = profileLevel->nProfileIndex;
+ size_t nProfileLevels =
+ sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kProfileLevels[index].mProfile;
+ profileLevel->eLevel = kProfileLevels[index].mLevel;
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index 6e98559..6692533 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -2,20 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- G711Decoder.cpp
-
-LOCAL_C_INCLUDES := \
- frameworks/base/media/libstagefright/include \
-
-LOCAL_MODULE := libstagefright_g711dec
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
SoftG711.cpp
LOCAL_C_INCLUDES := \
diff --git a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp b/media/libstagefright/codecs/g711/dec/G711Decoder.cpp
deleted file mode 100644
index 4414e4e..0000000
--- a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "G711Decoder"
-#include <utils/Log.h>
-
-#include "G711Decoder.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-static const size_t kMaxNumSamplesPerFrame = 16384;
-
-namespace android {
-
-G711Decoder::G711Decoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL) {
-}
-
-G711Decoder::~G711Decoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t G711Decoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- const char *mime;
- CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
- mIsMLaw = false;
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {
- mIsMLaw = true;
- } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)) {
- return ERROR_UNSUPPORTED;
- }
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kMaxNumSamplesPerFrame * sizeof(int16_t)));
-
- mSource->start();
-
- mStarted = true;
-
- return OK;
-}
-
-status_t G711Decoder::stop() {
- CHECK(mStarted);
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> G711Decoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t numChannels;
- int32_t sampleRate;
-
- CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, numChannels);
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "G711Decoder");
-
- return meta;
-}
-
-status_t G711Decoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
- } else {
- seekTimeUs = -1;
- }
-
- MediaBuffer *inBuffer;
- err = mSource->read(&inBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- if (inBuffer->range_length() > kMaxNumSamplesPerFrame) {
- LOGE("input buffer too large (%d).", inBuffer->range_length());
-
- inBuffer->release();
- inBuffer = NULL;
-
- return ERROR_UNSUPPORTED;
- }
-
- int64_t timeUs;
- CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- const uint8_t *inputPtr =
- (const uint8_t *)inBuffer->data() + inBuffer->range_offset();
-
- MediaBuffer *outBuffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&outBuffer), OK);
-
- if (mIsMLaw) {
- DecodeMLaw(
- static_cast<int16_t *>(outBuffer->data()),
- inputPtr, inBuffer->range_length());
- } else {
- DecodeALaw(
- static_cast<int16_t *>(outBuffer->data()),
- inputPtr, inBuffer->range_length());
- }
-
- // Each 8-bit byte is converted into a 16-bit sample.
- outBuffer->set_range(0, inBuffer->range_length() * 2);
-
- outBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
- inBuffer->release();
- inBuffer = NULL;
-
- *out = outBuffer;
-
- return OK;
-}
-
-// static
-void G711Decoder::DecodeALaw(
- int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize-- > 0) {
- int32_t x = *in++;
-
- int32_t ix = x ^ 0x55;
- ix &= 0x7f;
-
- int32_t iexp = ix >> 4;
- int32_t mant = ix & 0x0f;
-
- if (iexp > 0) {
- mant += 16;
- }
-
- mant = (mant << 4) + 8;
-
- if (iexp > 1) {
- mant = mant << (iexp - 1);
- }
-
- *out++ = (x > 127) ? mant : -mant;
- }
-}
-
-// static
-void G711Decoder::DecodeMLaw(
- int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize-- > 0) {
- int32_t x = *in++;
-
- int32_t mantissa = ~x;
- int32_t exponent = (mantissa >> 4) & 7;
- int32_t segment = exponent + 1;
- mantissa &= 0x0f;
-
- int32_t step = 4 << segment;
-
- int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
-
- *out++ = (x < 0x80) ? -abs : abs;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index f1bec08..2ffa5f2 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- M4vH263Decoder.cpp \
src/adaptive_smooth_no_mmx.cpp \
src/bitstream.cpp \
src/block_idct.cpp \
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
deleted file mode 100644
index 2bdb3ef..0000000
--- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "M4vH263Decoder"
-#include <utils/Log.h>
-#include <stdlib.h> // for free
-#include "ESDS.h"
-#include "M4vH263Decoder.h"
-
-#include "mp4dec_api.h"
-
-#include <OMX_Component.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-M4vH263Decoder::M4vH263Decoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mHandle(new tagvideoDecControls),
- mInputBuffer(NULL),
- mNumSamplesOutput(0),
- mTargetTimeUs(-1) {
-
- LOGV("M4vH263Decoder");
- memset(mHandle, 0, sizeof(tagvideoDecControls));
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
-
- // CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth));
- // CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight));
-
- // We'll ignore the dimension advertised by the source, the decoder
- // appears to require us to always start with the default dimensions
- // of 352 x 288 to operate correctly and later react to changes in
- // the dimensions as needed.
- mWidth = 352;
- mHeight = 288;
-
- mFormat->setInt32(kKeyWidth, mWidth);
- mFormat->setInt32(kKeyHeight, mHeight);
- mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- mFormat->setCString(kKeyDecoderComponent, "M4vH263Decoder");
-}
-
-M4vH263Decoder::~M4vH263Decoder() {
- if (mStarted) {
- stop();
- }
-
- delete mHandle;
- mHandle = NULL;
-}
-
-void M4vH263Decoder::allocateFrames(int32_t width, int32_t height) {
- size_t frameSize =
- (((width + 15) & - 16) * ((height + 15) & - 16) * 3) / 2;
-
- for (uint32_t i = 0; i < 2; ++i) {
- mFrames[i] = new MediaBuffer(frameSize);
- mFrames[i]->setObserver(this);
- }
-
- PVSetReferenceYUV(
- mHandle,
- (uint8_t *)mFrames[1]->data());
-}
-
-status_t M4vH263Decoder::start(MetaData *) {
- CHECK(!mStarted);
-
- const char *mime = NULL;
- sp<MetaData> meta = mSource->getFormat();
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- MP4DecodingMode mode;
- if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
- mode = MPEG4_MODE;
- } else {
- CHECK(!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime));
- mode = H263_MODE;
- }
-
- uint32_t type;
- const void *data = NULL;
- size_t size = 0;
- uint8_t *vol_data[1] = {0};
- int32_t vol_size = 0;
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const uint8_t *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
-
- vol_data[0] = (uint8_t *) malloc(codec_specific_data_size);
- memcpy(vol_data[0], codec_specific_data, codec_specific_data_size);
- vol_size = codec_specific_data_size;
- } else {
- vol_data[0] = NULL;
- vol_size = 0;
-
- }
-
- Bool success = PVInitVideoDecoder(
- mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
- if (vol_data[0]) free(vol_data[0]);
-
- if (success != PV_TRUE) {
- LOGW("PVInitVideoDecoder failed. Unsupported content?");
- return ERROR_UNSUPPORTED;
- }
-
- MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
- if (mode != actualMode) {
- PVCleanUpVideoDecoder(mHandle);
- return UNKNOWN_ERROR;
- }
-
- PVSetPostProcType((VideoDecControls *) mHandle, 0);
-
- int32_t width, height;
- PVGetVideoDimensions(mHandle, &width, &height);
- if (mode == H263_MODE && (width == 0 || height == 0)) {
- width = 352;
- height = 288;
- }
- allocateFrames(width, height);
-
- mSource->start();
-
- mNumSamplesOutput = 0;
- mTargetTimeUs = -1;
- mStarted = true;
-
- return OK;
-}
-
-status_t M4vH263Decoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- mSource->stop();
-
- releaseFrames();
-
- mStarted = false;
- return (PVCleanUpVideoDecoder(mHandle) == PV_TRUE)? OK: UNKNOWN_ERROR;
-}
-
-sp<MetaData> M4vH263Decoder::getFormat() {
- return mFormat;
-}
-
-status_t M4vH263Decoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
-
- bool seeking = false;
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- seeking = true;
- CHECK_EQ((int)PVResetVideoDecoder(mHandle), PV_TRUE);
- }
-
- MediaBuffer *inputBuffer = NULL;
- status_t err = mSource->read(&inputBuffer, options);
- if (err != OK) {
- return err;
- }
-
- if (seeking) {
- int64_t targetTimeUs;
- if (inputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
-
- uint8_t *bitstream =
- (uint8_t *) inputBuffer->data() + inputBuffer->range_offset();
-
- uint32_t timestamp = 0xFFFFFFFF;
- int32_t bufferSize = inputBuffer->range_length();
- uint32_t useExtTimestamp = 0;
- if (PVDecodeVideoFrame(
- mHandle, &bitstream, ×tamp, &bufferSize,
- &useExtTimestamp,
- (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data())
- != PV_TRUE) {
- LOGE("failed to decode video frame.");
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- return UNKNOWN_ERROR;
- }
-
- int32_t disp_width, disp_height;
- PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
-
- int32_t buf_width, buf_height;
- PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
-
- if (buf_width != mWidth || buf_height != mHeight) {
- ++mNumSamplesOutput; // The client will never get to see this frame.
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- mWidth = buf_width;
- mHeight = buf_height;
- mFormat->setInt32(kKeyWidth, mWidth);
- mFormat->setInt32(kKeyHeight, mHeight);
-
- CHECK_LE(disp_width, buf_width);
- CHECK_LE(disp_height, buf_height);
-
- mFormat->setRect(kKeyCropRect, 0, 0, disp_width - 1, disp_height - 1);
-
- return INFO_FORMAT_CHANGED;
- }
-
- int64_t timeUs;
- CHECK(inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- bool skipFrame = false;
-
- if (mTargetTimeUs >= 0) {
- CHECK(timeUs <= mTargetTimeUs);
-
- if (timeUs < mTargetTimeUs) {
- // We're still waiting for the frame with the matching
- // timestamp and we won't return the current one.
- skipFrame = true;
-
- LOGV("skipping frame at %lld us", timeUs);
- } else {
- LOGV("found target frame at %lld us", timeUs);
-
- mTargetTimeUs = -1;
- }
- }
-
- if (skipFrame) {
- *out = new MediaBuffer(0);
- } else {
- *out = mFrames[mNumSamplesOutput & 0x01];
- (*out)->add_ref();
- (*out)->meta_data()->setInt64(kKeyTime, timeUs);
- }
-
- ++mNumSamplesOutput;
-
- return OK;
-}
-
-void M4vH263Decoder::releaseFrames() {
- for (size_t i = 0; i < sizeof(mFrames) / sizeof(mFrames[0]); ++i) {
- MediaBuffer *buffer = mFrames[i];
-
- buffer->setObserver(NULL);
- buffer->release();
-
- mFrames[i] = NULL;
- }
-}
-
-void M4vH263Decoder::signalBufferReturned(MediaBuffer *buffer) {
- LOGV("signalBufferReturned");
-}
-
-
-} // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index cffbfb5..ddced5f 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -23,11 +23,31 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
#include "mp4dec_api.h"
namespace android {
+static const CodecProfileLevel kM4VProfileLevels[] = {
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
+};
+
+static const CodecProfileLevel kH263ProfileLevels[] = {
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level10 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level20 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 },
+};
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -181,6 +201,39 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoProfileLevelQuerySupported:
+ {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+ (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+ if (profileLevel->nPortIndex != 0) { // Input port only
+ LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+ return OMX_ErrorUnsupportedIndex;
+ }
+
+ size_t index = profileLevel->nProfileIndex;
+ if (mMode == MODE_H263) {
+ size_t nProfileLevels =
+ sizeof(kH263ProfileLevels) / sizeof(kH263ProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kH263ProfileLevels[index].mProfile;
+ profileLevel->eLevel = kH263ProfileLevels[index].mLevel;
+ } else {
+ size_t nProfileLevels =
+ sizeof(kM4VProfileLevels) / sizeof(kM4VProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kM4VProfileLevels[index].mProfile;
+ profileLevel->eLevel = kM4VProfileLevels[index].mLevel;
+ }
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 229988e..a08c9f0 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- MP3Decoder.cpp \
src/pvmp3_normalize.cpp \
src/pvmp3_alias_reduction.cpp \
src/pvmp3_crc.cpp \
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
deleted file mode 100644
index 0ba42ff..0000000
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MP3Decoder"
-
-#include "MP3Decoder.h"
-
-#include "include/pvmp3decoder_api.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
- : mSource(source),
- mNumChannels(0),
- mStarted(false),
- mBufferGroup(NULL),
- mConfig(new tPVMP3DecoderExternal),
- mDecoderBuf(NULL),
- mAnchorTimeUs(0),
- mNumFramesOutput(0),
- mInputBuffer(NULL) {
- init();
-}
-
-void MP3Decoder::init() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t sampleRate;
- CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- mMeta->setInt32(kKeyChannelCount, mNumChannels);
- mMeta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- mMeta->setInt64(kKeyDuration, durationUs);
- }
-
- mMeta->setCString(kKeyDecoderComponent, "MP3Decoder");
-}
-
-MP3Decoder::~MP3Decoder() {
- if (mStarted) {
- stop();
- }
-
- delete mConfig;
- mConfig = NULL;
-}
-
-status_t MP3Decoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(4608 * 2));
-
- mConfig->equalizerType = flat;
- mConfig->crcEnabled = false;
-
- uint32_t memRequirements = pvmp3_decoderMemRequirements();
- mDecoderBuf = malloc(memRequirements);
-
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumFramesOutput = 0;
- mStarted = true;
-
- return OK;
-}
-
-status_t MP3Decoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- free(mDecoderBuf);
- mDecoderBuf = NULL;
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> MP3Decoder::getFormat() {
- return mMeta;
-}
-
-status_t MP3Decoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumFramesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumFramesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
-
- mConfig->pInputBuffer =
- (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
- mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
-
- mConfig->outputFrameSize = buffer->size() / sizeof(int16_t);
- mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data());
-
- ERROR_CODE decoderErr;
- if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
- != NO_DECODING_ERROR) {
- LOGV("mp3 decoder returned error %d", decoderErr);
-
- if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
- mConfig->outputFrameSize == 0) {
-
- if (mConfig->outputFrameSize == 0) {
- LOGE("Output frame size is 0");
- }
- buffer->release();
- buffer = NULL;
-
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- return UNKNOWN_ERROR;
- }
-
- // This is recoverable, just ignore the current frame and
- // play silence instead.
- memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
- mConfig->inputBufferUsedLength = mInputBuffer->range_length();
- }
-
- buffer->set_range(
- 0, mConfig->outputFrameSize * sizeof(int16_t));
-
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
- mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumFramesOutput * 1000000) / mConfig->samplingRate);
-
- mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 832b885..32bbd6b 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -2,24 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- VPXDecoder.cpp \
-
-LOCAL_MODULE := libstagefright_vpxdec
-
-LOCAL_C_INCLUDES := \
- $(TOP)/frameworks/base/media/libstagefright/include \
- frameworks/base/include/media/stagefright/openmax \
- $(TOP)/external/libvpx \
- $(TOP)/external/libvpx/vpx_codec \
- $(TOP)/external/libvpx/vpx_ports
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
SoftVPX.cpp
LOCAL_C_INCLUDES := \
@@ -30,7 +12,6 @@
frameworks/base/include/media/stagefright/openmax \
LOCAL_STATIC_LIBRARIES := \
- libstagefright_vpxdec \
libvpx
LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
deleted file mode 100644
index 489e5ad..0000000
--- a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VPXDecoder"
-#include <utils/Log.h>
-
-#include "VPXDecoder.h"
-
-#include <OMX_Component.h>
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include "vpx/vpx_decoder.h"
-#include "vpx/vpx_codec.h"
-#include "vpx/vp8dx.h"
-
-namespace android {
-
-VPXDecoder::VPXDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferSize(0),
- mCtx(NULL),
- mBufferGroup(NULL),
- mTargetTimeUs(-1) {
- sp<MetaData> inputFormat = source->getFormat();
- const char *mime;
- CHECK(inputFormat->findCString(kKeyMIMEType, &mime));
- CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_VPX));
-
- CHECK(inputFormat->findInt32(kKeyWidth, &mWidth));
- CHECK(inputFormat->findInt32(kKeyHeight, &mHeight));
-
- mBufferSize = (mWidth * mHeight * 3) / 2;
-
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- mFormat->setInt32(kKeyWidth, mWidth);
- mFormat->setInt32(kKeyHeight, mHeight);
- mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- mFormat->setCString(kKeyDecoderComponent, "VPXDecoder");
-
- int64_t durationUs;
- if (inputFormat->findInt64(kKeyDuration, &durationUs)) {
- mFormat->setInt64(kKeyDuration, durationUs);
- }
-}
-
-VPXDecoder::~VPXDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t VPXDecoder::start(MetaData *) {
- if (mStarted) {
- return UNKNOWN_ERROR;
- }
-
- status_t err = mSource->start();
-
- if (err != OK) {
- return err;
- }
-
- mCtx = new vpx_codec_ctx_t;
- vpx_codec_err_t vpx_err;
- if ((vpx_err = vpx_codec_dec_init(
- (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0))) {
- LOGE("on2 decoder failed to initialize. (%d)", vpx_err);
-
- mSource->stop();
-
- return UNKNOWN_ERROR;
- }
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
-
- mTargetTimeUs = -1;
-
- mStarted = true;
-
- return OK;
-}
-
-status_t VPXDecoder::stop() {
- if (!mStarted) {
- return UNKNOWN_ERROR;
- }
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
- delete (vpx_codec_ctx_t *)mCtx;
- mCtx = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> VPXDecoder::getFormat() {
- return mFormat;
-}
-
-status_t VPXDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
-
- bool seeking = false;
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- seeking = true;
- }
-
- MediaBuffer *input;
- status_t err = mSource->read(&input, options);
-
- if (err != OK) {
- return err;
- }
-
- LOGV("read %d bytes from source\n", input->range_length());
-
- if (seeking) {
- int64_t targetTimeUs;
- if (input->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
-
- if (vpx_codec_decode(
- (vpx_codec_ctx_t *)mCtx,
- (uint8_t *)input->data() + input->range_offset(),
- input->range_length(),
- NULL,
- 0)) {
- LOGE("on2 decoder failed to decode frame.");
- input->release();
- input = NULL;
-
- return UNKNOWN_ERROR;
- }
-
- LOGV("successfully decoded 1 or more frames.");
-
- int64_t timeUs;
- CHECK(input->meta_data()->findInt64(kKeyTime, &timeUs));
-
- input->release();
- input = NULL;
-
- bool skipFrame = false;
-
- if (mTargetTimeUs >= 0) {
- CHECK(timeUs <= mTargetTimeUs);
-
- if (timeUs < mTargetTimeUs) {
- // We're still waiting for the frame with the matching
- // timestamp and we won't return the current one.
- skipFrame = true;
-
- LOGV("skipping frame at %lld us", timeUs);
- } else {
- LOGV("found target frame at %lld us", timeUs);
-
- mTargetTimeUs = -1;
- }
- }
-
- if (skipFrame) {
- *out = new MediaBuffer(0);
- return OK;
- }
-
- vpx_codec_iter_t iter = NULL;
- vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
-
- if (img == NULL) {
- // The VPX format supports "internal-only" frames that are
- // referenced by future content but never actually displayed, so
- // this is a perfectly valid scenario.
-
- *out = new MediaBuffer(0);
- return OK;
- }
-
- CHECK_EQ(img->fmt, IMG_FMT_I420);
-
- int32_t width = img->d_w;
- int32_t height = img->d_h;
-
- if (width != mWidth || height != mHeight) {
- LOGI("Image dimensions changed, width = %d, height = %d",
- width, height);
-
- mWidth = width;
- mHeight = height;
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
-
- mBufferSize = (mWidth * mHeight * 3) / 2;
- delete mBufferGroup;
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
-
- return INFO_FORMAT_CHANGED;
- }
-
- MediaBuffer *output;
- CHECK_EQ(mBufferGroup->acquire_buffer(&output), OK);
-
- const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
- uint8_t *dst = (uint8_t *)output->data();
- for (size_t i = 0; i < img->d_h; ++i) {
- memcpy(dst, srcLine, img->d_w);
-
- srcLine += img->stride[PLANE_Y];
- dst += img->d_w;
- }
-
- srcLine = (const uint8_t *)img->planes[PLANE_U];
- for (size_t i = 0; i < img->d_h / 2; ++i) {
- memcpy(dst, srcLine, img->d_w / 2);
-
- srcLine += img->stride[PLANE_U];
- dst += img->d_w / 2;
- }
-
- srcLine = (const uint8_t *)img->planes[PLANE_V];
- for (size_t i = 0; i < img->d_h / 2; ++i) {
- memcpy(dst, srcLine, img->d_w / 2);
-
- srcLine += img->stride[PLANE_V];
- dst += img->d_w / 2;
- }
-
- output->set_range(0, (width * height * 3) / 2);
-
- output->meta_data()->setInt64(kKeyTime, timeUs);
-
- *out = output;
-
- return OK;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index ec7bd1c..740c957 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -23,10 +23,30 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
namespace android {
+static const CodecProfileLevel kProfileLevels[] = {
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
+};
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -177,6 +197,28 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoProfileLevelQuerySupported:
+ {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+ (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+ if (profileLevel->nPortIndex != kInputPortIndex) {
+ LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+ return OMX_ErrorUnsupportedIndex;
+ }
+
+ size_t index = profileLevel->nProfileIndex;
+ size_t nProfileLevels =
+ sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kProfileLevels[index].mProfile;
+ profileLevel->eLevel = kProfileLevels[index].mLevel;
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 9251229..f33f3ac 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -2,21 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- VorbisDecoder.cpp \
-
-LOCAL_C_INCLUDES := \
- frameworks/base/media/libstagefright/include \
- external/tremolo \
-
-LOCAL_MODULE := libstagefright_vorbisdec
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
SoftVorbis.cpp
LOCAL_C_INCLUDES := \
@@ -24,9 +9,6 @@
frameworks/base/media/libstagefright/include \
frameworks/base/include/media/stagefright/openmax \
-LOCAL_STATIC_LIBRARIES := \
- libstagefright_vorbisdec
-
LOCAL_SHARED_LIBRARIES := \
libvorbisidec libstagefright libstagefright_omx \
libstagefright_foundation libutils
diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
deleted file mode 100644
index e14fb95..0000000
--- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VorbisDecoder"
-#include <utils/Log.h>
-
-#include "VorbisDecoder.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-extern "C" {
- #include <Tremolo/codec_internal.h>
-
- int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
- int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
- int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
-}
-
-namespace android {
-
-VorbisDecoder::VorbisDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mAnchorTimeUs(0),
- mNumFramesOutput(0),
- mState(NULL),
- mVi(NULL) {
- sp<MetaData> srcFormat = mSource->getFormat();
- CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
- CHECK(srcFormat->findInt32(kKeySampleRate, &mSampleRate));
-}
-
-VorbisDecoder::~VorbisDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-static void makeBitReader(
- const void *data, size_t size,
- ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
- buf->data = (uint8_t *)data;
- buf->size = size;
- buf->refcount = 1;
- buf->ptr.owner = NULL;
-
- ref->buffer = buf;
- ref->begin = 0;
- ref->length = size;
- ref->next = NULL;
-
- oggpack_readinit(bits, ref);
-}
-
-status_t VorbisDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kMaxNumSamplesPerBuffer * sizeof(int16_t)));
-
- mSource->start();
-
- sp<MetaData> meta = mSource->getFormat();
-
- mVi = new vorbis_info;
- vorbis_info_init(mVi);
-
- ///////////////////////////////////////////////////////////////////////////
-
- uint32_t type;
- const void *data;
- size_t size;
- CHECK(meta->findData(kKeyVorbisInfo, &type, &data, &size));
-
- ogg_buffer buf;
- ogg_reference ref;
- oggpack_buffer bits;
- makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
- CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
-
- ///////////////////////////////////////////////////////////////////////////
-
- CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
-
- makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
- CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
-
- ///////////////////////////////////////////////////////////////////////////
-
- mState = new vorbis_dsp_state;
- CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
-
- mAnchorTimeUs = 0;
- mNumFramesOutput = 0;
-
- // If the source never limits the number of valid frames contained
- // in the input data, we'll assume that all of the decoded frames are
- // valid.
- mNumFramesLeftOnPage = -1;
-
- mStarted = true;
-
- return OK;
-}
-
-status_t VorbisDecoder::stop() {
- CHECK(mStarted);
-
- vorbis_dsp_clear(mState);
- delete mState;
- mState = NULL;
-
- vorbis_info_clear(mVi);
- delete mVi;
- mVi = NULL;
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> VorbisDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, mNumChannels);
- meta->setInt32(kKeySampleRate, mSampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "VorbisDecoder");
-
- return meta;
-}
-
-int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) {
- ogg_buffer buf;
- buf.data = (uint8_t *)packet->data() + packet->range_offset();
- buf.size = packet->range_length();
- buf.refcount = 1;
- buf.ptr.owner = NULL;
-
- ogg_reference ref;
- ref.buffer = &buf;
- ref.begin = 0;
- ref.length = packet->range_length();
- ref.next = NULL;
-
- ogg_packet pack;
- pack.packet = &ref;
- pack.bytes = packet->range_length();
- pack.b_o_s = 0;
- pack.e_o_s = 0;
- pack.granulepos = 0;
- pack.packetno = 0;
-
- int numFrames = 0;
-
- int err = vorbis_dsp_synthesis(mState, &pack, 1);
- if (err != 0) {
- LOGW("vorbis_dsp_synthesis returned %d", err);
- } else {
- numFrames = vorbis_dsp_pcmout(
- mState, (int16_t *)out->data(), kMaxNumSamplesPerBuffer);
-
- if (numFrames < 0) {
- LOGE("vorbis_dsp_pcmout returned %d", numFrames);
- numFrames = 0;
- }
- }
-
- if (mNumFramesLeftOnPage >= 0) {
- if (numFrames > mNumFramesLeftOnPage) {
- LOGV("discarding %d frames at end of page",
- numFrames - mNumFramesLeftOnPage);
- numFrames = mNumFramesLeftOnPage;
- }
- mNumFramesLeftOnPage -= numFrames;
- }
-
- out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels);
-
- return numFrames;
-}
-
-status_t VorbisDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumFramesOutput = 0;
- vorbis_dsp_restart(mState);
- } else {
- seekTimeUs = -1;
- }
-
- MediaBuffer *inputBuffer;
- err = mSource->read(&inputBuffer, options);
-
- if (err != OK) {
- return ERROR_END_OF_STREAM;
- }
-
- int64_t timeUs;
- if (inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumFramesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
-
- int32_t numPageSamples;
- if (inputBuffer->meta_data()->findInt32(
- kKeyValidSamples, &numPageSamples)) {
- CHECK(numPageSamples >= 0);
- mNumFramesLeftOnPage = numPageSamples;
- }
-
- MediaBuffer *outputBuffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK);
-
- int numFrames = decodePacket(inputBuffer, outputBuffer);
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- outputBuffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumFramesOutput * 1000000ll) / mSampleRate);
-
- mNumFramesOutput += numFrames;
-
- *out = outputBuffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index e069b4d..95f2ae8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -291,7 +291,7 @@
void finishSeekIfNecessary(int64_t videoTimeUs);
void ensureCacheIsFetching_l();
- status_t startAudioPlayer_l();
+ status_t startAudioPlayer_l(bool sendErrorNotification = true);
void postAudioSeekComplete_l();
void shutdownVideoDecoder_l();
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index 2e25dd9..0e9af69 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -53,6 +53,8 @@
static sp<HTTPBase> Create(uint32_t flags = 0);
+ static void RegisterSocketUser(int s, uid_t uid);
+
protected:
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
diff --git a/media/libstagefright/include/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
deleted file mode 100644
index 88ba9d6..0000000
--- a/media/libstagefright/include/HTTPStream.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HTTP_STREAM_H_
-
-#define HTTP_STREAM_H_
-
-#include <sys/types.h>
-
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class HTTPStream {
-public:
- HTTPStream();
- ~HTTPStream();
-
- void setUID(uid_t uid);
-
- status_t connect(const char *server, int port = -1, bool https = false);
- status_t disconnect();
-
- status_t send(const char *data, size_t size);
-
- // Assumes data is a '\0' terminated string.
- status_t send(const char *data);
-
- // Receive up to "size" bytes of data.
- ssize_t receive(void *data, size_t size);
-
- status_t receive_header(int *http_status);
-
- // The header key used to retrieve the status line.
- static const char *kStatusKey;
-
- bool find_header_value(
- const AString &key, AString *value) const;
-
- // Pass a negative value to disable the timeout.
- void setReceiveTimeout(int seconds);
-
- // Receive a line of data terminated by CRLF, line will be '\0' terminated
- // _excluding_ the termianting CRLF.
- status_t receive_line(char *line, size_t size);
-
- static void RegisterSocketUser(int s, uid_t uid);
-
-private:
- enum State {
- READY,
- CONNECTING,
- CONNECTED
- };
-
- State mState;
- Mutex mLock;
-
- bool mUIDValid;
- uid_t mUID;
-
- int mSocket;
-
- KeyedVector<AString, AString> mHeaders;
-
- void *mSSLContext;
- void *mSSL;
-
- HTTPStream(const HTTPStream &);
- HTTPStream &operator=(const HTTPStream &);
-};
-
-} // namespace android
-
-#endif // HTTP_STREAM_H_
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
deleted file mode 100644
index c265b3a..0000000
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NU_HTTP_DATA_SOURCE_H_
-
-#define NU_HTTP_DATA_SOURCE_H_
-
-#include <utils/List.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-#include "HTTPStream.h"
-#include "include/HTTPBase.h"
-
-namespace android {
-
-struct NuHTTPDataSource : public HTTPBase {
- NuHTTPDataSource(uint32_t flags = 0);
-
- virtual status_t connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- off64_t offset = 0);
-
- virtual void disconnect();
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
- virtual status_t getSize(off64_t *size);
- virtual uint32_t flags();
-
- virtual sp<DecryptHandle> DrmInitialization();
- virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
- virtual String8 getUri();
-
- virtual String8 getMIMEType() const;
-
-protected:
- virtual ~NuHTTPDataSource();
-
-private:
- enum State {
- DISCONNECTED,
- CONNECTING,
- CONNECTED
- };
-
- Mutex mLock;
-
- uint32_t mFlags;
-
- State mState;
-
- String8 mHost;
- unsigned mPort;
- String8 mPath;
- bool mHTTPS;
- String8 mHeaders;
- String8 mUri;
-
- HTTPStream mHTTP;
- off64_t mOffset;
- off64_t mContentLength;
- bool mContentLengthValid;
- bool mHasChunkedTransferEncoding;
-
- String8 mContentType;
-
- // The number of data bytes in the current chunk before any subsequent
- // chunk header (or -1 if no more chunks).
- ssize_t mChunkDataBytesLeft;
-
- sp<DecryptHandle> mDecryptHandle;
- DrmManagerClient *mDrmManagerClient;
-
- status_t connect(
- const char *uri, const String8 &headers, off64_t offset);
-
- status_t connect(
- const char *host, unsigned port, const char *path,
- bool https,
- const String8 &headers,
- off64_t offset);
-
- // Read up to "size" bytes of data, respect transfer encoding.
- ssize_t internalRead(void *data, size_t size);
-
- void applyTimeoutResponse();
-
- static void MakeFullHeaders(
- const KeyedVector<String8, String8> *overrides,
- String8 *headers);
-
- NuHTTPDataSource(const NuHTTPDataSource &);
- NuHTTPDataSource &operator=(const NuHTTPDataSource &);
-};
-
-} // namespace android
-
-#endif // NU_HTTP_DATA_SOURCE_H_
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index ec3e5fa..d54b1c1 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -121,6 +121,7 @@
virtual ~OMX();
private:
+ struct CallbackDispatcherThread;
struct CallbackDispatcher;
Mutex mLock;
diff --git a/media/libstagefright/include/ThreadedSource.h b/media/libstagefright/include/ThreadedSource.h
deleted file mode 100644
index c67295c..0000000
--- a/media/libstagefright/include/ThreadedSource.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef THREADED_SOURCE_H_
-
-#define THREADED_SOURCE_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct ThreadedSource : public MediaSource {
- ThreadedSource(const sp<MediaSource> &source);
-
- virtual status_t start(MetaData *params);
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
- virtual ~ThreadedSource();
-
-private:
- enum {
- kWhatDecodeMore = 'deco',
- kWhatSeek = 'seek',
- };
-
- sp<MediaSource> mSource;
- sp<AHandlerReflector<ThreadedSource> > mReflector;
- sp<ALooper> mLooper;
-
- Mutex mLock;
- Condition mCondition;
- List<MediaBuffer *> mQueue;
- status_t mFinalResult;
- bool mDecodePending;
- bool mStarted;
-
- int64_t mSeekTimeUs;
- ReadOptions::SeekMode mSeekMode;
-
- void postDecodeMore_l();
- void clearQueue_l();
-
- DISALLOW_EVIL_CONSTRUCTORS(ThreadedSource);
-};
-
-} // namespace android
-
-#endif // THREADED_SOURCE_H_
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index d23aa3a..25f30d6 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -20,8 +20,6 @@
#include <dlfcn.h>
-#include <sys/prctl.h>
-
#include "../include/OMX.h"
#include "../include/OMXNodeInstance.h"
@@ -38,11 +36,32 @@
////////////////////////////////////////////////////////////////////////////////
+// This provides the underlying Thread used by CallbackDispatcher.
+// Note that deriving CallbackDispatcher from Thread does not work.
+
+struct OMX::CallbackDispatcherThread : public Thread {
+ CallbackDispatcherThread(CallbackDispatcher *dispatcher)
+ : mDispatcher(dispatcher) {
+ }
+
+private:
+ CallbackDispatcher *mDispatcher;
+
+ bool threadLoop();
+
+ CallbackDispatcherThread(const CallbackDispatcherThread &);
+ CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
struct OMX::CallbackDispatcher : public RefBase {
CallbackDispatcher(OMXNodeInstance *owner);
void post(const omx_message &msg);
+ bool loop();
+
protected:
virtual ~CallbackDispatcher();
@@ -54,13 +73,10 @@
Condition mQueueChanged;
List<omx_message> mQueue;
- pthread_t mThread;
+ sp<CallbackDispatcherThread> mThread;
void dispatch(const omx_message &msg);
- static void *ThreadWrapper(void *me);
- void threadEntry();
-
CallbackDispatcher(const CallbackDispatcher &);
CallbackDispatcher &operator=(const CallbackDispatcher &);
};
@@ -68,13 +84,8 @@
OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
: mOwner(owner),
mDone(false) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- pthread_create(&mThread, &attr, ThreadWrapper, this);
-
- pthread_attr_destroy(&attr);
+ mThread = new CallbackDispatcherThread(this);
+ mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO);
}
OMX::CallbackDispatcher::~CallbackDispatcher() {
@@ -86,10 +97,8 @@
}
// Don't call join on myself
- CHECK(mThread != pthread_self());
-
- void *dummy;
- pthread_join(mThread, &dummy);
+ status_t status = mThread->join();
+ CHECK(status == NO_ERROR);
}
void OMX::CallbackDispatcher::post(const omx_message &msg) {
@@ -107,17 +116,7 @@
mOwner->onMessage(msg);
}
-// static
-void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
- static_cast<CallbackDispatcher *>(me)->threadEntry();
-
- return NULL;
-}
-
-void OMX::CallbackDispatcher::threadEntry() {
- androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
- prctl(PR_SET_NAME, (unsigned long)"OMXCallbackDisp", 0, 0, 0);
-
+bool OMX::CallbackDispatcher::loop() {
for (;;) {
omx_message msg;
@@ -137,6 +136,14 @@
dispatch(msg);
}
+
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool OMX::CallbackDispatcherThread::threadLoop() {
+ return mDispatcher->loop();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 072d6b2..b398c9d 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -34,7 +34,7 @@
#include <openssl/md5.h>
#include <sys/socket.h>
-#include "HTTPStream.h"
+#include "HTTPBase.h"
namespace android {
@@ -251,7 +251,7 @@
mSocket = socket(AF_INET, SOCK_STREAM, 0);
if (mUIDValid) {
- HTTPStream::RegisterSocketUser(mSocket, mUID);
+ HTTPBase::RegisterSocketUser(mSocket, mUID);
}
MakeSocketBlocking(mSocket, false);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3188959..71d68f6 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -40,7 +40,7 @@
#include <sys/socket.h>
#include <netdb.h>
-#include "HTTPStream.h"
+#include "HTTPBase.h"
// If no access units are received within 5 secs, assume that the rtp
// stream has ended and signal end of stream.
@@ -1181,8 +1181,8 @@
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
if (mUIDValid) {
- HTTPStream::RegisterSocketUser(info->mRTPSocket, mUID);
- HTTPStream::RegisterSocketUser(info->mRTCPSocket, mUID);
+ HTTPBase::RegisterSocketUser(info->mRTPSocket, mUID);
+ HTTPBase::RegisterSocketUser(info->mRTCPSocket, mUID);
}
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 8ba235b..935f4ad 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -689,13 +689,11 @@
switch (simState) {
case ABSENT:
- case PERM_DISABLED:
// only force lock screen in case of missing sim if user hasn't
// gone through setup wizard
if (!mUpdateMonitor.isDeviceProvisioned()) {
if (!isShowing()) {
- if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_ABSENT "
- + "or PERM_DISABLED and keygaurd isn't showing,"
+ if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing,"
+ " we need to show the keyguard since the "
+ "device isn't provisioned yet.");
doKeyguard();
@@ -713,7 +711,17 @@
} else {
resetStateLocked();
}
-
+ break;
+ case PERM_DISABLED:
+ if (!isShowing()) {
+ if (DEBUG) Log.d(TAG, "PERM_DISABLED and "
+ + "keygaurd isn't showing.");
+ doKeyguard();
+ } else {
+ if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ + "show permanently disabled message in lockscreen.");
+ resetStateLocked();
+ }
break;
case READY:
if (isShowing()) {
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 75e799c..e177565 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -75,6 +75,7 @@
private StatusView mStatusView;
private final boolean mUseSystemIME = true; // TODO: Make configurable
+ private boolean mResuming; // used to prevent poking the wakelock during onResume()
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
@@ -185,7 +186,9 @@
}
public void afterTextChanged(Editable s) {
- mCallback.pokeWakelock();
+ if (!mResuming) {
+ mCallback.pokeWakelock();
+ }
}
});
}
@@ -208,6 +211,7 @@
/** {@inheritDoc} */
public void onResume() {
+ mResuming = true;
// reset status
mStatusView.resetStatusInfo(mUpdateMonitor, mLockPatternUtils);
@@ -222,6 +226,7 @@
if (deadline != 0) {
handleAttemptLockout(deadline);
}
+ mResuming = false;
}
/** {@inheritDoc} */
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 47ca3a0..8e16d94 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -48,9 +48,6 @@
static const int kDumpLockSleep = 20000;
static bool checkPermission() {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index f86ca47..e390ae20 100644
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -29,7 +29,6 @@
#include <camera/ICamera.h>
#include <camera/ICameraClient.h>
#include <camera/ICameraService.h>
-#include <ui/Overlay.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -311,8 +310,6 @@
virtual status_t registerBuffers(const BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation);
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
virtual status_t setBufferCount(int bufferCount);
@@ -381,13 +378,6 @@
}
}
-sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
- int32_t orientation) {
- // Not implemented.
- ASSERT(0);
- return NULL;
-}
-
//
// Utilities to use the Holder service
//
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index cc80062..8902f7a 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -26,26 +26,32 @@
namespace android {
/*
- * A handle to an application that can receive input.
- * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * Describes the properties of an application that can receive input.
+ *
+ * Used by the native input dispatcher as a handle for the window manager objects
* that describe an application.
*/
class InputApplicationHandle : public RefBase {
+public:
+ String8 name;
+ nsecs_t dispatchingTimeout;
+
+ /**
+ * Requests that the state of this object be updated to reflect
+ * the most current available information about the application.
+ *
+ * This method should only be called from within the input dispatcher's
+ * critical section.
+ *
+ * Returns true on success, or false if the handle is no longer valid.
+ */
+ virtual bool update() = 0;
+
protected:
InputApplicationHandle() { }
virtual ~InputApplicationHandle() { }
};
-
-/*
- * An input application describes properties of an application that can receive input.
- */
-struct InputApplication {
- sp<InputApplicationHandle> inputApplicationHandle;
- String8 name;
- nsecs_t dispatchingTimeout;
-};
-
} // namespace android
#endif // _UI_INPUT_APPLICATION_H
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index da9b55c..1cac5025 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -211,11 +211,8 @@
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false),
- mFocusedWindow(NULL),
- mFocusedApplication(NULL),
mCurrentInputTargetsValid(false),
- mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE),
- mLastHoverWindow(NULL) {
+ mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
mInboundQueue.headSentinel.refCount = -1;
@@ -501,16 +498,15 @@
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
- && mInputTargetWaitApplication != NULL) {
+ && mInputTargetWaitApplicationHandle != NULL) {
int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
- const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y);
- if (touchedWindow
- && touchedWindow->inputWindowHandle != NULL
- && touchedWindow->inputWindowHandle->getInputApplicationHandle()
- != mInputTargetWaitApplication) {
+ sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
+ if (touchedWindowHandle != NULL
+ && touchedWindowHandle->inputApplicationHandle
+ != mInputTargetWaitApplicationHandle) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
@@ -524,25 +520,25 @@
return needWake;
}
-const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
+sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
// Traverse windows from front to back to find touched window.
- size_t numWindows = mWindows.size();
+ size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* window = & mWindows.editItemAt(i);
- int32_t flags = window->layoutParamsFlags;
+ sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ int32_t flags = windowHandle->layoutParamsFlags;
- if (window->visible) {
- if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
- bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
- | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
+ if (windowHandle->visible) {
+ if (!(flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
+ bool isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
+ | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
// Found window.
- return window;
+ return windowHandle;
}
}
}
- if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
+ if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
// Error window is on top but not visible, so touch is dropped.
return NULL;
}
@@ -781,8 +777,8 @@
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
- if (mFocusedWindow) {
- commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle;
+ if (mFocusedWindowHandle != NULL) {
+ commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
@@ -1011,7 +1007,7 @@
mCurrentInputTargetsValid = false;
mCurrentInputTargets.clear();
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
- mInputTargetWaitApplication.clear();
+ mInputTargetWaitApplicationHandle.clear();
}
void InputDispatcher::commitTargetsLocked() {
@@ -1019,9 +1015,11 @@
}
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
- const EventEntry* entry, const InputApplication* application, const InputWindow* window,
+ const EventEntry* entry,
+ const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime) {
- if (application == NULL && window == NULL) {
+ if (applicationHandle == NULL && windowHandle == NULL) {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
#if DEBUG_FOCUS
LOGD("Waiting for system to become ready for input.");
@@ -1030,29 +1028,29 @@
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplication.clear();
+ mInputTargetWaitApplicationHandle.clear();
}
} else {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
#if DEBUG_FOCUS
LOGD("Waiting for application to become ready for input: %s",
- getApplicationWindowLabelLocked(application, window).string());
+ getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
#endif
- nsecs_t timeout = window ? window->dispatchingTimeout :
- application ? application->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+ nsecs_t timeout = windowHandle != NULL ? windowHandle->dispatchingTimeout :
+ applicationHandle != NULL ?
+ applicationHandle->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = currentTime + timeout;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplication.clear();
+ mInputTargetWaitApplicationHandle.clear();
- if (window && window->inputWindowHandle != NULL) {
- mInputTargetWaitApplication =
- window->inputWindowHandle->getInputApplicationHandle();
+ if (windowHandle != NULL) {
+ mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
}
- if (mInputTargetWaitApplication == NULL && application) {
- mInputTargetWaitApplication = application->inputApplicationHandle;
+ if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
+ mInputTargetWaitApplicationHandle = applicationHandle;
}
}
}
@@ -1062,7 +1060,8 @@
}
if (currentTime >= mInputTargetWaitTimeoutTime) {
- onANRLocked(currentTime, application, window, entry->eventTime, mInputTargetWaitStartTime);
+ onANRLocked(currentTime, applicationHandle, windowHandle,
+ entry->eventTime, mInputTargetWaitStartTime);
// Force poll loop to wake up immediately on next iteration once we get the
// ANR response back from the policy.
@@ -1129,15 +1128,15 @@
// If there is no currently focused window and no focused application
// then drop the event.
- if (! mFocusedWindow) {
- if (mFocusedApplication) {
+ if (mFocusedWindowHandle == NULL) {
+ if (mFocusedApplicationHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Waiting because there is no focused window but there is a "
"focused application that may eventually add a window: %s.",
- getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
+ getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, NULL, nextWakeupTime);
+ mFocusedApplicationHandle, NULL, nextWakeupTime);
goto Unresponsive;
}
@@ -1147,34 +1146,34 @@
}
// Check permissions.
- if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
+ if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
}
// If the currently focused window is paused then keep waiting.
- if (mFocusedWindow->paused) {
+ if (mFocusedWindowHandle->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window is paused.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
+ mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
goto Unresponsive;
}
// If the currently focused window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
+ if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window still processing previous input.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
+ mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
goto Unresponsive;
}
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow,
+ addWindowTargetLocked(mFocusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
// Done.
@@ -1236,7 +1235,7 @@
// Update the touch state as needed based on the properties of the touch event.
int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
- const InputWindow* newHoverWindow = NULL;
+ sp<InputWindowHandle> newHoverWindowHandle;
bool isSplit = mTouchState.split;
bool switchedDevice = mTouchState.deviceId >= 0
@@ -1279,42 +1278,44 @@
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(sample->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
- const InputWindow* newTouchedWindow = NULL;
- const InputWindow* topErrorWindow = NULL;
+ sp<InputWindowHandle> newTouchedWindowHandle;
+ sp<InputWindowHandle> topErrorWindowHandle;
bool isTouchModal = false;
// Traverse windows from front to back to find touched window and outside targets.
- size_t numWindows = mWindows.size();
+ size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* window = & mWindows.editItemAt(i);
- int32_t flags = window->layoutParamsFlags;
+ sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ int32_t flags = windowHandle->layoutParamsFlags;
- if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
- if (! topErrorWindow) {
- topErrorWindow = window;
+ if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+ if (topErrorWindowHandle == NULL) {
+ topErrorWindowHandle = windowHandle;
}
}
- if (window->visible) {
- if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
- isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
- | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
- if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
- newTouchedWindow = window;
+ if (windowHandle->visible) {
+ if (! (flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
+ isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
+ | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+ if (! screenWasOff
+ || (flags & InputWindowHandle::FLAG_TOUCHABLE_WHEN_WAKING)) {
+ newTouchedWindowHandle = windowHandle;
}
break; // found touched window, exit window loop
}
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
+ && (flags & InputWindowHandle::FLAG_WATCH_OUTSIDE_TOUCH)) {
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
- if (isWindowObscuredAtPointLocked(window, x, y)) {
+ if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
- mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
+ mTempTouchState.addOrUpdateWindow(
+ windowHandle, outsideTargetFlags, BitSet32(0));
}
}
}
@@ -1322,7 +1323,7 @@
// If there is an error window but it is not taking focus (typically because
// it is invisible) then wait for it. Any other focused window may in
// fact be in ANR state.
- if (topErrorWindow && newTouchedWindow != topErrorWindow) {
+ if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) {
#if DEBUG_FOCUS
LOGD("Waiting because system error window is pending.");
#endif
@@ -1333,26 +1334,26 @@
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindow && newTouchedWindow->supportsSplitTouch()) {
+ if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->supportsSplitTouch()) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
// New window does not support splitting but we have already split events.
// Assign the pointer to the first foreground window we find.
// (May be NULL which is why we put this code block before the next check.)
- newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
+ newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
}
// If we did not find a touched window then fail.
- if (! newTouchedWindow) {
- if (mFocusedApplication) {
+ if (newTouchedWindowHandle == NULL) {
+ if (mFocusedApplicationHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Waiting because there is no touched window but there is a "
"focused application that may eventually add a new window: %s.",
- getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
+ getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, NULL, nextWakeupTime);
+ mFocusedApplicationHandle, NULL, nextWakeupTime);
goto Unresponsive;
}
@@ -1366,20 +1367,20 @@
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
- if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+ if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
// Update hover state.
if (isHoverAction) {
- newHoverWindow = newTouchedWindow;
+ newHoverWindowHandle = newTouchedWindowHandle;
// Ensure all subsequent motion samples are also within the touched window.
// Set *outSplitBatchAfterSample to the sample before the first one that is not
// within the touched window.
if (!isTouchModal) {
while (sample->next) {
- if (!newHoverWindow->touchableRegionContainsPoint(
+ if (!newHoverWindowHandle->touchableRegionContainsPoint(
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
*outSplitBatchAfterSample = sample;
@@ -1389,7 +1390,7 @@
}
}
} else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
- newHoverWindow = mLastHoverWindow;
+ newHoverWindowHandle = mLastHoverWindowHandle;
}
// Update the temporary touch state.
@@ -1398,7 +1399,7 @@
uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
pointerIds.markBit(pointerId);
}
- mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+ mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -1420,19 +1421,22 @@
int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- const InputWindow* oldTouchedWindow = mTempTouchState.getFirstForegroundWindow();
- const InputWindow* newTouchedWindow = findTouchedWindowAtLocked(x, y);
- if (oldTouchedWindow != newTouchedWindow && newTouchedWindow) {
+ sp<InputWindowHandle> oldTouchedWindowHandle =
+ mTempTouchState.getFirstForegroundWindowHandle();
+ sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(x, y);
+ if (oldTouchedWindowHandle != newTouchedWindowHandle
+ && newTouchedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Touch is slipping out of window %s into window %s.",
- oldTouchedWindow->name.string(), newTouchedWindow->name.string());
+ oldTouchedWindowHandle->name.string(),
+ newTouchedWindowHandle->name.string());
#endif
// Make a slippery exit from the old window.
- mTempTouchState.addOrUpdateWindow(oldTouchedWindow,
+ mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
// Make a slippery entrance into the new window.
- if (newTouchedWindow->supportsSplitTouch()) {
+ if (newTouchedWindowHandle->supportsSplitTouch()) {
isSplit = true;
}
@@ -1441,7 +1445,7 @@
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
- if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+ if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
@@ -1449,7 +1453,7 @@
if (isSplit) {
pointerIds.markBit(entry->pointerProperties[0].id);
}
- mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+ mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
// Split the batch here so we send exactly one sample.
*outSplitBatchAfterSample = &entry->firstSample;
@@ -1457,25 +1461,25 @@
}
}
- if (newHoverWindow != mLastHoverWindow) {
+ if (newHoverWindowHandle != mLastHoverWindowHandle) {
// Split the batch here so we send exactly one sample as part of ENTER or EXIT.
*outSplitBatchAfterSample = &entry->firstSample;
// Let the previous window know that the hover sequence is over.
- if (mLastHoverWindow) {
+ if (mLastHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string());
+ LOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->name.string());
#endif
- mTempTouchState.addOrUpdateWindow(mLastHoverWindow,
+ mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
}
// Let the new window know that the hover sequence is starting.
- if (newHoverWindow) {
+ if (newHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string());
+ LOGD("Sending hover enter event to window %s.", newHoverWindowHandle->name.string());
#endif
- mTempTouchState.addOrUpdateWindow(newHoverWindow,
+ mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
}
}
@@ -1488,7 +1492,8 @@
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
haveForegroundWindow = true;
- if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) {
+ if (! checkInjectionPermission(touchedWindow.windowHandle,
+ entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
injectionPermission = INJECTION_PERMISSION_DENIED;
goto Failed;
@@ -1510,14 +1515,15 @@
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
- const int32_t foregroundWindowUid = foregroundWindow->ownerUid;
+ sp<InputWindowHandle> foregroundWindowHandle =
+ mTempTouchState.getFirstForegroundWindowHandle();
+ const int32_t foregroundWindowUid = foregroundWindowHandle->ownerUid;
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- const InputWindow* inputWindow = touchedWindow.window;
- if (inputWindow->ownerUid != foregroundWindowUid) {
- mTempTouchState.addOrUpdateWindow(inputWindow,
+ sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
+ if (inputWindowHandle->ownerUid != foregroundWindowUid) {
+ mTempTouchState.addOrUpdateWindow(inputWindowHandle,
InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
}
}
@@ -1529,22 +1535,22 @@
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// If the touched window is paused then keep waiting.
- if (touchedWindow.window->paused) {
+ if (touchedWindow.windowHandle->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because touched window is paused.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- NULL, touchedWindow.window, nextWakeupTime);
+ NULL, touchedWindow.windowHandle, nextWakeupTime);
goto Unresponsive;
}
// If the touched window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) {
+ if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
LOGD("Waiting because touched window still processing previous input.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- NULL, touchedWindow.window, nextWakeupTime);
+ NULL, touchedWindow.windowHandle, nextWakeupTime);
goto Unresponsive;
}
}
@@ -1557,12 +1563,13 @@
// engine only supports touch events. We would need to add a mechanism similar
// to View.onGenericMotionEvent to enable wallpapers to handle these events.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
- if (foregroundWindow->hasWallpaper) {
- for (size_t i = 0; i < mWindows.size(); i++) {
- const InputWindow* window = & mWindows[i];
- if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
- mTempTouchState.addOrUpdateWindow(window,
+ sp<InputWindowHandle> foregroundWindowHandle =
+ mTempTouchState.getFirstForegroundWindowHandle();
+ if (foregroundWindowHandle->hasWallpaper) {
+ for (size_t i = 0; i < mWindowHandles.size(); i++) {
+ sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ if (windowHandle->layoutParamsType == InputWindowHandle::TYPE_WALLPAPER) {
+ mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0));
@@ -1576,7 +1583,7 @@
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
- addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags,
+ addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds);
}
@@ -1658,7 +1665,7 @@
}
// Update hover state.
- mLastHoverWindow = newHoverWindow;
+ mLastHoverWindowHandle = newHoverWindowHandle;
}
} else {
#if DEBUG_FOCUS
@@ -1681,16 +1688,16 @@
return injectionResult;
}
-void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
- BitSet32 pointerIds) {
+void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds) {
mCurrentInputTargets.push();
InputTarget& target = mCurrentInputTargets.editTop();
- target.inputChannel = window->inputChannel;
+ target.inputChannel = windowHandle->inputChannel;
target.flags = targetFlags;
- target.xOffset = - window->frameLeft;
- target.yOffset = - window->frameTop;
- target.scaleFactor = window->scaleFactor;
+ target.xOffset = - windowHandle->frameLeft;
+ target.yOffset = - windowHandle->frameTop;
+ target.scaleFactor = windowHandle->scaleFactor;
target.pointerIds = pointerIds;
}
@@ -1708,17 +1715,17 @@
}
}
-bool InputDispatcher::checkInjectionPermission(const InputWindow* window,
+bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState
- && (window == NULL || window->ownerUid != injectionState->injectorUid)
+ && (windowHandle == NULL || windowHandle->ownerUid != injectionState->injectorUid)
&& !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
- if (window) {
- LOGW("Permission denied: injecting event from pid %d uid %d to window "
- "with input channel %s owned by uid %d",
+ if (windowHandle != NULL) {
+ LOGW("Permission denied: injecting event from pid %d uid %d to window %s "
+ "owned by uid %d",
injectionState->injectorPid, injectionState->injectorUid,
- window->inputChannel->getName().string(),
- window->ownerUid);
+ windowHandle->name.string(),
+ windowHandle->ownerUid);
} else {
LOGW("Permission denied: injecting event from pid %d uid %d",
injectionState->injectorPid, injectionState->injectorUid);
@@ -1729,22 +1736,24 @@
}
bool InputDispatcher::isWindowObscuredAtPointLocked(
- const InputWindow* window, int32_t x, int32_t y) const {
- size_t numWindows = mWindows.size();
+ const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
+ size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* other = & mWindows.itemAt(i);
- if (other == window) {
+ sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ if (otherHandle == windowHandle) {
break;
}
- if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) {
+ if (otherHandle->visible && ! otherHandle->isTrustedOverlay()
+ && otherHandle->frameContainsPoint(x, y)) {
return true;
}
}
return false;
}
-bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* window) {
- ssize_t connectionIndex = getConnectionIndexLocked(window->inputChannel);
+bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
+ const sp<InputWindowHandle>& windowHandle) {
+ ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
return connection->outboundQueue.isEmpty();
@@ -1753,19 +1762,20 @@
}
}
-String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* application,
- const InputWindow* window) {
- if (application) {
- if (window) {
- String8 label(application->name);
+String8 InputDispatcher::getApplicationWindowLabelLocked(
+ const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle) {
+ if (applicationHandle != NULL) {
+ if (windowHandle != NULL) {
+ String8 label(applicationHandle->name);
label.append(" - ");
- label.append(window->name);
+ label.append(windowHandle->name);
return label;
} else {
- return application->name;
+ return applicationHandle->name;
}
- } else if (window) {
- return window->name;
+ } else if (windowHandle != NULL) {
+ return windowHandle->name;
} else {
return String8("<unknown application or window>");
}
@@ -2422,11 +2432,11 @@
}
InputTarget target;
- const InputWindow* window = getWindowLocked(connection->inputChannel);
- if (window) {
- target.xOffset = -window->frameLeft;
- target.yOffset = -window->frameTop;
- target.scaleFactor = window->scaleFactor;
+ sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
+ if (windowHandle != NULL) {
+ target.xOffset = -windowHandle->frameLeft;
+ target.yOffset = -windowHandle->frameTop;
+ target.scaleFactor = windowHandle->scaleFactor;
} else {
target.xOffset = 0;
target.yOffset = 0;
@@ -2809,7 +2819,7 @@
}
if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- if (!mLastHoverWindow) {
+ if (mLastHoverWindowHandle == NULL) {
#if DEBUG_BATCHING
LOGD("Not streaming hover move because there is no "
"last hovered window.");
@@ -2817,15 +2827,16 @@
goto NoBatchingOrStreaming;
}
- const InputWindow* hoverWindow = findTouchedWindowAtLocked(
+ sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked(
pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (mLastHoverWindow != hoverWindow) {
+ if (mLastHoverWindowHandle != hoverWindowHandle) {
#if DEBUG_BATCHING
LOGD("Not streaming hover move because the last hovered window "
"is '%s' but the currently hovered window is '%s'.",
- mLastHoverWindow->name.string(),
- hoverWindow ? hoverWindow->name.string() : "<null>");
+ mLastHoverWindowHandle->name.string(),
+ hoverWindowHandle != NULL
+ ? hoverWindowHandle->name.string() : "<null>");
#endif
goto NoBatchingOrStreaming;
}
@@ -3125,111 +3136,109 @@
}
}
-const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) {
- for (size_t i = 0; i < mWindows.size(); i++) {
- const InputWindow* window = & mWindows[i];
- if (window->inputChannel == inputChannel) {
- return window;
+sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
+ const sp<InputChannel>& inputChannel) const {
+ size_t numWindows = mWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+ if (windowHandle->inputChannel == inputChannel) {
+ return windowHandle;
}
}
return NULL;
}
-void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
+bool InputDispatcher::hasWindowHandleLocked(
+ const sp<InputWindowHandle>& windowHandle) const {
+ size_t numWindows = mWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ if (mWindowHandles.itemAt(i) == windowHandle) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
#if DEBUG_FOCUS
LOGD("setInputWindows");
#endif
{ // acquire lock
AutoMutex _l(mLock);
- // Clear old window pointers.
- sp<InputChannel> oldFocusedWindowChannel;
- if (mFocusedWindow) {
- oldFocusedWindowChannel = mFocusedWindow->inputChannel;
- mFocusedWindow = NULL;
- }
- sp<InputChannel> oldLastHoverWindowChannel;
- if (mLastHoverWindow) {
- oldLastHoverWindowChannel = mLastHoverWindow->inputChannel;
- mLastHoverWindow = NULL;
- }
+ mWindowHandles = inputWindowHandles;
- // Loop over new windows and rebuild the necessary window pointers for
- // tracking focus and touch.
- mWindows = inputWindows;
-
- size_t numWindows = mWindows.size();
- for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* window = & mWindows.itemAt(i);
- if (window->hasFocus) {
- mFocusedWindow = window;
- break;
+ sp<InputWindowHandle> newFocusedWindowHandle;
+ bool foundHoveredWindow = false;
+ for (size_t i = 0; i < mWindowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+ if (!windowHandle->update() || windowHandle->inputChannel == NULL) {
+ mWindowHandles.removeAt(i--);
+ continue;
+ }
+ if (windowHandle->hasFocus) {
+ newFocusedWindowHandle = windowHandle;
+ }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
}
}
- if (oldFocusedWindowChannel != NULL) {
- if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) {
+ if (!foundHoveredWindow) {
+ mLastHoverWindowHandle = NULL;
+ }
+
+ if (mFocusedWindowHandle != newFocusedWindowHandle) {
+ if (mFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Focus left window: %s",
- oldFocusedWindowChannel->getName().string());
+ mFocusedWindowHandle->name.string());
#endif
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
- synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options);
- oldFocusedWindowChannel.clear();
+ synthesizeCancelationEventsForInputChannelLocked(
+ mFocusedWindowHandle->inputChannel, options);
}
- }
- if (mFocusedWindow && oldFocusedWindowChannel == NULL) {
+ if (newFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
- LOGD("Focus entered window: %s",
- mFocusedWindow->inputChannel->getName().string());
+ LOGD("Focus entered window: %s",
+ newFocusedWindowHandle->name.string());
#endif
+ }
+ mFocusedWindowHandle = newFocusedWindowHandle;
}
- for (size_t i = 0; i < mTouchState.windows.size(); ) {
+ for (size_t i = 0; i < mTouchState.windows.size(); i++) {
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
- const InputWindow* window = getWindowLocked(touchedWindow.channel);
- if (window) {
- touchedWindow.window = window;
- i += 1;
- } else {
+ if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
- LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
+ LOGD("Touched window was removed: %s", touchedWindow.windowHandle->name.string());
#endif
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
- synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options);
- mTouchState.windows.removeAt(i);
+ synthesizeCancelationEventsForInputChannelLocked(
+ touchedWindow.windowHandle->inputChannel, options);
+ mTouchState.windows.removeAt(i--);
}
}
-
- // Recover the last hovered window.
- if (oldLastHoverWindowChannel != NULL) {
- mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel);
- oldLastHoverWindowChannel.clear();
- }
-
-#if DEBUG_FOCUS
- //logDispatchStateLocked();
-#endif
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
-void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) {
+void InputDispatcher::setFocusedApplication(
+ const sp<InputApplicationHandle>& inputApplicationHandle) {
#if DEBUG_FOCUS
LOGD("setFocusedApplication");
#endif
{ // acquire lock
AutoMutex _l(mLock);
- releaseFocusedApplicationLocked();
-
- if (inputApplication) {
- mFocusedApplicationStorage = *inputApplication;
- mFocusedApplication = & mFocusedApplicationStorage;
+ if (inputApplicationHandle != NULL && inputApplicationHandle->update()) {
+ mFocusedApplicationHandle = inputApplicationHandle;
+ } else {
+ mFocusedApplicationHandle.clear();
}
#if DEBUG_FOCUS
@@ -3241,13 +3250,6 @@
mLooper->wake();
}
-void InputDispatcher::releaseFocusedApplicationLocked() {
- if (mFocusedApplication) {
- mFocusedApplication = NULL;
- mFocusedApplicationStorage.inputApplicationHandle.clear();
- }
-}
-
void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
#if DEBUG_FOCUS
LOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
@@ -3313,15 +3315,15 @@
{ // acquire lock
AutoMutex _l(mLock);
- const InputWindow* fromWindow = getWindowLocked(fromChannel);
- const InputWindow* toWindow = getWindowLocked(toChannel);
- if (! fromWindow || ! toWindow) {
+ sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
+ sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
+ if (fromWindowHandle == NULL || toWindowHandle == NULL) {
#if DEBUG_FOCUS
LOGD("Cannot transfer focus because from or to window not found.");
#endif
return false;
}
- if (fromWindow == toWindow) {
+ if (fromWindowHandle == toWindowHandle) {
#if DEBUG_FOCUS
LOGD("Trivial transfer to same window.");
#endif
@@ -3331,7 +3333,7 @@
bool found = false;
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTouchState.windows[i];
- if (touchedWindow.window == fromWindow) {
+ if (touchedWindow.windowHandle == fromWindowHandle) {
int32_t oldTargetFlags = touchedWindow.targetFlags;
BitSet32 pointerIds = touchedWindow.pointerIds;
@@ -3340,7 +3342,7 @@
int32_t newTargetFlags = oldTargetFlags
& (InputTarget::FLAG_FOREGROUND
| InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
- mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
+ mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
found = true;
break;
@@ -3390,7 +3392,7 @@
resetTargetsLocked();
mTouchState.reset();
- mLastHoverWindow = NULL;
+ mLastHoverWindowHandle.clear();
}
void InputDispatcher::logDispatchStateLocked() {
@@ -3413,15 +3415,15 @@
dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
- if (mFocusedApplication) {
+ if (mFocusedApplicationHandle != NULL) {
dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
- mFocusedApplication->name.string(),
- mFocusedApplication->dispatchingTimeout / 1000000.0);
+ mFocusedApplicationHandle->name.string(),
+ mFocusedApplicationHandle->dispatchingTimeout / 1000000.0);
} else {
dump.append(INDENT "FocusedApplication: <null>\n");
}
dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
- mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>");
+ mFocusedWindowHandle != NULL ? mFocusedWindowHandle->name.string() : "<null>");
dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
@@ -3432,37 +3434,37 @@
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTouchState.windows[i];
dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
- i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value,
+ i, touchedWindow.windowHandle->name.string(), touchedWindow.pointerIds.value,
touchedWindow.targetFlags);
}
} else {
dump.append(INDENT "TouchedWindows: <none>\n");
}
- if (!mWindows.isEmpty()) {
+ if (!mWindowHandles.isEmpty()) {
dump.append(INDENT "Windows:\n");
- for (size_t i = 0; i < mWindows.size(); i++) {
- const InputWindow& window = mWindows[i];
+ for (size_t i = 0; i < mWindowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], scale=%f, "
"touchableRegion=",
- i, window.name.string(),
- toString(window.paused),
- toString(window.hasFocus),
- toString(window.hasWallpaper),
- toString(window.visible),
- toString(window.canReceiveKeys),
- window.layoutParamsFlags, window.layoutParamsType,
- window.layer,
- window.frameLeft, window.frameTop,
- window.frameRight, window.frameBottom,
- window.scaleFactor);
- dumpRegion(dump, window.touchableRegion);
- dump.appendFormat(", inputFeatures=0x%08x", window.inputFeatures);
+ i, windowHandle->name.string(),
+ toString(windowHandle->paused),
+ toString(windowHandle->hasFocus),
+ toString(windowHandle->hasWallpaper),
+ toString(windowHandle->visible),
+ toString(windowHandle->canReceiveKeys),
+ windowHandle->layoutParamsFlags, windowHandle->layoutParamsType,
+ windowHandle->layer,
+ windowHandle->frameLeft, windowHandle->frameTop,
+ windowHandle->frameRight, windowHandle->frameBottom,
+ windowHandle->scaleFactor);
+ dumpRegion(dump, windowHandle->touchableRegion);
+ dump.appendFormat(", inputFeatures=0x%08x", windowHandle->inputFeatures);
dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
- window.ownerPid, window.ownerUid,
- window.dispatchingTimeout / 1000000.0);
+ windowHandle->ownerPid, windowHandle->ownerUid,
+ windowHandle->dispatchingTimeout / 1000000.0);
}
} else {
dump.append(INDENT "Windows: <none>\n");
@@ -3634,23 +3636,19 @@
}
void InputDispatcher::onANRLocked(
- nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+ nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime) {
LOGI("Application is not responding: %s. "
"%01.1fms since event, %01.1fms since wait started",
- getApplicationWindowLabelLocked(application, window).string(),
+ getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
(currentTime - eventTime) / 1000000.0,
(currentTime - waitStartTime) / 1000000.0);
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
- if (application) {
- commandEntry->inputApplicationHandle = application->inputApplicationHandle;
- }
- if (window) {
- commandEntry->inputWindowHandle = window->inputWindowHandle;
- commandEntry->inputChannel = window->inputChannel;
- }
+ commandEntry->inputApplicationHandle = applicationHandle;
+ commandEntry->inputWindowHandle = windowHandle;
}
void InputDispatcher::doNotifyConfigurationChangedInterruptible(
@@ -3684,7 +3682,9 @@
mLock.lock();
- resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel);
+ resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
+ commandEntry->inputWindowHandle != NULL
+ ? commandEntry->inputWindowHandle->inputChannel : NULL);
}
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -4561,7 +4561,7 @@
windows = other.windows;
}
-void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
+void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds) {
if (targetFlags & InputTarget::FLAG_SPLIT) {
split = true;
@@ -4569,7 +4569,7 @@
for (size_t i = 0; i < windows.size(); i++) {
TouchedWindow& touchedWindow = windows.editItemAt(i);
- if (touchedWindow.window == window) {
+ if (touchedWindow.windowHandle == windowHandle) {
touchedWindow.targetFlags |= targetFlags;
if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
@@ -4582,10 +4582,9 @@
windows.push();
TouchedWindow& touchedWindow = windows.editTop();
- touchedWindow.window = window;
+ touchedWindow.windowHandle = windowHandle;
touchedWindow.targetFlags = targetFlags;
touchedWindow.pointerIds = pointerIds;
- touchedWindow.channel = window->inputChannel;
}
void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
@@ -4602,11 +4601,11 @@
}
}
-const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() const {
+sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows.itemAt(i);
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- return window.window;
+ return window.windowHandle;
}
}
return NULL;
@@ -4618,8 +4617,8 @@
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows.itemAt(i);
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- if (haveSlipperyForegroundWindow
- || !(window.window->layoutParamsFlags & InputWindow::FLAG_SLIPPERY)) {
+ if (haveSlipperyForegroundWindow || !(window.windowHandle->layoutParamsFlags
+ & InputWindowHandle::FLAG_SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index bdd1922..15fd274 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -321,13 +321,14 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0;
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
/* Sets the focused application.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setFocusedApplication(const InputApplication* inputApplication) = 0;
+ virtual void setFocusedApplication(
+ const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
/* Sets the input dispatching mode.
*
@@ -406,8 +407,8 @@
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags);
- virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
- virtual void setFocusedApplication(const InputApplication* inputApplication);
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+ virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void setInputFilterEnabled(bool enabled);
@@ -578,7 +579,6 @@
sp<Connection> connection;
nsecs_t eventTime;
KeyEntry* keyEntry;
- sp<InputChannel> inputChannel;
sp<InputApplicationHandle> inputApplicationHandle;
sp<InputWindowHandle> inputWindowHandle;
int32_t userActivityEventType;
@@ -894,7 +894,7 @@
// to transfer focus to a new application.
EventEntry* mNextUnblockedEvent;
- const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y);
+ sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
// All registered connections mapped by receive pipe file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
@@ -953,19 +953,19 @@
bool mDispatchFrozen;
bool mInputFilterEnabled;
- Vector<InputWindow> mWindows;
+ Vector<sp<InputWindowHandle> > mWindowHandles;
- const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel);
+ sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+ bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
// Focus tracking for keys, trackball, etc.
- const InputWindow* mFocusedWindow;
+ sp<InputWindowHandle> mFocusedWindowHandle;
// Focus tracking for touch.
struct TouchedWindow {
- const InputWindow* window;
+ sp<InputWindowHandle> windowHandle;
int32_t targetFlags;
BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
- sp<InputChannel> channel;
};
struct TouchState {
bool down;
@@ -978,9 +978,10 @@
~TouchState();
void reset();
void copyFrom(const TouchState& other);
- void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds);
+ void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds);
void filterNonAsIsTouchWindows();
- const InputWindow* getFirstForegroundWindow() const;
+ sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
};
@@ -988,9 +989,7 @@
TouchState mTempTouchState;
// Focused application.
- InputApplication* mFocusedApplication;
- InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
- void releaseFocusedApplicationLocked();
+ sp<InputApplicationHandle> mFocusedApplicationHandle;
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(
@@ -1021,16 +1020,17 @@
nsecs_t mInputTargetWaitStartTime;
nsecs_t mInputTargetWaitTimeoutTime;
bool mInputTargetWaitTimeoutExpired;
- sp<InputApplicationHandle> mInputTargetWaitApplication;
+ sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
// Contains the last window which received a hover event.
- const InputWindow* mLastHoverWindow;
+ sp<InputWindowHandle> mLastHoverWindowHandle;
// Finding targets for input events.
void resetTargetsLocked();
void commitTargetsLocked();
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
- const InputApplication* application, const InputWindow* window,
+ const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime);
void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
const sp<InputChannel>& inputChannel);
@@ -1043,15 +1043,17 @@
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
const MotionSample** outSplitBatchAfterSample);
- void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
- BitSet32 pointerIds);
+ void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds);
void addMonitoringTargetsLocked();
void pokeUserActivityLocked(const EventEntry* eventEntry);
- bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
- bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const;
- bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
- String8 getApplicationWindowLabelLocked(const InputApplication* application,
- const InputWindow* window);
+ bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
+ const InjectionState* injectionState);
+ bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
+ int32_t x, int32_t y) const;
+ bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
+ String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle);
// Manage the dispatch cycle for a single connection.
// These methods are deliberately not Interruptible because doing all of the work
@@ -1100,7 +1102,8 @@
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onANRLocked(
- nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+ nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime);
// Outbound policy interactions.
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index b552f6d..0ce8867 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -22,25 +22,25 @@
namespace android {
-// --- InputWindow ---
+// --- InputWindowHandle ---
-bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const {
return touchableRegion.contains(x, y);
}
-bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight
&& y >= frameTop && y <= frameBottom;
}
-bool InputWindow::isTrustedOverlay() const {
+bool InputWindowHandle::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
-bool InputWindow::supportsSplitTouch() const {
- return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH;
+bool InputWindowHandle::supportsSplitTouch() const {
+ return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
} // namespace android
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index d166ad4..272081c 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -31,29 +31,14 @@
/*
* A handle to a window that can receive input.
+ *
* Used by the native input dispatcher to indirectly refer to the window manager objects
* that describe a window.
*/
class InputWindowHandle : public RefBase {
-protected:
- InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- mInputApplicationHandle(inputApplicationHandle) { }
- virtual ~InputWindowHandle() { }
-
public:
- inline sp<InputApplicationHandle> getInputApplicationHandle() {
- return mInputApplicationHandle;
- }
+ const sp<InputApplicationHandle> inputApplicationHandle;
-private:
- sp<InputApplicationHandle> mInputApplicationHandle;
-};
-
-
-/*
- * An input window describes the bounds of a window that can receive input.
- */
-struct InputWindow {
// Window flags from WindowManager.LayoutParams
enum {
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
@@ -164,6 +149,22 @@
bool isTrustedOverlay() const;
bool supportsSplitTouch() const;
+
+ /**
+ * Requests that the state of this object be updated to reflect
+ * the most current available information about the application.
+ *
+ * This method should only be called from within the input dispatcher's
+ * critical section.
+ *
+ * Returns true on success, or false if the handle is no longer valid.
+ */
+ virtual bool update() = 0;
+
+protected:
+ InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+ inputApplicationHandle(inputApplicationHandle) { }
+ virtual ~InputWindowHandle() { }
};
} // namespace android
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 67067de..131894a 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -369,11 +369,12 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- virtual void setInputWindows(const Vector<InputWindow>& inputWindows) {
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
ADD_FAILURE() << "Should never be called by input reader.";
}
- virtual void setFocusedApplication(const InputApplication* inputApplication) {
+ virtual void setFocusedApplication(
+ const sp<InputApplicationHandle>& inputApplicationHandle) {
ADD_FAILURE() << "Should never be called by input reader.";
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 786f2fa..168b894 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -76,6 +76,7 @@
import com.android.internal.backup.LocalTransport;
import com.android.server.PackageManagerBackupAgent.Metadata;
+import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
@@ -96,6 +97,10 @@
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
@@ -1679,6 +1684,7 @@
class PerformFullBackupTask implements Runnable {
ParcelFileDescriptor mOutputFile;
+ DeflaterOutputStream mDeflater;
IFullBackupRestoreObserver mObserver;
boolean mIncludeApks;
boolean mIncludeShared;
@@ -1688,6 +1694,55 @@
File mFilesDir;
File mManifestFile;
+ class FullBackupRunner implements Runnable {
+ PackageInfo mPackage;
+ IBackupAgent mAgent;
+ ParcelFileDescriptor mPipe;
+ int mToken;
+ boolean mSendApk;
+
+ FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
+ int token, boolean sendApk) throws IOException {
+ mPackage = pack;
+ mAgent = agent;
+ mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
+ mToken = token;
+ mSendApk = sendApk;
+ }
+
+ @Override
+ public void run() {
+ try {
+ BackupDataOutput output = new BackupDataOutput(
+ mPipe.getFileDescriptor());
+
+ if (DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
+ writeAppManifest(mPackage, mManifestFile, mSendApk);
+ FullBackup.backupToTar(mPackage.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+
+ if (mSendApk) {
+ writeApkToBackup(mPackage, output);
+ }
+
+ if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
+ prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL);
+ mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
+ } catch (IOException e) {
+ Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote agent vanished during full backup of "
+ + mPackage.packageName);
+ } finally {
+ try {
+ mPipe.close();
+ } catch (IOException e) {}
+ }
+ }
+ }
+
PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
boolean includeApks, boolean includeShared,
boolean doAllApps, String[] packages, AtomicBoolean latch) {
@@ -1736,13 +1791,21 @@
}
}
+ // Set up the compression stage
+ FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
+ Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
+ DeflaterOutputStream out = new DeflaterOutputStream(ofstream, deflater, true);
+
+ // !!! TODO: if using encryption, set up the encryption stage
+ // and emit the tar header stating the password salt.
+
PackageInfo pkg = null;
try {
// Now back up the app data via the agent mechanism
int N = packagesToBackup.size();
for (int i = 0; i < N; i++) {
pkg = packagesToBackup.get(i);
- backupOnePackage(pkg);
+ backupOnePackage(pkg, out);
}
// Finally, shared storage if requested
@@ -1754,6 +1817,7 @@
} finally {
tearDown(pkg);
try {
+ out.close();
mOutputFile.close();
} catch (IOException e) {
/* nothing we can do about this */
@@ -1771,13 +1835,17 @@
}
}
- private void backupOnePackage(PackageInfo pkg) throws RemoteException {
+ private void backupOnePackage(PackageInfo pkg, DeflaterOutputStream out)
+ throws RemoteException {
Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
IApplicationThread.BACKUP_MODE_FULL);
if (agent != null) {
+ ParcelFileDescriptor[] pipes = null;
try {
+ pipes = ParcelFileDescriptor.createPipe();
+
ApplicationInfo app = pkg.applicationInfo;
final boolean sendApk = mIncludeApks
&& ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
@@ -1786,31 +1854,54 @@
sendOnBackupPackage(pkg.packageName);
- BackupDataOutput output = new BackupDataOutput(
- mOutputFile.getFileDescriptor());
+ final int token = generateToken();
+ FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
+ token, sendApk);
+ pipes[1].close(); // the runner has dup'd it
+ pipes[1] = null;
+ Thread t = new Thread(runner);
+ t.start();
- if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
- writeAppManifest(pkg, mManifestFile, sendApk);
- FullBackup.backupToTar(pkg.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ // Now pull data from the app and stuff it into the compressor
+ try {
+ FileInputStream raw = new FileInputStream(pipes[0].getFileDescriptor());
+ DataInputStream in = new DataInputStream(raw);
- if (sendApk) {
- writeApkToBackup(pkg, output);
+ byte[] buffer = new byte[16 * 1024];
+ int chunkTotal;
+ while ((chunkTotal = in.readInt()) > 0) {
+ while (chunkTotal > 0) {
+ int toRead = (chunkTotal > buffer.length)
+ ? buffer.length : chunkTotal;
+ int nRead = in.read(buffer, 0, toRead);
+ out.write(buffer, 0, nRead);
+ chunkTotal -= nRead;
+ }
+ }
+ } catch (IOException e) {
+ Slog.i(TAG, "Caught exception reading from agent", e);
}
- if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
- final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
} else {
- if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName);
+ if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
}
+
} catch (IOException e) {
Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+ } finally {
+ try {
+ if (pipes != null) {
+ if (pipes[0] != null) pipes[0].close();
+ if (pipes[1] != null) pipes[1].close();
+ }
+
+ // Apply a full sync/flush after each application's data
+ out.flush();
+ } catch (IOException e) {
+ Slog.w(TAG, "Error bringing down backup stack");
+ }
}
} else {
Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
@@ -2084,11 +2175,12 @@
try {
mBytes = 0;
byte[] buffer = new byte[32 * 1024];
- FileInputStream instream = new FileInputStream(mInputFile.getFileDescriptor());
+ FileInputStream rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
+ InflaterInputStream in = new InflaterInputStream(rawInStream);
boolean didRestore;
do {
- didRestore = restoreOneFile(instream, buffer);
+ didRestore = restoreOneFile(in, buffer);
} while (didRestore);
if (DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 41450d2..85891a2 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -33,7 +33,9 @@
import android.net.IConnectivityManager;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.LinkProperties.CompareAddressesResult;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
@@ -76,6 +78,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
@@ -92,6 +96,7 @@
public class ConnectivityService extends IConnectivityManager.Stub {
private static final boolean DBG = true;
+ private static final boolean VDBG = true;
private static final String TAG = "ConnectivityService";
private static final boolean LOGD_RULES = false;
@@ -126,6 +131,11 @@
private NetworkStateTracker mNetTrackers[];
/**
+ * The link properties that define the current links
+ */
+ private LinkProperties mCurrentLinkProperties[];
+
+ /**
* A per Net list of the PID's that requested access to the net
* used both as a refcount and for per-PID DNS selection
*/
@@ -332,6 +342,7 @@
mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
mNetworkPreference = getPersistedNetworkPreference();
@@ -468,6 +479,7 @@
mNetConfigs[netType].radio);
continue;
}
+ mCurrentLinkProperties[netType] = mNetTrackers[netType].getLinkProperties();
}
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1563,6 +1575,8 @@
* right routing table entries exist.
*/
private void handleConnectivityChange(int netType, boolean doReset) {
+ int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+
/*
* If a non-default network is enabled, add the host routes that
* will allow it's DNS servers to be accessed.
@@ -1570,6 +1584,45 @@
handleDnsConfigurationChange(netType);
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+ LinkProperties newLp = mNetTrackers[netType].getLinkProperties();
+ LinkProperties curLp = mCurrentLinkProperties[netType];
+ mCurrentLinkProperties[netType] = newLp;
+ if (VDBG) {
+ log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
+ " doReset=" + doReset + " resetMask=" + resetMask +
+ "\n curLp=" + curLp +
+ "\n newLp=" + newLp);
+ }
+
+ if (curLp.isIdenticalInterfaceName(newLp)) {
+ CompareAddressesResult car = curLp.compareAddresses(newLp);
+ if ((car.removed.size() != 0) || (car.added.size() != 0)) {
+ for (LinkAddress linkAddr : car.removed) {
+ if (linkAddr.getAddress() instanceof Inet4Address) {
+ resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
+ }
+ if (linkAddr.getAddress() instanceof Inet6Address) {
+ resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
+ }
+ }
+ if (DBG) {
+ log("handleConnectivityChange: addresses changed" +
+ " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
+ "\n car=" + car);
+ }
+ } else {
+ if (DBG) {
+ log("handleConnectivityChange: address are the same reset per doReset" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
+ }
+ } else {
+ resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
+ log("handleConnectivityChange: interface not not equivalent reset both" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
if (mNetConfigs[netType].isDefault()) {
handleApplyDefaultProxy(netType);
addDefaultRoute(mNetTrackers[netType]);
@@ -1597,15 +1650,13 @@
}
}
- if (doReset) {
+ if (doReset || resetMask != 0) {
LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
if (linkProperties != null) {
String iface = linkProperties.getInterfaceName();
if (TextUtils.isEmpty(iface) == false) {
- if (DBG) {
- log("resetConnections(" + iface + ", NetworkUtils.RESET_ALL_ADDRESSES)");
- }
- NetworkUtils.resetConnections(iface, NetworkUtils.RESET_ALL_ADDRESSES);
+ if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
+ NetworkUtils.resetConnections(iface, resetMask);
}
}
}
diff --git a/services/java/com/android/server/LoadAverageService.java b/services/java/com/android/server/LoadAverageService.java
index da9fc99..e05b570 100644
--- a/services/java/com/android/server/LoadAverageService.java
+++ b/services/java/com/android/server/LoadAverageService.java
@@ -28,7 +28,6 @@
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
-import android.view.WindowManagerImpl;
public class LoadAverageService extends Service {
private View mView;
@@ -91,32 +90,46 @@
setPadding(4, 4, 4, 4);
//setBackgroundResource(com.android.internal.R.drawable.load_average_background);
+ // Need to scale text size by density... but we won't do it
+ // linearly, because with higher dps it is nice to squeeze the
+ // text a bit to fit more of it. And with lower dps, trying to
+ // go much smaller will result in unreadable text.
+ int textSize = 10;
+ float density = c.getResources().getDisplayMetrics().density;
+ if (density < 1) {
+ textSize = 9;
+ } else {
+ textSize = (int)(10*density);
+ if (textSize < 10) {
+ textSize = 10;
+ }
+ }
mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
- mLoadPaint.setTextSize(10);
+ mLoadPaint.setTextSize(textSize);
mLoadPaint.setARGB(255, 255, 255, 255);
mAddedPaint = new Paint();
mAddedPaint.setAntiAlias(true);
- mAddedPaint.setTextSize(10);
+ mAddedPaint.setTextSize(textSize);
mAddedPaint.setARGB(255, 128, 255, 128);
mRemovedPaint = new Paint();
mRemovedPaint.setAntiAlias(true);
mRemovedPaint.setStrikeThruText(true);
- mRemovedPaint.setTextSize(10);
+ mRemovedPaint.setTextSize(textSize);
mRemovedPaint.setARGB(255, 255, 128, 128);
mShadowPaint = new Paint();
mShadowPaint.setAntiAlias(true);
- mShadowPaint.setTextSize(10);
+ mShadowPaint.setTextSize(textSize);
//mShadowPaint.setFakeBoldText(true);
mShadowPaint.setARGB(192, 0, 0, 0);
mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
mShadow2Paint = new Paint();
mShadow2Paint.setAntiAlias(true);
- mShadow2Paint.setTextSize(10);
+ mShadow2Paint.setTextSize(textSize);
//mShadow2Paint.setFakeBoldText(true);
mShadow2Paint.setARGB(192, 0, 0, 0);
mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
@@ -153,14 +166,16 @@
}
@Override
- protected void onMeasure(int widthMeasureSpect, int heightMeasureSpec) {
- setMeasuredDimension(mNeededWidth, mNeededHeight);
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
+ resolveSize(mNeededHeight, heightMeasureSpec));
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
- final int W = getWidth();
+ final int W = mNeededWidth;
+ final int RIGHT = getWidth()-1;
final Stats stats = mStats;
final int userTime = stats.getLastUserTime();
@@ -178,7 +193,7 @@
int systemW = (systemTime*W)/totalTime;
int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
- int x = W - mPaddingRight;
+ int x = RIGHT - mPaddingRight;
int top = mPaddingTop + 2;
int bottom = mPaddingTop + mFH - 2;
@@ -196,15 +211,15 @@
}
int y = mPaddingTop - (int)mAscent;
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
y-1, mShadowPaint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
y+1, mShadowPaint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
y-1, mShadow2Paint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
y+1, mShadow2Paint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth,
y, mLoadPaint);
int N = stats.countWorkingStats();
@@ -216,7 +231,7 @@
userW = (st.rel_utime*W)/totalTime;
systemW = (st.rel_stime*W)/totalTime;
- x = W - mPaddingRight;
+ x = RIGHT - mPaddingRight;
if (systemW > 0) {
canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
x -= systemW;
@@ -226,18 +241,18 @@
x -= userW;
}
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
y-1, mShadowPaint);
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
y+1, mShadowPaint);
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
y-1, mShadow2Paint);
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
y+1, mShadow2Paint);
Paint p = mLoadPaint;
if (st.added) p = mAddedPaint;
if (st.removed) p = mRemovedPaint;
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth, y, p);
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p);
}
}
@@ -270,7 +285,7 @@
super.onCreate();
mView = new LoadView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 2e54c99..94465fd 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -2361,6 +2361,19 @@
pw.print(" -> "); pw.println(e.getValue().toString());
}
}
+
+ pw.println("");
+
+ synchronized (mVolumes) {
+ pw.println(" mVolumes:");
+
+ final int N = mVolumes.size();
+ for (int i = 0; i < N; i++) {
+ final StorageVolume v = mVolumes.get(i);
+ pw.print(" ");
+ pw.println(v.toString());
+ }
+ }
}
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 829df39..41e8a31 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -196,6 +196,9 @@
} else {
Slog.d(TAG, "not enabling bandwidth control");
}
+
+ SystemProperties.set(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
+ mBandwidthControlEnabled ? "1" : "0");
}
public void registerObserver(INetworkManagementEventObserver obs) {
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 80cdf6b..f99951fa 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1155,9 +1155,7 @@
| AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
- AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END
- | AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START
- | AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
+ AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
| AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
| AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 1af7015..dbd9474 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -838,8 +838,6 @@
*/
private void sendAccessibilityEvent(int eventType) {
AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
- event.setPackageName(mContext.getPackageName());
- event.setClassName(getClass().getName());
mAccessibilityManager.sendAccessibilityEvent(event);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8501163..fd93bcf 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -45,7 +45,6 @@
import android.app.IProcessObserver;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
-import android.app.IThumbnailRetriever;
import android.app.Instrumentation;
import android.app.Notification;
import android.app.NotificationManager;
@@ -54,6 +53,7 @@
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -181,22 +181,8 @@
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
- private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- // This is the maximum number of application processes we would like
- // to have running. Due to the asynchronous nature of things, we can
- // temporarily go beyond this limit.
- static final int MAX_PROCESSES = 2;
-
- // Set to false to leave processes running indefinitely, relying on
- // the kernel killing them as resources are required.
- static final boolean ENFORCE_PROCESS_LIMIT = false;
-
- // This is the maximum number of activities that we would like to have
- // running at a given time.
- static final int MAX_ACTIVITIES = 20;
-
// Maximum number of recent tasks that we can remember.
static final int MAX_RECENT_TASKS = 20;
@@ -914,7 +900,8 @@
*/
boolean mBooted = false;
- int mProcessLimit = 0;
+ int mProcessLimit = MAX_HIDDEN_APPS;
+ int mProcessLimitOverride = -1;
WindowManagerService mWindowManager;
@@ -2291,11 +2278,10 @@
}
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(callingActivity);
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(callingActivity);
+ if (r == null) {
return false;
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
if (r.app == null || r.app.thread == null) {
// The caller is not running... d'oh!
return false;
@@ -2442,11 +2428,10 @@
public void setRequestedOrientation(IBinder token,
int requestedOrientation) {
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
return;
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
mWindowManager.setAppOrientation(r, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -2464,11 +2449,10 @@
public int getRequestedOrientation(IBinder token) {
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return mWindowManager.getAppOrientation(r);
}
}
@@ -2609,11 +2593,10 @@
public final void finishSubActivity(IBinder token, String resultWho,
int requestCode) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord self = mMainStack.isInStackLocked(token);
+ if (self == null) {
return;
}
- ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
@@ -2652,11 +2635,10 @@
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord self = mMainStack.isInStackLocked(token);
+ if (self == null) {
return;
}
- ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
@@ -2735,8 +2717,7 @@
}
}
- r.stack.cleanUpActivityLocked(r, true);
- r.state = ActivityState.STOPPED;
+ r.stack.cleanUpActivityLocked(r, true, true);
}
atTop = false;
}
@@ -3920,20 +3901,9 @@
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- r = (ActivityRecord)mMainStack.mHistory.get(index);
- r.icicle = icicle;
- r.haveState = true;
- r.updateThumbnail(thumbnail, description);
- r.stopped = true;
- r.state = ActivityState.STOPPED;
- if (!r.finishing) {
- if (r.configDestroy) {
- r.stack.destroyActivityLocked(r, true);
- r.stack.resumeTopActivityLocked(null);
- }
- }
+ r = mMainStack.isInStackLocked(token);
+ if (r != null) {
+ r.stack.activityStoppedLocked(r, icicle, thumbnail, description);
}
}
@@ -3966,35 +3936,30 @@
}
private ActivityRecord getCallingRecordLocked(IBinder token) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- if (r != null) {
- return r.resultTo;
- }
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
+ return null;
}
- return null;
+ return r.resultTo;
}
public ComponentName getActivityClassForToken(IBinder token) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- return r.intent.getComponent();
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
+ return null;
}
- return null;
+ return r.intent.getComponent();
}
}
public String getPackageForToken(IBinder token) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- return r.packageName;
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
+ return null;
}
- return null;
+ return r.packageName;
}
}
@@ -4057,11 +4022,10 @@
int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
ActivityRecord activity = null;
if (type == INTENT_SENDER_ACTIVITY_RESULT) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ activity = mMainStack.isInStackLocked(token);
+ if (activity == null) {
return null;
}
- activity = (ActivityRecord)mMainStack.mHistory.get(index);
if (activity.finishing) {
return null;
}
@@ -4183,11 +4147,17 @@
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
- mProcessLimit = max;
+ synchronized (this) {
+ mProcessLimit = max < 0 ? MAX_HIDDEN_APPS : max;
+ mProcessLimitOverride = max;
+ }
+ trimApplications();
}
public int getProcessLimit() {
- return mProcessLimit;
+ synchronized (this) {
+ return mProcessLimitOverride;
+ }
}
void foregroundTokenDied(ForegroundToken token) {
@@ -5451,11 +5421,10 @@
synchronized(this) {
if (r == null) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ r = mMainStack.isInStackLocked(token);
+ if (r == null) {
return;
}
- r = (ActivityRecord)mMainStack.mHistory.get(index);
}
if (thumbnail == null && r.thumbHolder != null) {
thumbnail = r.thumbHolder.lastThumbnail;
@@ -6169,9 +6138,8 @@
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- r = (ActivityRecord)mMainStack.mHistory.get(index);
+ r = mMainStack.isInStackLocked(token);
+ if (r != null) {
mMainStack.activitySleptLocked(r);
}
}
@@ -6322,22 +6290,20 @@
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {
- int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
throw new IllegalArgumentException();
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
r.immersive = immersive;
}
}
public boolean isImmersive(IBinder token) {
synchronized (this) {
- int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
throw new IllegalArgumentException();
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return r.immersive;
}
}
@@ -8800,9 +8766,10 @@
} else {
foreground = " ";
}
- pw.println(String.format("%s%s #%2d: adj=%s/%s%s %s (%s)",
+ pw.println(String.format("%s%s #%2d: adj=%s/%s%s trm=%2d %s (%s)",
prefix, (r.persistent ? persistentLabel : normalLabel),
- N-i, oomAdj, schedGroup, foreground, r.toShortString(), r.adjType));
+ N-i, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
+ r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
pw.print(prefix);
pw.print(" ");
@@ -10337,12 +10304,11 @@
ActivityRecord activity = null;
if (token != null) {
- int aindex = mMainStack.indexOfTokenLocked(token);
- if (aindex < 0) {
+ activity = mMainStack.isInStackLocked(token);
+ if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
- activity = (ActivityRecord)mMainStack.mHistory.get(aindex);
}
int clientLabel = 0;
@@ -11556,8 +11522,8 @@
return false;
}
int state = r.state;
- r.state = r.IDLE;
- if (state == r.IDLE) {
+ r.state = BroadcastRecord.IDLE;
+ if (state == BroadcastRecord.IDLE) {
if (explicit) {
Slog.w(TAG, "finishReceiver called but state is IDLE");
}
@@ -12941,7 +12907,7 @@
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
- long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
+ long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
if (when < (now+GC_TIMEOUT)) {
when = now + GC_TIMEOUT;
@@ -13084,16 +13050,14 @@
}
}
- private final boolean updateOomAdjLocked(
+ private final void updateOomAdjLocked(
ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
app.hiddenAdj = hiddenAdj;
if (app.thread == null) {
- return true;
+ return;
}
- boolean success = true;
-
final boolean wasKeeping = app.keeping;
int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
@@ -13129,10 +13093,10 @@
if (Process.setOomAdj(app.pid, adj)) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set app " + app.processName +
- " oom adj to " + adj);
+ " oom adj to " + adj + " because " + app.adjType);
app.setAdj = adj;
} else {
- success = false;
+ Slog.w(TAG, "Failed setting oom adj of " + app + " to " + adj);
}
}
if (app.setSchedGroup != app.curSchedGroup) {
@@ -13158,8 +13122,7 @@
} finally {
Binder.restoreCallingIdentity(oldId);
}
- }
- if (false) {
+ } else {
if (app.thread != null) {
try {
app.thread.setSchedulingGroup(app.curSchedGroup);
@@ -13169,8 +13132,6 @@
}
}
}
-
- return success;
}
private final ActivityRecord resumedAppLocked() {
@@ -13184,30 +13145,26 @@
return resumedActivity;
}
- private final boolean updateOomAdjLocked(ProcessRecord app) {
+ private final void updateOomAdjLocked(ProcessRecord app) {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
int curAdj = app.curAdj;
- final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
- && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+ final boolean wasHidden = curAdj >= HIDDEN_APP_MIN_ADJ
+ && curAdj <= HIDDEN_APP_MAX_ADJ;
mAdjSeq++;
- final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
- if (res) {
- final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
- && app.curAdj <= HIDDEN_APP_MAX_ADJ;
- if (nowHidden != wasHidden) {
- // Changed to/from hidden state, so apps after it in the LRU
- // list may also be changed.
- updateOomAdjLocked();
- }
+ updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
+ final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
+ && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+ if (nowHidden != wasHidden) {
+ // Changed to/from hidden state, so apps after it in the LRU
+ // list may also be changed.
+ updateOomAdjLocked();
}
- return res;
}
- final boolean updateOomAdjLocked() {
- boolean didOomAdj = true;
+ final void updateOomAdjLocked() {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -13229,45 +13186,104 @@
int step = 0;
int numHidden = 0;
- // First try updating the OOM adjustment for each of the
+ // First update the OOM adjustment for each of the
// application processes based on their current state.
int i = mLruProcesses.size();
int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
+ int numBg = 0;
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
//Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
- if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
- if (curHiddenAdj < EMPTY_APP_ADJ
- && app.curAdj == curHiddenAdj) {
- step++;
- if (step >= factor) {
- step = 0;
- curHiddenAdj++;
- }
+ updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
+ if (curHiddenAdj < EMPTY_APP_ADJ
+ && app.curAdj == curHiddenAdj) {
+ step++;
+ if (step >= factor) {
+ step = 0;
+ curHiddenAdj++;
}
+ }
+ if (!app.killedBackground) {
if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
- if (!app.killedBackground) {
- numHidden++;
- if (numHidden > MAX_HIDDEN_APPS) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): hidden #" + numHidden);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
- }
+ numHidden++;
+ if (numHidden > mProcessLimit) {
+ Slog.i(TAG, "No longer want " + app.processName
+ + " (pid " + app.pid + "): hidden #" + numHidden);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "too many background");
+ app.killedBackground = true;
+ Process.killProcessQuiet(app.pid);
+ } else {
+ numBg++;
}
+ } else if (app.curAdj >= HOME_APP_ADJ) {
+ numBg++;
}
- } else {
- didOomAdj = false;
}
}
- // If we return false, we will fall back on killing processes to
- // have a fixed limit. Do this if a limit has been requested; else
- // only return false if one of the adjustments failed.
- return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
+ // Now determine the memory trimming level of background processes.
+ // Unfortunately we need to start at the back of the list to do this
+ // properly. We only do this if the number of background apps we
+ // are managing to keep around is less than half the maximum we desire;
+ // if we are keeping a good number around, we'll let them use whatever
+ // memory they want.
+ if (numHidden <= (MAX_HIDDEN_APPS/2)) {
+ final int N = mLruProcesses.size();
+ factor = numBg/3;
+ step = 0;
+ int curLevel = ComponentCallbacks.TRIM_MEMORY_COMPLETE;
+ for (i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
+ if (app.trimMemoryLevel < curLevel && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(curLevel);
+ } catch (RemoteException e) {
+ }
+ if (curLevel >= ComponentCallbacks.TRIM_MEMORY_COMPLETE) {
+ // For these apps we will also finish their activities
+ // to help them free memory.
+ mMainStack.destroyActivitiesLocked(app, false);
+ }
+ }
+ app.trimMemoryLevel = curLevel;
+ step++;
+ if (step >= factor) {
+ switch (curLevel) {
+ case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+ curLevel = ComponentCallbacks.TRIM_MEMORY_MODERATE;
+ break;
+ case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+ curLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+ break;
+ }
+ }
+ } else if (app.curAdj >= PERCEPTIBLE_APP_ADJ) {
+ if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_INVISIBLE
+ && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_INVISIBLE);
+ } catch (RemoteException e) {
+ }
+ }
+ app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_INVISIBLE;
+ } else {
+ app.trimMemoryLevel = 0;
+ }
+ }
+ } else {
+ final int N = mLruProcesses.size();
+ for (i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ app.trimMemoryLevel = 0;
+ }
+ }
+
+ if (mAlwaysFinishActivities) {
+ mMainStack.destroyActivitiesLocked(null, false);
+ }
}
final void trimApplications() {
@@ -13307,165 +13323,8 @@
}
}
- // Now try updating the OOM adjustment for each of the
- // application processes based on their current state.
- // If the setOomAdj() API is not supported, then go with our
- // back-up plan...
- if (!updateOomAdjLocked()) {
-
- // Count how many processes are running services.
- int numServiceProcs = 0;
- for (i=mLruProcesses.size()-1; i>=0; i--) {
- final ProcessRecord app = mLruProcesses.get(i);
-
- if (app.persistent || app.services.size() != 0
- || app.curReceiver != null) {
- // Don't count processes holding services against our
- // maximum process count.
- if (localLOGV) Slog.v(
- TAG, "Not trimming app " + app + " with services: "
- + app.services);
- numServiceProcs++;
- }
- }
-
- int curMaxProcs = mProcessLimit;
- if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
- if (mAlwaysFinishActivities) {
- curMaxProcs = 1;
- }
- curMaxProcs += numServiceProcs;
-
- // Quit as many processes as we can to get down to the desired
- // process count. First remove any processes that no longer
- // have activites running in them.
- for ( i=0;
- i<mLruProcesses.size()
- && mLruProcesses.size() > curMaxProcs;
- i++) {
- final ProcessRecord app = mLruProcesses.get(i);
- // Quit an application only if it is not currently
- // running any activities.
- if (!app.persistent && app.activities.size() == 0
- && app.curReceiver == null && app.services.size() == 0) {
- Slog.i(
- TAG, "Exiting empty application process "
- + app.processName + " ("
- + (app.thread != null ? app.thread.asBinder() : null)
- + ")\n");
- if (app.pid > 0 && app.pid != MY_PID) {
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "empty");
- Process.killProcessQuiet(app.pid);
- } else {
- try {
- app.thread.scheduleExit();
- } catch (Exception e) {
- // Ignore exceptions.
- }
- }
- // todo: For now we assume the application is not buggy
- // or evil, and will quit as a result of our request.
- // Eventually we need to drive this off of the death
- // notification, and kill the process if it takes too long.
- cleanUpApplicationRecordLocked(app, false, i);
- i--;
- }
- }
-
- // If we still have too many processes, now from the least
- // recently used process we start finishing activities.
- if (false) Slog.v(
- TAG, "*** NOW HAVE " + mLruProcesses.size() +
- " of " + curMaxProcs + " processes");
- for ( i=0;
- i<mLruProcesses.size()
- && mLruProcesses.size() > curMaxProcs;
- i++) {
- final ProcessRecord app = mLruProcesses.get(i);
- // Quit the application only if we have a state saved for
- // all of its activities.
- boolean canQuit = !app.persistent && app.curReceiver == null
- && app.services.size() == 0;
- int NUMA = app.activities.size();
- int j;
- if (false) Slog.v(
- TAG, "Looking to quit " + app.processName);
- for (j=0; j<NUMA && canQuit; j++) {
- ActivityRecord r = app.activities.get(j);
- if (false) Slog.v(
- TAG, " " + r.intent.getComponent().flattenToShortString()
- + ": frozen=" + r.haveState + ", visible=" + r.visible);
- canQuit = (r.haveState || !r.stateNotNeeded)
- && !r.visible && r.stopped;
- }
- if (canQuit) {
- // Finish all of the activities, and then the app itself.
- for (j=0; j<NUMA; j++) {
- ActivityRecord r = app.activities.get(j);
- if (!r.finishing) {
- r.stack.destroyActivityLocked(r, false);
- }
- r.resultTo = null;
- }
- Slog.i(TAG, "Exiting application process "
- + app.processName + " ("
- + (app.thread != null ? app.thread.asBinder() : null)
- + ")\n");
- if (app.pid > 0 && app.pid != MY_PID) {
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "old background");
- Process.killProcessQuiet(app.pid);
- } else {
- try {
- app.thread.scheduleExit();
- } catch (Exception e) {
- // Ignore exceptions.
- }
- }
- // todo: For now we assume the application is not buggy
- // or evil, and will quit as a result of our request.
- // Eventually we need to drive this off of the death
- // notification, and kill the process if it takes too long.
- cleanUpApplicationRecordLocked(app, false, i);
- i--;
- //dump();
- }
- }
-
- }
-
- int curMaxActivities = MAX_ACTIVITIES;
- if (mAlwaysFinishActivities) {
- curMaxActivities = 1;
- }
-
- // Finally, if there are too many activities now running, try to
- // finish as many as we can to get back down to the limit.
- for ( i=0;
- i<mMainStack.mLRUActivities.size()
- && mMainStack.mLRUActivities.size() > curMaxActivities;
- i++) {
- final ActivityRecord r
- = (ActivityRecord)mMainStack.mLRUActivities.get(i);
-
- // We can finish this one if we have its icicle saved and
- // it is not persistent.
- if ((r.haveState || !r.stateNotNeeded) && !r.visible
- && r.stopped && !r.finishing) {
- final int origSize = mMainStack.mLRUActivities.size();
- r.stack.destroyActivityLocked(r, true);
-
- // This will remove it from the LRU list, so keep
- // our index at the same value. Note that this check to
- // see if the size changes is just paranoia -- if
- // something unexpected happens, we don't want to end up
- // in an infinite loop.
- if (origSize > mMainStack.mLRUActivities.size()) {
- i--;
- }
- }
- }
+ // Now update the oom adj for all processes.
+ updateOomAdjLocked();
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b1da69f..93d8164 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -52,6 +52,7 @@
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -83,6 +84,8 @@
static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
+ static final boolean DEBUG_STATES = false;
+
static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
// How long we wait until giving up on the last activity telling us it
@@ -392,19 +395,25 @@
}
final int indexOfTokenLocked(IBinder token) {
- int count = mHistory.size();
-
- // convert the token to an entry in the history.
- int index = -1;
- for (int i=count-1; i>=0; i--) {
- Object o = mHistory.get(i);
- if (o == token) {
- index = i;
- break;
- }
+ try {
+ ActivityRecord r = (ActivityRecord)token;
+ return mHistory.indexOf(r);
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Bad activity token: " + token, e);
+ return -1;
}
+ }
- return index;
+ final ActivityRecord isInStackLocked(IBinder token) {
+ try {
+ ActivityRecord r = (ActivityRecord)token;
+ if (mHistory.contains(r)) {
+ return r;
+ }
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Bad activity token: " + token, e);
+ }
+ return null;
}
private final boolean updateLRUListLocked(ActivityRecord r) {
@@ -604,6 +613,8 @@
// As part of the process of launching, ActivityThread also performs
// a resume.
r.state = ActivityState.RESUMED;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
+ + " (starting new instance)");
r.stopped = false;
mResumedActivity = r;
r.task.touchActiveTime();
@@ -617,6 +628,8 @@
// should look like we asked it to pause+stop (but remain visible),
// and it has done so and reported back the current icicle and
// other state.
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
+ + " (starting in stopped state)");
r.state = ActivityState.STOPPED;
r.stopped = true;
}
@@ -797,7 +810,8 @@
resumeTopActivityLocked(null);
return;
}
- if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
+ else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
@@ -879,6 +893,8 @@
r = mHistory.get(index);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ + (timeout ? " (due to timeout)" : " (pause complete)"));
r.state = ActivityState.PAUSED;
completePauseLocked();
} else {
@@ -891,6 +907,22 @@
}
}
+ final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
+ CharSequence description) {
+ r.icicle = icicle;
+ r.haveState = true;
+ r.updateThumbnail(thumbnail, description);
+ r.stopped = true;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
+ r.state = ActivityState.STOPPED;
+ if (!r.finishing) {
+ if (r.configDestroy) {
+ destroyActivityLocked(r, true, false);
+ resumeTopActivityLocked(null);
+ }
+ }
+ }
+
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
@@ -914,7 +946,7 @@
// instance right now, we need to first completely stop
// the current instance before starting the new one.
if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
- destroyActivityLocked(prev, true);
+ destroyActivityLocked(prev, true, false);
} else {
mStoppingActivities.add(prev);
if (mStoppingActivities.size() > 3) {
@@ -1371,6 +1403,7 @@
mService.updateCpuStats();
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
@@ -1447,6 +1480,8 @@
} catch (Exception e) {
// Whoops, need to restart this activity!
+ if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
+ + lastState + ": " + next);
next.state = lastState;
mResumedActivity = lastResumedActivity;
Slog.i(TAG, "Restarting because process died: " + next);
@@ -2960,6 +2995,8 @@
r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+ + " (stop requested)");
r.state = ActivityState.STOPPING;
if (DEBUG_VISBILITY) Slog.v(
TAG, "Stopping visible=" + r.visible + " for " + r);
@@ -2977,9 +3014,10 @@
Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
r.stopped = true;
+ if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
r.state = ActivityState.STOPPED;
if (r.configDestroy) {
- destroyActivityLocked(r, true);
+ destroyActivityLocked(r, true, false);
}
}
}
@@ -3145,7 +3183,7 @@
for (i=0; i<NF; i++) {
ActivityRecord r = (ActivityRecord)finishes.get(i);
synchronized (mService) {
- destroyActivityLocked(r, true);
+ destroyActivityLocked(r, true, false);
}
}
@@ -3340,6 +3378,8 @@
checkReadyForSleepLocked();
}
}
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+ + " (finish requested)");
r.state = ActivityState.STOPPING;
mService.updateOomAdjLocked();
return r;
@@ -3353,6 +3393,7 @@
mResumedActivity = null;
}
final ActivityState prevState = r.state;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
r.state = ActivityState.FINISHING;
if (mode == FINISH_IMMEDIATELY
@@ -3360,7 +3401,7 @@
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
// it right now.
- return destroyActivityLocked(r, true) ? null : r;
+ return destroyActivityLocked(r, true, true) ? null : r;
} else {
// Need to go through the full pause cycle to get this
// activity into the stopped state and then finish it.
@@ -3378,7 +3419,8 @@
* processing going away, in which case there is no remaining client-side
* state to destroy so only the cleanup here is needed.
*/
- final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices) {
+ final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
+ boolean setState) {
if (mResumedActivity == r) {
mResumedActivity = null;
}
@@ -3389,6 +3431,11 @@
r.configDestroy = false;
r.frozenBeforeDestroy = false;
+ if (setState) {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)");
+ r.state = ActivityState.DESTROYED;
+ }
+
// Make sure this record is no longer in the pending finishes list.
// This could happen, for example, if we are trimming activities
// down to the max limit while they are still waiting to finish.
@@ -3428,6 +3475,8 @@
r.makeFinishing();
mHistory.remove(r);
r.takeFromHistory();
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ + " (removed from history)");
r.state = ActivityState.DESTROYED;
mService.mWindowManager.removeAppToken(r);
if (VALIDATE_TOKENS) {
@@ -3453,6 +3502,22 @@
}
}
+ final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj) {
+ for (int i=mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if (owner != null && r.app != owner) {
+ continue;
+ }
+ // We can destroy this one if we have its icicle saved and
+ // it is not in the process of pausing/stopping/finishing.
+ if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
+ && r.state != ActivityState.DESTROYING
+ && r.state != ActivityState.DESTROYED) {
+ destroyActivityLocked(r, true, oomAdj);
+ }
+ }
+ }
+
/**
* Destroy the current CLIENT SIDE instance of an activity. This may be
* called both when actually finishing an activity, or when performing
@@ -3460,7 +3525,7 @@
* but then create a new client-side object for this same HistoryRecord.
*/
final boolean destroyActivityLocked(ActivityRecord r,
- boolean removeFromApp) {
+ boolean removeFromApp, boolean oomAdj) {
if (DEBUG_SWITCH) Slog.v(
TAG, "Removing activity: token=" + r
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
@@ -3470,7 +3535,7 @@
boolean removedFromHistory = false;
- cleanUpActivityLocked(r, false);
+ cleanUpActivityLocked(r, false, false);
final boolean hadApp = r.app != null;
@@ -3488,7 +3553,7 @@
if (r.app.activities.size() == 0) {
// No longer have activities, so update location in
// LRU list.
- mService.updateLruProcessLocked(r.app, true, false);
+ mService.updateLruProcessLocked(r.app, oomAdj, false);
}
}
@@ -3513,12 +3578,23 @@
r.app = null;
r.nowVisible = false;
+ // If the activity is finishing, we need to wait on removing it
+ // from the list to give it a chance to do its cleanup. During
+ // that time it may make calls back with its token so we need to
+ // be able to find it on the list and so we don't want to remove
+ // it from the list yet. Otherwise, we can just immediately put
+ // it in the destroyed state since we are not removing it from the
+ // list.
if (r.finishing && !skipDestroy) {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
+ + " (destroy requested)");
r.state = ActivityState.DESTROYING;
Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
msg.obj = r;
mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
} else {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ + " (destroy skipped)");
r.state = ActivityState.DESTROYED;
}
} else {
@@ -3527,6 +3603,8 @@
removeActivityFromHistoryLocked(r);
removedFromHistory = true;
} else {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ + " (no app)");
r.state = ActivityState.DESTROYED;
}
}
@@ -3919,7 +3997,7 @@
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Switch is destroying non-running " + r);
- destroyActivityLocked(r, true);
+ destroyActivityLocked(r, true, false);
} else if (r.state == ActivityState.PAUSING) {
// A little annoying: we are waiting for this activity to
// finish pausing. Let's not do anything now, but just
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index da83e7d..99830f9 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -61,6 +61,7 @@
int setAdj; // Last set OOM adjustment for this process
int curSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
+ int trimMemoryLevel; // Last selected memory trimming level
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running any services that are foreground?
@@ -181,7 +182,8 @@
pw.print(" cur="); pw.print(curAdj);
pw.print(" set="); pw.println(setAdj);
pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
- pw.print(" setSchedGroup="); pw.println(setSchedGroup);
+ pw.print(" setSchedGroup="); pw.print(setSchedGroup);
+ pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
pw.print(" foregroundServices="); pw.print(foregroundServices);
pw.print(" forcingToForeground="); pw.println(forcingToForeground);
@@ -305,8 +307,6 @@
}
void toShortString(StringBuilder sb) {
- sb.append(Integer.toHexString(System.identityHashCode(this)));
- sb.append(' ');
sb.append(pid);
sb.append(':');
sb.append(processName);
@@ -320,6 +320,8 @@
}
StringBuilder sb = new StringBuilder(128);
sb.append("ProcessRecord{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
toShortString(sb);
sb.append('}');
return stringName = sb.toString();
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index c185012..55ba8e2 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -41,6 +41,9 @@
import com.android.internal.net.VpnConfig;
import com.android.server.ConnectivityService.VpnCallback;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charsets;
import java.util.Arrays;
@@ -192,10 +195,15 @@
}
// Configure the interface. Abort if any of these steps fails.
- ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(
- jniConfigure(config.mtu, config.addresses, config.routes));
+ ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
try {
String interfaze = jniGetName(tun.getFd());
+ if (jniSetAddresses(interfaze, config.addresses) < 1) {
+ throw new IllegalArgumentException("At least one address must be specified");
+ }
+ if (config.routes != null) {
+ jniSetRoutes(interfaze, config.routes);
+ }
if (mInterface != null && !mInterface.equals(interfaze)) {
jniReset(mInterface);
}
@@ -279,8 +287,10 @@
}
}
- private native int jniConfigure(int mtu, String addresses, String routes);
+ private native int jniCreate(int mtu);
private native String jniGetName(int tun);
+ private native int jniSetAddresses(String interfaze, String addresses);
+ private native int jniSetRoutes(String interfaze, String routes);
private native void jniReset(String interfaze);
private native int jniCheck(String interfaze);
private native void jniProtect(int socket, String interfaze);
@@ -323,7 +333,6 @@
*/
private class LegacyVpnRunner extends Thread {
private static final String TAG = "LegacyVpnRunner";
- private static final String NONE = "--";
private final VpnConfig mConfig;
private final String[] mDaemons;
@@ -346,10 +355,10 @@
public void exit() {
// We assume that everything is reset after the daemons die.
+ interrupt();
for (String daemon : mDaemons) {
SystemProperties.set("ctl.stop", daemon);
}
- interrupt();
}
public LegacyVpnInfo getInfo() {
@@ -380,7 +389,7 @@
Thread.sleep(yield ? 200 : 1);
} else {
mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
- throw new IllegalStateException("time is up");
+ throw new IllegalStateException("Time is up");
}
}
@@ -404,12 +413,11 @@
}
}
- // Reset the properties.
- SystemProperties.set("vpn.dns", NONE);
- SystemProperties.set("vpn.via", NONE);
- while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
- !NONE.equals(SystemProperties.get("vpn.via"))) {
- checkpoint(true);
+ // Clear the previous state.
+ File state = new File("/data/misc/vpn/state");
+ state.delete();
+ if (state.exists()) {
+ throw new IllegalStateException("Cannot delete the state");
}
// Check if we need to restart any of the daemons.
@@ -461,29 +469,34 @@
OutputStream out = socket.getOutputStream();
for (String argument : arguments) {
byte[] bytes = argument.getBytes(Charsets.UTF_8);
- if (bytes.length >= 0xFFFF) {
- throw new IllegalArgumentException("argument is too large");
+ if (bytes.length > 0xFFFF) {
+ throw new IllegalArgumentException("Argument is too large");
}
out.write(bytes.length >> 8);
out.write(bytes.length);
out.write(bytes);
checkpoint(false);
}
-
- // Send End-Of-Arguments.
- out.write(0xFF);
- out.write(0xFF);
out.flush();
+ socket.shutdownOutput();
+
+ // Wait for End-of-File.
+ InputStream in = socket.getInputStream();
+ while (true) {
+ try {
+ if (in.read() == -1) {
+ break;
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ checkpoint(true);
+ }
socket.close();
}
- // Now here is the beast from the old days. We check few
- // properties to figure out the current status. Ideally we
- // can read things back from the sockets and get rid of the
- // properties, but we have no time...
- while (NONE.equals(SystemProperties.get("vpn.dns")) ||
- NONE.equals(SystemProperties.get("vpn.via"))) {
-
+ // Wait for the daemons to create the new state.
+ while (!state.exists()) {
// Check if a running daemon is dead.
for (int i = 0; i < mDaemons.length; ++i) {
String daemon = mDaemons[i];
@@ -495,20 +508,45 @@
checkpoint(true);
}
- // Now we are connected. Get the interface.
- mConfig.interfaze = SystemProperties.get("vpn.via");
+ // Now we are connected. Read and parse the new state.
+ byte[] buffer = new byte[(int) state.length()];
+ if (new FileInputStream(state).read(buffer) != buffer.length) {
+ throw new IllegalStateException("Cannot read the state");
+ }
+ String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1);
+ if (parameters.length != 6) {
+ throw new IllegalStateException("Cannot parse the state");
+ }
- // Get the DNS servers if they are not set in config.
+ // Set the interface and the addresses in the config.
+ mConfig.interfaze = parameters[0].trim();
+ mConfig.addresses = parameters[1].trim();
+
+ // Set the routes if they are not set in the config.
+ if (mConfig.routes == null || mConfig.routes.isEmpty()) {
+ mConfig.routes = parameters[2].trim();
+ }
+
+ // Set the DNS servers if they are not set in the config.
if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
- String dnsServers = SystemProperties.get("vpn.dns").trim();
+ String dnsServers = parameters[3].trim();
if (!dnsServers.isEmpty()) {
mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
}
}
- // TODO: support search domains from ISAKMP mode config.
+ // Set the search domains if they are not set in the config.
+ if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
+ String searchDomains = parameters[4].trim();
+ if (!searchDomains.isEmpty()) {
+ mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
+ }
+ }
- // The final step must be synchronized.
+ // Set the routes.
+ jniSetRoutes(mConfig.interfaze, mConfig.routes);
+
+ // Here is the last step and it must be done synchronously.
synchronized (Vpn.this) {
// Check if the thread is interrupted while we are waiting.
checkpoint(false);
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index d3d9df4..bfa2b39 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -101,7 +101,7 @@
boolean firstWindowDrawn;
// Input application handle used by the input dispatcher.
- InputApplicationHandle mInputApplicationHandle;
+ final InputApplicationHandle mInputApplicationHandle;
AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
super(_service, _token.asBinder(),
diff --git a/services/java/com/android/server/wm/InputApplication.java b/services/java/com/android/server/wm/InputApplication.java
deleted file mode 100644
index e04fd31..0000000
--- a/services/java/com/android/server/wm/InputApplication.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-
-/**
- * Describes input-related application properties for use by the input dispatcher.
- * @hide
- */
-public final class InputApplication {
- // Application handle.
- public InputApplicationHandle inputApplicationHandle;
-
- // Application name.
- public String name;
-
- // Dispatching timeout.
- public long dispatchingTimeoutNanos;
-
- public void recycle() {
- inputApplicationHandle = null;
- }
-}
diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/wm/InputApplicationHandle.java
index 64c8e7e..d78b1d9 100644
--- a/services/java/com/android/server/wm/InputApplicationHandle.java
+++ b/services/java/com/android/server/wm/InputApplicationHandle.java
@@ -32,6 +32,12 @@
// The window manager's application window token.
public final AppWindowToken appWindowToken;
+ // Application name.
+ public String name;
+
+ // Dispatching timeout.
+ public long dispatchingTimeoutNanos;
+
private native void nativeDispose();
public InputApplicationHandle(AppWindowToken appWindowToken) {
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 65007f9..3133a19 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -25,7 +25,6 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.os.Environment;
-import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.SystemProperties;
@@ -83,10 +82,10 @@
private static native int nativeInjectInputEvent(InputEvent event,
int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
int policyFlags);
- private static native void nativeSetInputWindows(InputWindow[] windows);
+ private static native void nativeSetInputWindows(InputWindowHandle[] windowHandles);
private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
private static native void nativeSetSystemUiVisibility(int visibility);
- private static native void nativeSetFocusedApplication(InputApplication application);
+ private static native void nativeSetFocusedApplication(InputApplicationHandle application);
private static native InputDevice nativeGetInputDevice(int deviceId);
private static native void nativeGetInputConfiguration(Configuration configuration);
private static native int[] nativeGetInputDeviceIds();
@@ -372,11 +371,11 @@
return nativeGetInputDeviceIds();
}
- public void setInputWindows(InputWindow[] windows) {
- nativeSetInputWindows(windows);
+ public void setInputWindows(InputWindowHandle[] windowHandles) {
+ nativeSetInputWindows(windowHandles);
}
- public void setFocusedApplication(InputApplication application) {
+ public void setFocusedApplication(InputApplicationHandle application) {
nativeSetFocusedApplication(application);
}
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 6806634..08a3560 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import android.graphics.Rect;
-import android.os.Binder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -26,6 +25,7 @@
import android.view.WindowManager;
import java.util.ArrayList;
+import java.util.Arrays;
final class InputMonitor {
private final WindowManagerService mService;
@@ -42,12 +42,14 @@
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
- // Temporary list of windows information to provide to the input dispatcher.
- private InputWindowList mTempInputWindows = new InputWindowList();
-
- // Temporary input application object to provide to the input dispatcher.
- private InputApplication mTempInputApplication = new InputApplication();
-
+ // Fake handles for the drag surface, lazily initialized.
+ private InputApplicationHandle mDragApplicationHandle;
+ private InputWindowHandle mDragWindowHandle;
+
+ // Array of window handles to provide to the input dispatcher.
+ private InputWindowHandle[] mInputWindowHandles;
+ private int mInputWindowHandleCount;
+
// Set to true when the first input device configuration change notification
// is received to indicate that the input devices are ready.
private final Object mInputDevicesReadyMonitor = new Object();
@@ -68,8 +70,10 @@
synchronized (mService.mWindowMap) {
WindowState windowState = (WindowState) inputWindowHandle.windowState;
- Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);
- mService.removeWindowLocked(windowState.mSession, windowState);
+ if (windowState != null) {
+ Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);
+ mService.removeWindowLocked(windowState.mSession, windowState);
+ }
}
}
@@ -94,8 +98,11 @@
if (appWindowToken == null && inputApplicationHandle != null) {
appWindowToken = inputApplicationHandle.appWindowToken;
- Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to application "
- + appWindowToken.stringName);
+ if (appWindowToken != null) {
+ Slog.i(WindowManagerService.TAG,
+ "Input event dispatching timed out sending to application "
+ + appWindowToken.stringName);
+ }
}
if (appWindowToken != null && appWindowToken.appToken != null) {
@@ -114,32 +121,59 @@
return 0; // abort dispatching
}
- private void addDragInputWindowLw(InputWindowList windowList) {
- final InputWindow inputWindow = windowList.add();
- inputWindow.inputChannel = mService.mDragState.mServerChannel;
- inputWindow.name = "drag";
- inputWindow.layoutParamsFlags = 0;
- inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- inputWindow.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- inputWindow.visible = true;
- inputWindow.canReceiveKeys = false;
- inputWindow.hasFocus = true;
- inputWindow.hasWallpaper = false;
- inputWindow.paused = false;
- inputWindow.layer = mService.mDragState.getDragLayerLw();
- inputWindow.ownerPid = Process.myPid();
- inputWindow.ownerUid = Process.myUid();
- inputWindow.inputFeatures = 0;
- inputWindow.scaleFactor = 1.0f;
+ private void addDragInputWindowLw() {
+ if (mDragWindowHandle == null) {
+ mDragApplicationHandle = new InputApplicationHandle(null);
+ mDragApplicationHandle.name = "drag";
+ mDragApplicationHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+
+ mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null);
+ mDragWindowHandle.name = "drag";
+ mDragWindowHandle.layoutParamsFlags = 0;
+ mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
+ mDragWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.visible = true;
+ mDragWindowHandle.canReceiveKeys = false;
+ mDragWindowHandle.hasFocus = true;
+ mDragWindowHandle.hasWallpaper = false;
+ mDragWindowHandle.paused = false;
+ mDragWindowHandle.ownerPid = Process.myPid();
+ mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.inputFeatures = 0;
+ mDragWindowHandle.scaleFactor = 1.0f;
+
+ // The drag window cannot receive new touches.
+ mDragWindowHandle.touchableRegion.setEmpty();
+ }
+
+ mDragWindowHandle.layer = mService.mDragState.getDragLayerLw();
// The drag window covers the entire display
- inputWindow.frameLeft = 0;
- inputWindow.frameTop = 0;
- inputWindow.frameRight = mService.mDisplay.getRealWidth();
- inputWindow.frameBottom = mService.mDisplay.getRealHeight();
+ mDragWindowHandle.frameLeft = 0;
+ mDragWindowHandle.frameTop = 0;
+ mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
+ mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
- // The drag window cannot receive new touches.
- inputWindow.touchableRegion.setEmpty();
+ addInputWindowHandleLw(mDragWindowHandle);
+ }
+
+ private void addInputWindowHandleLw(InputWindowHandle windowHandle) {
+ if (mInputWindowHandles == null) {
+ mInputWindowHandles = new InputWindowHandle[16];
+ }
+ if (mInputWindowHandleCount >= mInputWindowHandles.length) {
+ mInputWindowHandles = Arrays.copyOf(mInputWindowHandles,
+ mInputWindowHandleCount * 2);
+ }
+ mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
+ }
+
+ private void clearInputWindowHandlesLw() {
+ while (mInputWindowHandleCount != 0) {
+ mInputWindowHandles[--mInputWindowHandleCount] = null;
+ }
}
public void setUpdateInputWindowsNeededLw() {
@@ -154,7 +188,7 @@
mUpdateInputWindowsNeeded = false;
if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw");
-
+
// Populate the input window list with information about all of the windows that
// could potentially receive input.
// As an optimization, we could try to prune the list of windows but this turns
@@ -168,7 +202,7 @@
if (WindowManagerService.DEBUG_DRAG) {
Log.d(WindowManagerService.TAG, "Inserting drag window");
}
- addDragInputWindowLw(mTempInputWindows);
+ addDragInputWindowLw();
}
final int N = windows.size();
@@ -194,48 +228,48 @@
}
// Add a window to our list of input windows.
- final InputWindow inputWindow = mTempInputWindows.add();
- inputWindow.inputWindowHandle = child.mInputWindowHandle;
- inputWindow.inputChannel = child.mInputChannel;
- inputWindow.name = child.toString();
- inputWindow.layoutParamsFlags = flags;
- inputWindow.layoutParamsType = type;
- inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
- inputWindow.visible = isVisible;
- inputWindow.canReceiveKeys = child.canReceiveKeys();
- inputWindow.hasFocus = hasFocus;
- inputWindow.hasWallpaper = hasWallpaper;
- inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
- inputWindow.layer = child.mLayer;
- inputWindow.ownerPid = child.mSession.mPid;
- inputWindow.ownerUid = child.mSession.mUid;
- inputWindow.inputFeatures = child.mAttrs.inputFeatures;
+ final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
+ inputWindowHandle.inputChannel = child.mInputChannel;
+ inputWindowHandle.name = child.toString();
+ inputWindowHandle.layoutParamsFlags = flags;
+ inputWindowHandle.layoutParamsType = type;
+ inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
+ inputWindowHandle.visible = isVisible;
+ inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
+ inputWindowHandle.hasFocus = hasFocus;
+ inputWindowHandle.hasWallpaper = hasWallpaper;
+ inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
+ inputWindowHandle.layer = child.mLayer;
+ inputWindowHandle.ownerPid = child.mSession.mPid;
+ inputWindowHandle.ownerUid = child.mSession.mUid;
+ inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
final Rect frame = child.mFrame;
- inputWindow.frameLeft = frame.left;
- inputWindow.frameTop = frame.top;
- inputWindow.frameRight = frame.right;
- inputWindow.frameBottom = frame.bottom;
+ inputWindowHandle.frameLeft = frame.left;
+ inputWindowHandle.frameTop = frame.top;
+ inputWindowHandle.frameRight = frame.right;
+ inputWindowHandle.frameBottom = frame.bottom;
if (child.mGlobalScale != 1) {
// If we are scaling the window, input coordinates need
// to be inversely scaled to map from what is on screen
// to what is actually being touched in the UI.
- inputWindow.scaleFactor = 1.0f/child.mGlobalScale;
+ inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
} else {
- inputWindow.scaleFactor = 1;
+ inputWindowHandle.scaleFactor = 1;
}
- child.getTouchableRegion(inputWindow.touchableRegion);
+ child.getTouchableRegion(inputWindowHandle.touchableRegion);
+
+ addInputWindowHandleLw(inputWindowHandle);
}
// Send windows to native code.
- mService.mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());
-
+ mService.mInputManager.setInputWindows(mInputWindowHandles);
+
// Clear the list in preparation for the next round.
- // Also avoids keeping InputChannel objects referenced unnecessarily.
- mTempInputWindows.clear();
-
+ clearInputWindowHandlesLw();
+
if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
}
@@ -329,14 +363,11 @@
if (newApp == null) {
mService.mInputManager.setFocusedApplication(null);
} else {
- mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle;
- mTempInputApplication.name = newApp.toString();
- mTempInputApplication.dispatchingTimeoutNanos =
- newApp.inputDispatchingTimeoutNanos;
+ final InputApplicationHandle handle = newApp.mInputApplicationHandle;
+ handle.name = newApp.toString();
+ handle.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos;
- mService.mInputManager.setFocusedApplication(mTempInputApplication);
-
- mTempInputApplication.recycle();
+ mService.mInputManager.setFocusedApplication(handle);
}
}
diff --git a/services/java/com/android/server/wm/InputWindow.java b/services/java/com/android/server/wm/InputWindow.java
deleted file mode 100644
index 655d734..0000000
--- a/services/java/com/android/server/wm/InputWindow.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.graphics.Region;
-import android.view.InputChannel;
-
-/**
- * Describes input-related window properties for use by the input dispatcher.
- * @hide
- */
-public final class InputWindow {
- // The window handle.
- public InputWindowHandle inputWindowHandle;
-
- // The input channel associated with the window.
- public InputChannel inputChannel;
-
- // The window name.
- public String name;
-
- // Window layout params attributes. (WindowManager.LayoutParams)
- public int layoutParamsFlags;
- public int layoutParamsType;
-
- // Dispatching timeout.
- public long dispatchingTimeoutNanos;
-
- // Window frame.
- public int frameLeft;
- public int frameTop;
- public int frameRight;
- public int frameBottom;
-
- // Global scaling factor applied to touch events when they are dispatched
- // to the window
- public float scaleFactor;
-
- // Window touchable region.
- public final Region touchableRegion = new Region();
-
- // Window is visible.
- public boolean visible;
-
- // Window can receive keys.
- public boolean canReceiveKeys;
-
- // Window has focus.
- public boolean hasFocus;
-
- // Window has wallpaper. (window is the current wallpaper target)
- public boolean hasWallpaper;
-
- // Input event dispatching is paused.
- public boolean paused;
-
- // Window layer.
- public int layer;
-
- // Id of process and user that owns the window.
- public int ownerPid;
- public int ownerUid;
-
- // Window input features.
- public int inputFeatures;
-
- public void recycle() {
- inputWindowHandle = null;
- inputChannel = null;
- }
-}
diff --git a/services/java/com/android/server/wm/InputWindowHandle.java b/services/java/com/android/server/wm/InputWindowHandle.java
index cc508c6..abf68d9 100644
--- a/services/java/com/android/server/wm/InputWindowHandle.java
+++ b/services/java/com/android/server/wm/InputWindowHandle.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import android.graphics.Region;
+import android.view.InputChannel;
import android.view.WindowManagerPolicy;
/**
@@ -35,6 +37,57 @@
// The window manager's window state.
public final WindowManagerPolicy.WindowState windowState;
+ // The input channel associated with the window.
+ public InputChannel inputChannel;
+
+ // The window name.
+ public String name;
+
+ // Window layout params attributes. (WindowManager.LayoutParams)
+ public int layoutParamsFlags;
+ public int layoutParamsType;
+
+ // Dispatching timeout.
+ public long dispatchingTimeoutNanos;
+
+ // Window frame.
+ public int frameLeft;
+ public int frameTop;
+ public int frameRight;
+ public int frameBottom;
+
+ // Global scaling factor applied to touch events when they are dispatched
+ // to the window
+ public float scaleFactor;
+
+ // Window touchable region.
+ public final Region touchableRegion = new Region();
+
+ // Window is visible.
+ public boolean visible;
+
+ // Window can receive keys.
+ public boolean canReceiveKeys;
+
+ // Window has focus.
+ public boolean hasFocus;
+
+ // Window has wallpaper. (window is the current wallpaper target)
+ public boolean hasWallpaper;
+
+ // Input event dispatching is paused.
+ public boolean paused;
+
+ // Window layer.
+ public int layer;
+
+ // Id of process and user that owns the window.
+ public int ownerPid;
+ public int ownerUid;
+
+ // Window input features.
+ public int inputFeatures;
+
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
diff --git a/services/java/com/android/server/wm/InputWindowList.java b/services/java/com/android/server/wm/InputWindowList.java
deleted file mode 100644
index 6077337..0000000
--- a/services/java/com/android/server/wm/InputWindowList.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-
-/**
- * A specialized list of window information objects backed by an array.
- *
- * This class is part of an InputManager optimization to avoid allocating objects and arrays
- * unnecessarily. Internally, it keeps an array full of demand-allocated objects that it
- * recycles each time the list is cleared. The used portion of the array is padded with a null.
- *
- * The contents of the list are intended to be Z-ordered from top to bottom.
- *
- * @hide
- */
-public final class InputWindowList {
- private InputWindow[] mArray;
- private int mCount;
-
- /**
- * Creates an empty list.
- */
- public InputWindowList() {
- mArray = new InputWindow[8];
- }
-
- /**
- * Clears the list.
- */
- public void clear() {
- if (mCount == 0) {
- return;
- }
-
- int count = mCount;
- mCount = 0;
- mArray[count] = mArray[0];
- while (count > 0) {
- count -= 1;
- mArray[count].recycle();
- }
- mArray[0] = null;
- }
-
- /**
- * Adds an uninitialized input window object to the list and returns it.
- */
- public InputWindow add() {
- if (mCount + 1 == mArray.length) {
- InputWindow[] oldArray = mArray;
- mArray = new InputWindow[oldArray.length * 2];
- System.arraycopy(oldArray, 0, mArray, 0, mCount);
- }
-
- // Grab object from tail (after used section) if available.
- InputWindow item = mArray[mCount + 1];
- if (item == null) {
- item = new InputWindow();
- }
-
- mArray[mCount] = item;
- mCount += 1;
- mArray[mCount] = null;
- return item;
- }
-
- /**
- * Gets the input window objects as a null-terminated array.
- * @return The input window array.
- */
- public InputWindow[] toNullTerminatedArray() {
- return mArray;
- }
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index b370ec9..d298ff7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -272,7 +272,7 @@
float mSurfaceAlpha;
// Input channel and input window handle used by the input dispatcher.
- InputWindowHandle mInputWindowHandle;
+ final InputWindowHandle mInputWindowHandle;
InputChannel mInputChannel;
// Used to improve performance of toString()
@@ -306,6 +306,7 @@
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
+ mInputWindowHandle = null;
return;
}
mDeathRecipient = deathRecipient;
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index e1c7305..6fa5dfa 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,10 +4,8 @@
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_BatteryService.cpp \
- com_android_server_InputApplication.cpp \
com_android_server_InputApplicationHandle.cpp \
com_android_server_InputManager.cpp \
- com_android_server_InputWindow.cpp \
com_android_server_InputWindowHandle.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index c9a702a..e80dd04 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -32,17 +32,13 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
-
-#ifdef HAVE_ANDROID_OS
#include <linux/ioctl.h>
#include <linux/android_alarm.h>
-#endif
namespace android {
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
{
-#ifdef HAVE_ANDROID_OS
struct timezone tz;
tz.tz_minuteswest = minswest;
@@ -57,30 +53,20 @@
}
return 0;
-#else
- return -ENOSYS;
-#endif
}
static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
{
-#ifdef HAVE_ANDROID_OS
return open("/dev/alarm", O_RDWR);
-#else
- return -1;
-#endif
}
static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd)
{
-#ifdef HAVE_ANDROID_OS
close(fd);
-#endif
}
static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
{
-#ifdef HAVE_ANDROID_OS
struct timespec ts;
ts.tv_sec = seconds;
ts.tv_nsec = nanoseconds;
@@ -90,12 +76,10 @@
{
LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
}
-#endif
}
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
{
-#ifdef HAVE_ANDROID_OS
int result = 0;
do
@@ -110,7 +94,6 @@
}
return result;
-#endif
}
static JNINativeMethod sMethods[] = {
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 98d0d92..b9f2c1f 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -32,10 +32,7 @@
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
-
-#ifdef HAVE_ANDROID_OS
#include <linux/ioctl.h>
-#endif
namespace android {
diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp
deleted file mode 100644
index 1f80242..0000000
--- a/services/jni/com_android_server_InputApplication.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "InputApplication"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include "com_android_server_InputApplication.h"
-#include "com_android_server_InputApplicationHandle.h"
-
-namespace android {
-
-static struct {
- jfieldID inputApplicationHandle;
- jfieldID name;
- jfieldID dispatchingTimeoutNanos;
-} gInputApplicationClassInfo;
-
-
-// --- Global functions ---
-
-void android_server_InputApplication_toNative(
- JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication) {
- jobject inputApplicationHandleObj = env->GetObjectField(inputApplicationObj,
- gInputApplicationClassInfo.inputApplicationHandle);
- if (inputApplicationHandleObj) {
- outInputApplication->inputApplicationHandle =
- android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
- env->DeleteLocalRef(inputApplicationHandleObj);
- } else {
- outInputApplication->inputApplicationHandle = NULL;
- }
-
- jstring nameObj = jstring(env->GetObjectField(inputApplicationObj,
- gInputApplicationClassInfo.name));
- if (nameObj) {
- const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- outInputApplication->name.setTo(nameStr);
- env->ReleaseStringUTFChars(nameObj, nameStr);
- env->DeleteLocalRef(nameObj);
- } else {
- LOGE("InputApplication.name should not be null.");
- outInputApplication->name.setTo("unknown");
- }
-
- outInputApplication->dispatchingTimeout = env->GetLongField(inputApplicationObj,
- gInputApplicationClassInfo.dispatchingTimeoutNanos);
-}
-
-
-// --- JNI ---
-
-#define FIND_CLASS(var, className) \
- var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#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_server_InputApplication(JNIEnv* env) {
- jclass clazz;
- FIND_CLASS(clazz, "com/android/server/wm/InputApplication");
-
- GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle,
- clazz,
- "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
-
- GET_FIELD_ID(gInputApplicationClassInfo.name, clazz,
- "name", "Ljava/lang/String;");
-
- GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
- clazz,
- "dispatchingTimeoutNanos", "J");
- return 0;
-}
-
-} /* namespace android */
diff --git a/services/jni/com_android_server_InputApplication.h b/services/jni/com_android_server_InputApplication.h
deleted file mode 100644
index 85fb891..0000000
--- a/services/jni/com_android_server_InputApplication.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _ANDROID_SERVER_INPUT_APPLICATION_H
-#define _ANDROID_SERVER_INPUT_APPLICATION_H
-
-#include <input/InputApplication.h>
-
-#include "JNIHelp.h"
-#include "jni.h"
-
-namespace android {
-
-extern void android_server_InputApplication_toNative(
- JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication);
-
-} // namespace android
-
-#endif // _ANDROID_SERVER_INPUT_APPLICATION_H
diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp
index 9516964..7de67d9 100644
--- a/services/jni/com_android_server_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -27,6 +27,8 @@
static struct {
jfieldID ptr;
+ jfieldID name;
+ jfieldID dispatchingTimeoutNanos;
} gInputApplicationHandleClassInfo;
static Mutex gHandleMutex;
@@ -47,6 +49,31 @@
return env->NewLocalRef(mObjWeak);
}
+bool NativeInputApplicationHandle::update() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject obj = env->NewLocalRef(mObjWeak);
+ if (!obj) {
+ return false;
+ }
+
+ jstring nameObj = jstring(env->GetObjectField(obj,
+ gInputApplicationHandleClassInfo.name));
+ if (nameObj) {
+ const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+ name.setTo(nameStr);
+ env->ReleaseStringUTFChars(nameObj, nameStr);
+ env->DeleteLocalRef(nameObj);
+ } else {
+ name.setTo("<null>");
+ }
+
+ dispatchingTimeout = env->GetLongField(obj,
+ gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+
+ env->DeleteLocalRef(obj);
+ return true;
+}
+
// --- Global functions ---
@@ -113,6 +140,13 @@
GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
"ptr", "I");
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
+ "name", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
+ clazz,
+ "dispatchingTimeoutNanos", "J");
+
return 0;
}
diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h
index 9d18721..04cd9d6 100644
--- a/services/jni/com_android_server_InputApplicationHandle.h
+++ b/services/jni/com_android_server_InputApplicationHandle.h
@@ -31,6 +31,8 @@
jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
+ virtual bool update();
+
private:
jweak mObjWeak;
};
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 14a4109..de9c9d0 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -46,9 +46,7 @@
#include <android/graphics/GraphicsJNI.h>
#include "com_android_server_PowerManagerService.h"
-#include "com_android_server_InputApplication.h"
#include "com_android_server_InputApplicationHandle.h"
-#include "com_android_server_InputWindow.h"
#include "com_android_server_InputWindowHandle.h"
namespace android {
@@ -175,8 +173,8 @@
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
- void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
- void setFocusedApplication(JNIEnv* env, jobject applicationObj);
+ void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray);
+ void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj);
void setInputDispatchMode(bool enabled, bool frozen);
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
@@ -582,31 +580,38 @@
return isScreenOn();
}
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) {
- Vector<InputWindow> windows;
+void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
+ Vector<sp<InputWindowHandle> > windowHandles;
- bool newPointerGesturesEnabled = true;
- jsize length = env->GetArrayLength(windowObjArray);
- for (jsize i = 0; i < length; i++) {
- jobject windowObj = env->GetObjectArrayElement(windowObjArray, i);
- if (! windowObj) {
- break; // found null element indicating end of used portion of the array
- }
-
- windows.push();
- InputWindow& window = windows.editTop();
- android_server_InputWindow_toNative(env, windowObj, &window);
- if (window.inputChannel == NULL) {
- windows.pop();
- } else if (window.hasFocus) {
- if (window.inputFeatures & InputWindow::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES) {
- newPointerGesturesEnabled = false;
+ if (windowHandleObjArray) {
+ jsize length = env->GetArrayLength(windowHandleObjArray);
+ for (jsize i = 0; i < length; i++) {
+ jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
+ if (! windowHandleObj) {
+ break; // found null element indicating end of used portion of the array
}
+
+ sp<InputWindowHandle> windowHandle =
+ android_server_InputWindowHandle_getHandle(env, windowHandleObj);
+ if (windowHandle != NULL) {
+ windowHandles.push(windowHandle);
+ }
+ env->DeleteLocalRef(windowHandleObj);
}
- env->DeleteLocalRef(windowObj);
}
- mInputManager->getDispatcher()->setInputWindows(windows);
+ mInputManager->getDispatcher()->setInputWindows(windowHandles);
+
+ // Do this after the dispatcher has updated the window handle state.
+ bool newPointerGesturesEnabled = true;
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ if (windowHandle->hasFocus && (windowHandle->inputFeatures
+ & InputWindowHandle::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
+ newPointerGesturesEnabled = false;
+ }
+ }
uint32_t changes = 0;
{ // acquire lock
@@ -623,16 +628,10 @@
}
}
-void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) {
- if (applicationObj) {
- InputApplication application;
- android_server_InputApplication_toNative(env, applicationObj, &application);
- if (application.inputApplicationHandle != NULL) {
- mInputManager->getDispatcher()->setFocusedApplication(&application);
- return;
- }
- }
- mInputManager->getDispatcher()->setFocusedApplication(NULL);
+void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) {
+ sp<InputApplicationHandle> applicationHandle =
+ android_server_InputApplicationHandle_getHandle(env, applicationHandleObj);
+ mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
}
void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
@@ -1137,21 +1136,21 @@
}
static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz,
- jobjectArray windowObjArray) {
+ jobjectArray windowHandleObjArray) {
if (checkInputManagerUnitialized(env)) {
return;
}
- gNativeInputManager->setInputWindows(env, windowObjArray);
+ gNativeInputManager->setInputWindows(env, windowHandleObjArray);
}
static void android_server_InputManager_nativeSetFocusedApplication(JNIEnv* env, jclass clazz,
- jobject applicationObj) {
+ jobject applicationHandleObj) {
if (checkInputManagerUnitialized(env)) {
return;
}
- gNativeInputManager->setFocusedApplication(env, applicationObj);
+ gNativeInputManager->setFocusedApplication(env, applicationHandleObj);
}
static void android_server_InputManager_nativeSetInputDispatchMode(JNIEnv* env,
@@ -1313,9 +1312,9 @@
(void*) android_server_InputManager_nativeSetInputFilterEnabled },
{ "nativeInjectInputEvent", "(Landroid/view/InputEvent;IIIII)I",
(void*) android_server_InputManager_nativeInjectInputEvent },
- { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindow;)V",
+ { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindowHandle;)V",
(void*) android_server_InputManager_nativeSetInputWindows },
- { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplication;)V",
+ { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplicationHandle;)V",
(void*) android_server_InputManager_nativeSetFocusedApplication },
{ "nativeSetInputDispatchMode", "(ZZ)V",
(void*) android_server_InputManager_nativeSetInputDispatchMode },
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
deleted file mode 100644
index 0426f63..0000000
--- a/services/jni/com_android_server_InputWindow.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "InputWindow"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include <android_view_InputChannel.h>
-#include <android/graphics/Region.h>
-#include "com_android_server_InputWindow.h"
-#include "com_android_server_InputWindowHandle.h"
-
-namespace android {
-
-static struct {
- jfieldID inputWindowHandle;
- jfieldID inputChannel;
- jfieldID name;
- jfieldID layoutParamsFlags;
- jfieldID layoutParamsType;
- jfieldID dispatchingTimeoutNanos;
- jfieldID frameLeft;
- jfieldID frameTop;
- jfieldID frameRight;
- jfieldID frameBottom;
- jfieldID scaleFactor;
- jfieldID touchableRegion;
- jfieldID visible;
- jfieldID canReceiveKeys;
- jfieldID hasFocus;
- jfieldID hasWallpaper;
- jfieldID paused;
- jfieldID layer;
- jfieldID ownerPid;
- jfieldID ownerUid;
- jfieldID inputFeatures;
-} gInputWindowClassInfo;
-
-
-// --- Global functions ---
-
-void android_server_InputWindow_toNative(
- JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow) {
- jobject inputWindowHandleObj = env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.inputWindowHandle);
- if (inputWindowHandleObj) {
- outInputWindow->inputWindowHandle =
- android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
- env->DeleteLocalRef(inputWindowHandleObj);
- } else {
- outInputWindow->inputWindowHandle = NULL;
- }
-
- jobject inputChannelObj = env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.inputChannel);
- if (inputChannelObj) {
- outInputWindow->inputChannel =
- android_view_InputChannel_getInputChannel(env, inputChannelObj);
- env->DeleteLocalRef(inputChannelObj);
- } else {
- outInputWindow->inputChannel = NULL;
- }
-
- jstring nameObj = jstring(env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.name));
- if (nameObj) {
- const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- outInputWindow->name.setTo(nameStr);
- env->ReleaseStringUTFChars(nameObj, nameStr);
- env->DeleteLocalRef(nameObj);
- } else {
- LOGE("InputWindow.name should not be null.");
- outInputWindow->name.setTo("unknown");
- }
-
- outInputWindow->layoutParamsFlags = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.layoutParamsFlags);
- outInputWindow->layoutParamsType = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.layoutParamsType);
- outInputWindow->dispatchingTimeout = env->GetLongField(inputWindowObj,
- gInputWindowClassInfo.dispatchingTimeoutNanos);
- outInputWindow->frameLeft = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameLeft);
- outInputWindow->frameTop = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameTop);
- outInputWindow->frameRight = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameRight);
- outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameBottom);
- outInputWindow->scaleFactor = env->GetFloatField(inputWindowObj,
- gInputWindowClassInfo.scaleFactor);
-
- jobject regionObj = env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.touchableRegion);
- if (regionObj) {
- SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
- outInputWindow->touchableRegion.set(*region);
- env->DeleteLocalRef(regionObj);
- } else {
- outInputWindow->touchableRegion.setEmpty();
- }
-
- outInputWindow->visible = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.visible);
- outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.canReceiveKeys);
- outInputWindow->hasFocus = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.hasFocus);
- outInputWindow->hasWallpaper = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.hasWallpaper);
- outInputWindow->paused = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.paused);
- outInputWindow->layer = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.layer);
- outInputWindow->ownerPid = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.ownerPid);
- outInputWindow->ownerUid = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.ownerUid);
- outInputWindow->inputFeatures = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.inputFeatures);
-}
-
-
-// --- JNI ---
-
-#define FIND_CLASS(var, className) \
- var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#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_server_InputWindow(JNIEnv* env) {
- jclass clazz;
- FIND_CLASS(clazz, "com/android/server/wm/InputWindow");
-
- GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz,
- "inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;");
-
- GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz,
- "inputChannel", "Landroid/view/InputChannel;");
-
- GET_FIELD_ID(gInputWindowClassInfo.name, clazz,
- "name", "Ljava/lang/String;");
-
- GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz,
- "layoutParamsFlags", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz,
- "layoutParamsType", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz,
- "dispatchingTimeoutNanos", "J");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz,
- "frameLeft", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz,
- "frameTop", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz,
- "frameRight", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz,
- "frameBottom", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.scaleFactor, clazz,
- "scaleFactor", "F");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz,
- "touchableRegion", "Landroid/graphics/Region;");
-
- GET_FIELD_ID(gInputWindowClassInfo.visible, clazz,
- "visible", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz,
- "canReceiveKeys", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz,
- "hasFocus", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz,
- "hasWallpaper", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.paused, clazz,
- "paused", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.layer, clazz,
- "layer", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz,
- "ownerPid", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz,
- "ownerUid", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.inputFeatures, clazz,
- "inputFeatures", "I");
- return 0;
-}
-
-} /* namespace android */
diff --git a/services/jni/com_android_server_InputWindow.h b/services/jni/com_android_server_InputWindow.h
deleted file mode 100644
index eaf7bde..0000000
--- a/services/jni/com_android_server_InputWindow.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _ANDROID_SERVER_INPUT_WINDOW_H
-#define _ANDROID_SERVER_INPUT_WINDOW_H
-
-#include <input/InputWindow.h>
-
-#include "JNIHelp.h"
-#include "jni.h"
-
-namespace android {
-
-extern void android_server_InputWindow_toNative(
- JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow);
-
-} // namespace android
-
-#endif // _ANDROID_SERVER_INPUT_WINDOW_H
diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp
index aaf679c..09be881 100644
--- a/services/jni/com_android_server_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -21,6 +21,9 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/threads.h>
+#include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
+
#include "com_android_server_InputWindowHandle.h"
#include "com_android_server_InputApplicationHandle.h"
@@ -29,6 +32,26 @@
static struct {
jfieldID ptr;
jfieldID inputApplicationHandle;
+ jfieldID inputChannel;
+ jfieldID name;
+ jfieldID layoutParamsFlags;
+ jfieldID layoutParamsType;
+ jfieldID dispatchingTimeoutNanos;
+ jfieldID frameLeft;
+ jfieldID frameTop;
+ jfieldID frameRight;
+ jfieldID frameBottom;
+ jfieldID scaleFactor;
+ jfieldID touchableRegion;
+ jfieldID visible;
+ jfieldID canReceiveKeys;
+ jfieldID hasFocus;
+ jfieldID hasWallpaper;
+ jfieldID paused;
+ jfieldID layer;
+ jfieldID ownerPid;
+ jfieldID ownerUid;
+ jfieldID inputFeatures;
} gInputWindowHandleClassInfo;
static Mutex gHandleMutex;
@@ -51,6 +74,83 @@
return env->NewLocalRef(mObjWeak);
}
+bool NativeInputWindowHandle::update() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject obj = env->NewLocalRef(mObjWeak);
+ if (!obj) {
+ return false;
+ }
+
+ jobject inputChannelObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.inputChannel);
+ if (inputChannelObj) {
+ inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
+ env->DeleteLocalRef(inputChannelObj);
+ } else {
+ inputChannel = NULL;
+ }
+
+ jstring nameObj = jstring(env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.name));
+ if (nameObj) {
+ const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+ name.setTo(nameStr);
+ env->ReleaseStringUTFChars(nameObj, nameStr);
+ env->DeleteLocalRef(nameObj);
+ } else {
+ name.setTo("<null>");
+ }
+
+ layoutParamsFlags = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsFlags);
+ layoutParamsType = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsType);
+ dispatchingTimeout = env->GetLongField(obj,
+ gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
+ frameLeft = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameLeft);
+ frameTop = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameTop);
+ frameRight = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameRight);
+ frameBottom = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameBottom);
+ scaleFactor = env->GetFloatField(obj,
+ gInputWindowHandleClassInfo.scaleFactor);
+
+ jobject regionObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.touchableRegion);
+ if (regionObj) {
+ SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+ touchableRegion.set(*region);
+ env->DeleteLocalRef(regionObj);
+ } else {
+ touchableRegion.setEmpty();
+ }
+
+ visible = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.visible);
+ canReceiveKeys = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.canReceiveKeys);
+ hasFocus = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.hasFocus);
+ hasWallpaper = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.hasWallpaper);
+ paused = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.paused);
+ layer = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layer);
+ ownerPid = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.ownerPid);
+ ownerUid = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.ownerUid);
+ inputFeatures = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.inputFeatures);
+
+ env->DeleteLocalRef(obj);
+ return true;
+}
+
// --- Global functions ---
@@ -127,6 +227,65 @@
clazz,
"inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz,
+ "inputChannel", "Landroid/view/InputChannel;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
+ "name", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
+ "layoutParamsFlags", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
+ "layoutParamsType", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
+ "dispatchingTimeoutNanos", "J");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
+ "frameLeft", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz,
+ "frameTop", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz,
+ "frameRight", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz,
+ "frameBottom", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
+ "scaleFactor", "F");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
+ "touchableRegion", "Landroid/graphics/Region;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
+ "visible", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz,
+ "canReceiveKeys", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz,
+ "hasFocus", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
+ "hasWallpaper", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
+ "paused", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layer, clazz,
+ "layer", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
+ "ownerPid", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
+ "ownerUid", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
+ "inputFeatures", "I");
return 0;
}
diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h
index 43f2a6b..913c3b1 100644
--- a/services/jni/com_android_server_InputWindowHandle.h
+++ b/services/jni/com_android_server_InputWindowHandle.h
@@ -32,6 +32,8 @@
jobject getInputWindowHandleObjLocalRef(JNIEnv* env);
+ virtual bool update();
+
private:
jweak mObjWeak;
};
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index 5f920f1..d28a6b4 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "VpnJni"
#include <cutils/log.h>
-#include <cutils/properties.h>
#include <stdio.h>
#include <string.h>
@@ -54,7 +53,7 @@
#define SYSTEM_ERROR -1
#define BAD_ARGUMENT -2
-static int create_interface(char *name, int *index, int mtu)
+static int create_interface(int mtu)
{
int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
@@ -82,14 +81,6 @@
goto error;
}
- // Get interface index.
- if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
- LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
- goto error;
- }
-
- strncpy(name, ifr4.ifr_name, IFNAMSIZ);
- *index = ifr4.ifr_ifindex;
return tun;
error:
@@ -97,12 +88,40 @@
return SYSTEM_ERROR;
}
-static int set_addresses(const char *name, int index, const char *addresses)
+static int get_interface_name(char *name, int tun)
{
ifreq ifr4;
+ if (ioctl(tun, TUNGETIFF, &ifr4)) {
+ LOGE("Cannot get interface name: %s", strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+ return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+ LOGE("Cannot get index of %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
+{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
+ ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
ifr4.ifr_addr.sa_family = AF_INET;
+ ifr4.ifr_netmask.sa_family = AF_INET;
in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6));
@@ -146,7 +165,7 @@
}
in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
- *as_in_addr(&ifr4.ifr_addr) = htonl(mask);
+ *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
@@ -168,8 +187,13 @@
return count;
}
-static int set_routes(const char *name, int index, const char *routes)
+static int set_routes(const char *name, const char *routes)
{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
rtentry rt4;
memset(&rt4, 0, sizeof(rt4));
rt4.rt_dev = (char *)name;
@@ -253,17 +277,6 @@
return count;
}
-static int get_interface_name(char *name, int tun)
-{
- ifreq ifr4;
- if (ioctl(tun, TUNGETIFF, &ifr4)) {
- LOGE("Cannot get interface name: %s", strerror(errno));
- return SYSTEM_ERROR;
- }
- strncpy(name, ifr4.ifr_name, IFNAMSIZ);
- return 0;
-}
-
static int reset_interface(const char *name)
{
ifreq ifr4;
@@ -309,53 +322,14 @@
}
}
-static jint configure(JNIEnv *env, jobject thiz,
- jint mtu, jstring jAddresses, jstring jRoutes)
+static jint create(JNIEnv *env, jobject thiz, jint mtu)
{
- char name[IFNAMSIZ];
- int index;
- int tun = create_interface(name, &index, mtu);
+ int tun = create_interface(mtu);
if (tun < 0) {
throwException(env, tun, "Cannot create interface");
return -1;
}
-
- const char *addresses = NULL;
- const char *routes = NULL;
- int count;
-
- // At least one address must be set.
- addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
- if (!addresses) {
- jniThrowNullPointerException(env, "address");
- goto error;
- }
- count = set_addresses(name, index, addresses);
- env->ReleaseStringUTFChars(jAddresses, addresses);
- if (count <= 0) {
- throwException(env, count, "Cannot set address");
- goto error;
- }
- LOGD("Configured %d address(es) on %s", count, name);
-
- // On the contrary, routes are optional.
- routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
- if (routes) {
- count = set_routes(name, index, routes);
- env->ReleaseStringUTFChars(jRoutes, routes);
- if (count < 0) {
- throwException(env, count, "Cannot set route");
- goto error;
- }
- LOGD("Configured %d route(s) on %s", count, name);
- }
-
return tun;
-
-error:
- close(tun);
- LOGD("%s is destroyed", name);
- return -1;
}
static jstring getName(JNIEnv *env, jobject thiz, jint tun)
@@ -368,6 +342,72 @@
return env->NewStringUTF(name);
}
+static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jAddresses)
+{
+ const char *name = NULL;
+ const char *addresses = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
+ if (!addresses) {
+ jniThrowNullPointerException(env, "addresses");
+ goto error;
+ }
+ count = set_addresses(name, addresses);
+ if (count < 0) {
+ throwException(env, count, "Cannot set address");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (addresses) {
+ env->ReleaseStringUTFChars(jAddresses, addresses);
+ }
+ return count;
+}
+
+static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jRoutes)
+{
+ const char *name = NULL;
+ const char *routes = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
+ if (!routes) {
+ jniThrowNullPointerException(env, "routes");
+ goto error;
+ }
+ count = set_routes(name, routes);
+ if (count < 0) {
+ throwException(env, count, "Cannot set route");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (routes) {
+ env->ReleaseStringUTFChars(jRoutes, routes);
+ }
+ return count;
+}
+
static void reset(JNIEnv *env, jobject thiz, jstring jName)
{
const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
@@ -409,8 +449,10 @@
//------------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"jniConfigure", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)configure},
+ {"jniCreate", "(I)I", (void *)create},
{"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
+ {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+ {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
{"jniReset", "(Ljava/lang/String;)V", (void *)reset},
{"jniCheck", "(Ljava/lang/String;)I", (void *)check},
{"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 9dff48b..4178039 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -22,9 +22,7 @@
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_BatteryService(JNIEnv* env);
-int register_android_server_InputApplication(JNIEnv* env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
-int register_android_server_InputWindow(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
@@ -51,9 +49,7 @@
LOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_PowerManagerService(env);
- register_android_server_InputApplication(env);
register_android_server_InputApplicationHandle(env);
- register_android_server_InputWindow(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index fba3184..a69ce8b 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -52,7 +52,7 @@
/**
* Class returned by onSetupConnectionCompleted.
*/
- protected enum SetupResult {
+ public enum SetupResult {
SUCCESS,
ERR_BadCommand,
ERR_UnacceptableParameter,
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 5c84fdc..1bba8e3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,30 +17,25 @@
package com.android.internal.telephony;
+import com.android.internal.telephony.DataCallState.SetupResult;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import android.app.PendingIntent;
-import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.net.LinkProperties.CompareAddressesResult;
import android.net.ProxyProperties;
import android.os.AsyncResult;
-import android.os.Bundle;
import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.os.SystemProperties;
import android.text.TextUtils;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* {@hide}
@@ -497,8 +492,7 @@
} else {
if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
cid = response.cid;
- // set link properties based on data call response
- result = setLinkProperties(response, mLinkProperties);
+ result = updateLinkProperty(response).setupResult;
}
return result;
@@ -527,48 +521,41 @@
return response.setLinkProperties(lp, okToUseSystemPropertyDns);
}
- private DataConnectionAc.LinkPropertyChangeAction updateLinkProperty(
- DataCallState newState) {
- DataConnectionAc.LinkPropertyChangeAction changed =
- DataConnectionAc.LinkPropertyChangeAction.NONE;
+ public static class UpdateLinkPropertyResult {
+ public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
+ public LinkProperties oldLp;
+ public LinkProperties newLp;
+ public UpdateLinkPropertyResult(LinkProperties curLp) {
+ oldLp = curLp;
+ newLp = curLp;
+ }
+ }
- if (newState == null) return changed;
+ private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
+ UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
- DataCallState.SetupResult result;
- LinkProperties newLp = new LinkProperties();
+ if (newState == null) return result;
+
+ DataCallState.SetupResult setupResult;
+ result.newLp = new LinkProperties();
// set link properties based on data call response
- result = setLinkProperties(newState, newLp);
- if (result != DataCallState.SetupResult.SUCCESS) {
- if (DBG) log("UpdateLinkProperty failed : " + result);
- return changed;
+ result.setupResult = setLinkProperties(newState, result.newLp);
+ if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
+ if (DBG) log("updateLinkProperty failed : " + result.setupResult);
+ return result;
}
// copy HTTP proxy as it is not part DataCallState.
- newLp.setHttpProxy(mLinkProperties.getHttpProxy());
+ result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
- if (DBG) log("old LP=" + mLinkProperties);
- if (DBG) log("new LP=" + newLp);
-
- // Check consistency of link address. Currently we expect
- // only one "global" address is assigned per each IP type.
- Collection<LinkAddress> oLinks = mLinkProperties.getLinkAddresses();
- Collection<LinkAddress> nLinks = newLp.getLinkAddresses();
- for (LinkAddress oldLink : oLinks) {
- for (LinkAddress newLink : nLinks) {
- if ((NetworkUtils.addressTypeMatches(oldLink.getAddress(),
- newLink.getAddress())) &&
- (oldLink.equals(newLink) == false)) {
- return DataConnectionAc.LinkPropertyChangeAction.RESET;
- }
- }
+ if (DBG && (! result.oldLp.equals(result.newLp))) {
+ if (DBG) log("updateLinkProperty old != new");
+ if (VDBG) log("updateLinkProperty old LP=" + result.oldLp);
+ if (VDBG) log("updateLinkProperty new LP=" + result.newLp);
}
+ mLinkProperties = result.newLp;
- if (mLinkProperties == null || !mLinkProperties.equals(newLp)) {
- mLinkProperties = newLp;
- changed = DataConnectionAc.LinkPropertyChangeAction.CHANGED;
- }
-
- return changed;
+ return result;
}
/**
@@ -643,14 +630,15 @@
}
case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
DataCallState newState = (DataCallState) msg.obj;
- DataConnectionAc.LinkPropertyChangeAction action = updateLinkProperty(newState);
+ UpdateLinkPropertyResult result =
+ updateLinkProperty(newState);
if (VDBG) {
- log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE action="
- + action + " newState=" + newState);
+ log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
+ + result + " newState=" + newState);
}
mAc.replyToMessage(msg,
DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
- action.ordinal());
+ result);
break;
}
case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
@@ -688,7 +676,7 @@
case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
- new ArrayList(mApnList));
+ new ArrayList<ApnContext>(mApnList));
break;
}
case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 309dbed..9e185e5 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -16,12 +16,14 @@
package com.android.internal.telephony;
+import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import android.app.PendingIntent;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
+import android.net.LinkProperties.CompareAddressesResult;
import android.net.ProxyProperties;
import android.os.Message;
@@ -310,18 +312,18 @@
if (DBG) log("reqUpdateLinkPropertiesDataCallState");
}
- public LinkPropertyChangeAction rspUpdateLinkPropertiesDataCallState(Message response) {
- LinkPropertyChangeAction retVal = LinkPropertyChangeAction.fromInt(response.arg1);
- if (DBG) log("rspUpdateLinkPropertiesState=" + retVal);
+ public UpdateLinkPropertyResult rspUpdateLinkPropertiesDataCallState(Message response) {
+ UpdateLinkPropertyResult retVal = (UpdateLinkPropertyResult)response.obj;
+ if (DBG) log("rspUpdateLinkPropertiesState: retVal=" + retVal);
return retVal;
}
/**
* Update link properties in the data connection
*
- * @return true if link property has been updated. false otherwise.
+ * @return the removed and added addresses.
*/
- public LinkPropertyChangeAction updateLinkPropertiesDataCallStateSync(DataCallState newState) {
+ public UpdateLinkPropertyResult updateLinkPropertiesDataCallStateSync(DataCallState newState) {
Message response =
sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
if ((response != null) &&
@@ -329,7 +331,7 @@
return rspUpdateLinkPropertiesDataCallState(response);
} else {
log("getLinkProperties error response=" + response);
- return LinkPropertyChangeAction.NONE;
+ return new UpdateLinkPropertyResult(new LinkProperties());
}
}
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 48c5318..4b02e8e 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1430,6 +1430,11 @@
String getMeid();
/**
+ * Retrieves IMEI for phones. Returns null if IMEI is not set.
+ */
+ String getImei();
+
+ /**
* Retrieves the PhoneSubInfo of the Phone
*/
public PhoneSubInfo getPhoneSubInfo();
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index c2212db..b5bfc76f 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -685,6 +685,10 @@
return mActivePhone.getMeid();
}
+ public String getImei() {
+ return mActivePhone.getImei();
+ }
+
public PhoneSubInfo getPhoneSubInfo(){
return mActivePhone.getPhoneSubInfo();
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index a31b704..0d9d27d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -136,6 +136,11 @@
}
@Override
+ public String getImei() {
+ return mImei;
+ }
+
+ @Override
protected void log(String s) {
if (DBG)
Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 8a60b5a..286515e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -122,6 +122,8 @@
//keep track of if phone is in emergency callback mode
private boolean mIsPhoneInEcmState;
private Registrant mEcmExitRespRegistrant;
+ protected String mImei;
+ protected String mImeiSv;
private String mEsn;
private String mMeid;
// string to define how the carrier specifies its own ota sp number
@@ -489,6 +491,11 @@
return mSST.getImsi();
}
+ public String getImei() {
+ Log.e(LOG_TAG, "IMEI is not available in CDMA");
+ return null;
+ }
+
public boolean canConference() {
Log.e(LOG_TAG, "canConference: not possible in CDMA");
return false;
@@ -987,6 +994,8 @@
break;
}
String[] respId = (String[])ar.result;
+ mImei = respId[0];
+ mImeiSv = respId[1];
mEsn = respId[2];
mMeid = respId[3];
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index d357eac..1db9860 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -855,6 +855,10 @@
return mImeiSv;
}
+ public String getImei() {
+ return mImei;
+ }
+
public String getEsn() {
Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
return "0";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index df5898b..bf964b7 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -26,6 +26,9 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties.CompareAddressesResult;
+import android.net.NetworkUtils;
import android.net.ProxyProperties;
import android.net.TrafficStats;
import android.net.Uri;
@@ -53,6 +56,7 @@
import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone;
@@ -1037,7 +1041,7 @@
/**
* @param dcacs Collection of DataConnectionAc reported from RIL.
- * @return List of ApnContext whihc is connected, but does not present in
+ * @return List of ApnContext which is connected, but is not present in
* data connection list reported from RIL.
*/
private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
@@ -1091,32 +1095,30 @@
if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
// Create a hash map to store the dataCallState of each DataConnectionAc
- // TODO: Depends on how frequent the DATA_CALL_LIST got updated,
- // may cache response to reduce comparison.
- HashMap<DataCallState, DataConnectionAc> response;
- response = new HashMap<DataCallState, DataConnectionAc>();
+ HashMap<DataCallState, DataConnectionAc> dataCallStateToDcac;
+ dataCallStateToDcac = new HashMap<DataCallState, DataConnectionAc>();
for (DataCallState dataCallState : dataCallStates) {
DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);
- if (dcac != null) response.put(dataCallState, dcac);
+ if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac);
}
- // step1: Find a list of "connected" APN which does not have reference to
- // calls listed in the Data Call List.
- List<ApnContext> apnsToClear = findApnContextToClean(response.values());
+ // A list of apns to cleanup, those that aren't in the list we know we have to cleanup
+ List<ApnContext> apnsToCleanup = findApnContextToClean(dataCallStateToDcac.values());
- // step2: Check status of each calls in Data Call List.
- // Collect list of ApnContext associated with the data call if the link
- // has to be cleared.
+ // Find which connections have changed state and send a notification or cleanup
for (DataCallState newState : dataCallStates) {
- DataConnectionAc dcac = response.get(newState);
+ DataConnectionAc dcac = dataCallStateToDcac.get(newState);
- // no associated DataConnection found. Ignore.
- if (dcac == null) continue;
+ if (dcac == null) {
+ loge("onDataStateChanged(ar): No associated DataConnection ignore");
+ continue;
+ }
+ // The list of apn's associated with this DataConnection
Collection<ApnContext> apns = dcac.getApnListSync();
- // filter out ApnContext with "Connected/Connecting" state.
+ // Find which ApnContexts of this DC are in the "Connected/Connecting" state.
ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
for (ApnContext apnContext : apns) {
if (apnContext.getState() == State.CONNECTED ||
@@ -1125,67 +1127,86 @@
connectedApns.add(apnContext);
}
}
-
- // No "Connected" ApnContext associated with this CID. Ignore.
- if (connectedApns.isEmpty()) {
- continue;
- }
-
- if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
- + " newState=" + newState.toString());
- if (newState.active != 0) {
- boolean resetConnection;
- switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) {
- case NONE:
- if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
- resetConnection = false;
- break;
- case CHANGED:
- for (ApnContext apnContext : connectedApns) {
- if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" +
- apnContext.toString() + ")");
- mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
- apnContext.getApnType());
+ if (connectedApns.size() == 0) {
+ if (DBG) log("onDataStateChanged(ar): no connected apns");
+ } else {
+ // Determine if the connection/apnContext should be cleaned up
+ // or just a notification should be sent out.
+ if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
+ + " newState=" + newState.toString());
+ if (newState.active == 0) {
+ if (DBG) {
+ log("onDataStateChanged(ar): inactive, cleanup apns=" + connectedApns);
}
- // Temporary hack, at this time a transition from CDMA -> Global
- // fails so we'll hope for the best and not reset the connection.
- // @see bug/4455071
- if (SystemProperties.getBoolean("telephony.ignore-state-changes",
- true)) {
- log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
- resetConnection = false;
+ apnsToCleanup.addAll(connectedApns);
+ } else {
+ // Its active so update the DataConnections link properties
+ UpdateLinkPropertyResult result =
+ dcac.updateLinkPropertiesDataCallStateSync(newState);
+ if (result.oldLp.equals(result.newLp)) {
+ if (DBG) log("onDataStateChanged(ar): no change");
} else {
- // Things changed so reset connection, when hack is removed
- // this is the normal path.
- log("onDataStateChanged(ar): changed so resetting connection");
- resetConnection = true;
+ if (result.oldLp.isIdenticalInterfaceName(result.newLp)) {
+ if (! result.oldLp.isIdenticalDnses(result.newLp) ||
+ ! result.oldLp.isIdenticalRoutes(result.newLp) ||
+ ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
+ ! result.oldLp.isIdenticalAddresses(result.newLp)) {
+ // If the same address type was removed and added we need to cleanup
+ CompareAddressesResult car =
+ result.oldLp.compareAddresses(result.newLp);
+ boolean needToClean = false;
+ for (LinkAddress added : car.added) {
+ for (LinkAddress removed : car.removed) {
+ if (NetworkUtils.addressTypeMatches(removed.getAddress(),
+ added.getAddress())) {
+ needToClean = true;
+ break;
+ }
+ }
+ }
+ if (needToClean) {
+ if (DBG) {
+ log("onDataStateChanged(ar): addr change, cleanup apns=" +
+ connectedApns);
+ }
+ apnsToCleanup.addAll(connectedApns);
+ } else {
+ if (DBG) log("onDataStateChanged(ar): simple change");
+ for (ApnContext apnContext : connectedApns) {
+ mPhone.notifyDataConnection(
+ Phone.REASON_LINK_PROPERTIES_CHANGED,
+ apnContext.getApnType());
+ }
+ }
+ } else {
+ if (DBG) {
+ log("onDataStateChanged(ar): no changes");
+ }
+ }
+ } else {
+ if (DBG) {
+ log("onDataStateChanged(ar): interface change, cleanup apns="
+ + connectedApns);
+ }
+ apnsToCleanup.addAll(connectedApns);
+ }
}
- break;
- case RESET:
- default:
- if (DBG) log("onDataStateChanged(ar): an error, reset connection");
- resetConnection = true;
- break;
}
- if (resetConnection == false) continue;
}
-
- if (DBG) log("onDataStateChanged(ar): reset connection.");
-
- apnsToClear.addAll(connectedApns);
}
- // step3: Clear apn connection if applicable.
- if (!apnsToClear.isEmpty()) {
+ if (apnsToCleanup.size() != 0) {
// Add an event log when the network drops PDP
int cid = getCellLocationId();
EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
TelephonyManager.getDefault().getNetworkType());
}
- for (ApnContext apnContext : apnsToClear) {
+ // Cleanup those dropped connections
+ for (ApnContext apnContext : apnsToCleanup) {
cleanUpConnection(true, apnContext);
}
+
if (DBG) log("onDataStateChanged(ar): X");
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 9dfc015..5c4b446 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -264,6 +264,10 @@
return null;
}
+ public String getImei() {
+ return null;
+ }
+
public String getEsn() {
Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method");
return "0";
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index b9bf526..af5006f 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -38,20 +38,20 @@
vg.setUseDefaultMargins(true);
vg.setAlignmentMode(ALIGN_BOUNDS);
- Group row1 = new Group(1, CENTER);
- Group row2 = new Group(2, CENTER);
- Group row3 = new Group(3, BASELINE);
- Group row4 = new Group(4, BASELINE);
- Group row5 = new Group(5, FILL);
- Group row6 = new Group(6, CENTER);
- Group row7 = new Group(7, CENTER);
+ Spec row1 = spec(0, CENTER);
+ Spec row2 = spec(1, CENTER);
+ Spec row3 = spec(2, BASELINE);
+ Spec row4 = spec(3, BASELINE);
+ Spec row5 = spec(4, FILL, CAN_STRETCH);
+ Spec row6 = spec(5, CENTER);
+ Spec row7 = spec(6, CENTER);
- Group col1a = new Group(1, 4, CENTER);
- Group col1b = new Group(1, 4, LEFT);
- Group col1c = new Group(1, RIGHT);
- Group col2 = new Group(2, LEFT);
- Group col3 = new Group(3, FILL);
- Group col4 = new Group(4, FILL);
+ Spec col1a = spec(0, 4, CENTER);
+ Spec col1b = spec(0, 4, LEFT);
+ Spec col1c = spec(0, RIGHT);
+ Spec col2 = spec(1, LEFT);
+ Spec col3 = spec(2, FILL, CAN_STRETCH);
+ Spec col4 = spec(3, FILL);
{
TextView v = new TextView(context);
@@ -96,10 +96,7 @@
{
Space v = new Space(context);
{
- LayoutParams lp = new LayoutParams(row5, col3);
- lp.columnGroup.flexibility = CAN_STRETCH;
- lp.rowGroup.flexibility = CAN_STRETCH;
- vg.addView(v, lp);
+ vg.addView(v, new LayoutParams(row5, col3));
}
}
{
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
index 505c83d..b1c4486 100755
--- a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
@@ -21,7 +21,6 @@
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridLayout;
@@ -84,9 +83,7 @@
Alignment va = VERTICAL_ALIGNMENTS[i];
for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
Alignment ha = HORIZONTAL_ALIGNMENTS[j];
- Group rowGroup = new Group(i, va);
- Group colGroup = new Group(j, ha);
- LayoutParams layoutParams = new LayoutParams(rowGroup, colGroup);
+ LayoutParams layoutParams = new LayoutParams(spec(i, va), spec(j, ha));
String name = VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j];
ViewFactory factory = FACTORIES[(i + j) % FACTORIES.length];
container.addView(factory.create(name, 20), layoutParams);
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
index c5681e2..4ce449a 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
@@ -33,9 +33,9 @@
int va = VERTICAL_ALIGNMENTS[i];
for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
int ha = HORIZONTAL_ALIGNMENTS[j];
- GridLayout.Group rowGroup = new GridLayout.Group(UNDEFINED, null);
- GridLayout.Group colGroup = new GridLayout.Group(UNDEFINED, null);
- GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowGroup, colGroup);
+ Spec rowSpec = spec(UNDEFINED, null);
+ Spec colSpec = spec(UNDEFINED, null);
+ GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowSpec, colSpec);
//GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.setGravity(va | ha);
View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index a44072d..6b69864 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -198,7 +198,7 @@
}
void
-Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -207,7 +207,7 @@
}
void
-Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -226,7 +226,7 @@
void
Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -235,7 +235,7 @@
}
void
-Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -284,7 +284,7 @@
}
void
-BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
}
@@ -303,13 +303,13 @@
void
BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
}
void
-BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
}
@@ -331,7 +331,7 @@
}
void
-BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"),
"!=", new MethodCall(parcel, "readInt"))));
@@ -351,13 +351,13 @@
void
BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
}
void
-BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
}
@@ -378,7 +378,7 @@
}
void
-CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
}
@@ -397,13 +397,13 @@
void
CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
}
void
-CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
}
@@ -428,7 +428,7 @@
}
void
-StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
}
@@ -447,13 +447,13 @@
void
StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
}
void
-StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
}
@@ -496,7 +496,7 @@
void
CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = TextUtils.createFromParcel(parcel)
@@ -532,7 +532,7 @@
}
void
-RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -551,7 +551,7 @@
}
void
-RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -571,7 +571,7 @@
}
void
-IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
}
@@ -584,13 +584,13 @@
void
IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
}
void
-IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
}
@@ -610,7 +610,7 @@
}
void
-IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -631,7 +631,7 @@
void
BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -652,7 +652,7 @@
void
BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -672,7 +672,7 @@
}
void
-ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -691,7 +691,7 @@
}
void
-ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -709,25 +709,31 @@
addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
}
-void
-MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+static void EnsureClassLoader(StatementBlock* addTo, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, cl)));
+ // We don't want to look up the class loader once for every
+ // collection argument, so ensure we do it at most once per method.
+ if (*cl == NULL) {
+ *cl = new Variable(CLASSLOADER_TYPE, "cl");
+ addTo->Add(new VariableDeclaration(*cl,
+ new LiteralExpression("this.getClass().getClassLoader()"),
+ CLASSLOADER_TYPE));
+ }
+}
+
+void
+MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
+{
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl)));
}
void
MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new MethodCall(parcel, "readMap", 2, v, cl));
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
}
@@ -751,24 +757,18 @@
}
void
-ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, cl)));
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl)));
}
void
ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new MethodCall(parcel, "readList", 2, v, cl));
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
}
@@ -811,7 +811,7 @@
}
void
-ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = CLASS.CREATOR.createFromParcel(parcel)
@@ -833,7 +833,7 @@
void
ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
// TODO: really, we don't need to have this extra check, but we
// don't have two separate marshalling code paths
@@ -862,7 +862,7 @@
void
ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new Assignment(v, new MethodCall(parcel,
@@ -870,7 +870,7 @@
}
void
-ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
@@ -907,7 +907,7 @@
}
void
-InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// v = Interface.asInterface(parcel.readStrongBinder());
string type = v->type->QualifiedName();
@@ -961,14 +961,14 @@
}
void
-GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "implement GenericType::CreateFromParcel\n");
}
void
GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "implement GenericType::ReadFromParcel\n");
}
@@ -1009,7 +1009,7 @@
}
void
-GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
if (m_creator == STRING_TYPE->CreatorName()) {
addTo->Add(new Assignment(v,
@@ -1027,7 +1027,7 @@
void
GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
if (m_creator == STRING_TYPE->CreatorName()) {
addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 2ea3ac9..662e3a2 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -46,18 +46,18 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
protected:
void SetQualifiedName(const string& qualified);
@@ -89,16 +89,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
string m_marshallMethod;
@@ -116,16 +116,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class CharType : public Type
@@ -136,16 +136,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
@@ -159,16 +159,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class CharSequenceType : public Type
@@ -181,7 +181,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class RemoteExceptionType : public Type
@@ -192,7 +192,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class RuntimeExceptionType : public Type
@@ -203,7 +203,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class IBinderType : public Type
@@ -214,14 +214,14 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class IInterfaceType : public Type
@@ -232,7 +232,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class BinderType : public Type
@@ -243,7 +243,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class BinderProxyType : public Type
@@ -254,7 +254,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ParcelType : public Type
@@ -265,7 +265,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ParcelableInterfaceType : public Type
@@ -276,7 +276,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class MapType : public Type
@@ -287,9 +287,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ListType : public Type
@@ -302,9 +302,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ParcelableType : public Type
@@ -318,18 +318,18 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class InterfaceType : public Type
@@ -344,7 +344,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
bool m_oneway;
@@ -364,9 +364,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
string m_genericArguments;
@@ -387,9 +387,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
string m_creator;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index f17f66b..92f5b64 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -948,8 +948,6 @@
int
main(int argc, const char **argv)
{
- int err = 0;
-
Options options;
int result = parse_options(argc, argv, &options);
if (result) {
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 0f18132..83e3bbc 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -286,25 +286,25 @@
static void
generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
if (v->dimension == 0) {
- t->CreateFromParcel(addTo, v, parcel);
+ t->CreateFromParcel(addTo, v, parcel, cl);
}
if (v->dimension == 1) {
- t->CreateArrayFromParcel(addTo, v, parcel);
+ t->CreateArrayFromParcel(addTo, v, parcel, cl);
}
}
static void
generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
if (v->dimension == 0) {
- t->ReadFromParcel(addTo, v, parcel);
+ t->ReadFromParcel(addTo, v, parcel, cl);
}
if (v->dimension == 1) {
- t->ReadArrayFromParcel(addTo, v, parcel);
+ t->ReadArrayFromParcel(addTo, v, parcel, cl);
}
}
@@ -362,6 +362,7 @@
"enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
// args
+ Variable* cl = NULL;
VariableFactory stubArgs("_arg");
arg = method->args;
while (arg != NULL) {
@@ -373,7 +374,7 @@
if (convert_direction(arg->direction.data) & IN_PARAMETER) {
generate_create_from_parcel(t, c->statements, v,
- stubClass->transact_data);
+ stubClass->transact_data, &cl);
} else {
if (arg->type.dimension == 0) {
c->statements->Add(new Assignment(
@@ -531,7 +532,7 @@
if (_reply != NULL) {
if (_result != NULL) {
generate_create_from_parcel(proxy->returnType,
- tryStatement->statements, _result, _reply);
+ tryStatement->statements, _result, _reply, &cl);
}
// the out/inout parameters
@@ -541,7 +542,7 @@
Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
generate_read_from_parcel(t, tryStatement->statements,
- v, _reply);
+ v, _reply, &cl);
}
arg = arg->next;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 260cdc8..fc2f2f8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -131,6 +131,10 @@
*/
@Override
public CharSequence getText(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] != null) {
// FIXME: handle styled strings!
return mResourceData[index].getValue();
@@ -149,6 +153,10 @@
*/
@Override
public String getString(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] != null) {
return mResourceData[index].getValue();
}
@@ -166,6 +174,10 @@
*/
@Override
public boolean getBoolean(int index, boolean defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -188,6 +200,10 @@
*/
@Override
public int getInt(int index, int defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -252,6 +268,10 @@
*/
@Override
public float getFloat(int index, float defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -287,6 +307,10 @@
*/
@Override
public int getColor(int index, int defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -311,6 +335,10 @@
*/
@Override
public ColorStateList getColorStateList(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] == null) {
return null;
}
@@ -395,6 +423,10 @@
*/
@Override
public float getDimension(int index, float defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -568,6 +600,10 @@
*/
@Override
public float getFraction(int index, int base, int pbase, float defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -607,6 +643,10 @@
*/
@Override
public int getResourceId(int index, int defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
// get the Resource for this index
ResourceValue resValue = mResourceData[index];
@@ -718,6 +758,10 @@
*/
@Override
public Drawable getDrawable(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] == null) {
return null;
}
@@ -744,6 +788,10 @@
*/
@Override
public CharSequence[] getTextArray(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] == null) {
return null;
}
@@ -776,6 +824,10 @@
*/
@Override
public boolean getValue(int index, TypedValue outValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return false;
+ }
+
if (mResourceData[index] == null) {
return false;
}
@@ -795,6 +847,10 @@
*/
@Override
public boolean hasValue(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return false;
+ }
+
return mResourceData[index] != null;
}
@@ -811,6 +867,10 @@
*/
@Override
public TypedValue peekValue(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (getValue(index, mValue)) {
return mValue;
}
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index c1affa6..fcdbd2c 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -57,6 +57,7 @@
private static final boolean RELEASE_SOCKET = true;
private static final boolean DONT_RELEASE_SOCKET = false;
private static final int SESSION_TIMEOUT = 5; // in seconds
+ private static final int TRANSFER_TIMEOUT = 15; // in seconds
/** Listener for events relating to a SIP call, such as when a call is being
* recieved ("on ringing") or a call is outgoing ("on calling").
@@ -537,10 +538,14 @@
Log.v(TAG, "onCallTransferring mSipSession:"
+ mSipSession + " newSession:" + newSession);
mTransferringSession = newSession;
- // session changing request
try {
- String answer = createAnswer(sessionDescription).encode();
- newSession.answerCall(answer, SESSION_TIMEOUT);
+ if (sessionDescription == null) {
+ newSession.makeCall(newSession.getPeerProfile(),
+ createOffer().encode(), TRANSFER_TIMEOUT);
+ } else {
+ String answer = createAnswer(sessionDescription).encode();
+ newSession.answerCall(answer, SESSION_TIMEOUT);
+ }
} catch (Throwable e) {
Log.e(TAG, "onCallTransferring()", e);
newSession.endCall();
diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java
index c031bc1..dc628e0 100644
--- a/voip/java/com/android/server/sip/SipHelper.java
+++ b/voip/java/com/android/server/sip/SipHelper.java
@@ -19,6 +19,9 @@
import gov.nist.javax.sip.SipStackExt;
import gov.nist.javax.sip.clientauthutils.AccountManager;
import gov.nist.javax.sip.clientauthutils.AuthenticationHelper;
+import gov.nist.javax.sip.header.extensions.ReferencesHeader;
+import gov.nist.javax.sip.header.extensions.ReferredByHeader;
+import gov.nist.javax.sip.header.extensions.ReplacesHeader;
import android.net.sip.SipProfile;
import android.util.Log;
@@ -284,14 +287,18 @@
}
public ClientTransaction sendInvite(SipProfile caller, SipProfile callee,
- String sessionDescription, String tag)
- throws SipException {
+ String sessionDescription, String tag, ReferredByHeader referredBy,
+ String replaces) throws SipException {
try {
Request request = createRequest(Request.INVITE, caller, callee, tag);
+ if (referredBy != null) request.addHeader(referredBy);
+ if (replaces != null) {
+ request.addHeader(mHeaderFactory.createHeader(
+ ReplacesHeader.NAME, replaces));
+ }
request.setContent(sessionDescription,
mHeaderFactory.createContentTypeHeader(
"application", "sdp"));
-
ClientTransaction clientTransaction =
mSipProvider.getNewClientTransaction(request);
if (DEBUG) Log.d(TAG, "send INVITE: " + request);
@@ -455,6 +462,25 @@
}
}
+ public void sendReferNotify(Dialog dialog, String content)
+ throws SipException {
+ try {
+ Request request = dialog.createRequest(Request.NOTIFY);
+ request.addHeader(mHeaderFactory.createSubscriptionStateHeader(
+ "active;expires=60"));
+ // set content here
+ request.setContent(content,
+ mHeaderFactory.createContentTypeHeader(
+ "message", "sipfrag"));
+ request.addHeader(mHeaderFactory.createEventHeader(
+ ReferencesHeader.REFER));
+ if (DEBUG) Log.d(TAG, "send NOTIFY: " + request);
+ dialog.sendRequest(mSipProvider.getNewClientTransaction(request));
+ } catch (ParseException e) {
+ throw new SipException("sendReferNotify()", e);
+ }
+ }
+
public void sendInviteRequestTerminated(Request inviteRequest,
ServerTransaction inviteTransaction) throws SipException {
try {
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 4e44402..48d9b17 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -18,12 +18,15 @@
import gov.nist.javax.sip.clientauthutils.AccountManager;
import gov.nist.javax.sip.clientauthutils.UserCredentials;
-import gov.nist.javax.sip.header.SIPHeaderNames;
import gov.nist.javax.sip.header.ProxyAuthenticate;
+import gov.nist.javax.sip.header.ReferTo;
+import gov.nist.javax.sip.header.SIPHeaderNames;
+import gov.nist.javax.sip.header.StatusLine;
import gov.nist.javax.sip.header.WWWAuthenticate;
import gov.nist.javax.sip.header.extensions.ReferredByHeader;
import gov.nist.javax.sip.header.extensions.ReplacesHeader;
import gov.nist.javax.sip.message.SIPMessage;
+import gov.nist.javax.sip.message.SIPResponse;
import android.net.sip.ISipSession;
import android.net.sip.ISipSessionListener;
@@ -71,12 +74,15 @@
import javax.sip.header.CSeqHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
+import javax.sip.header.HeaderAddress;
import javax.sip.header.MinExpiresHeader;
+import javax.sip.header.ReferToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Message;
import javax.sip.message.Request;
import javax.sip.message.Response;
+
/**
* Manages {@link ISipSession}'s for a SIP account.
*/
@@ -390,25 +396,26 @@
}
}
+ private SipSessionImpl createNewSession(RequestEvent event,
+ ISipSessionListener listener, ServerTransaction transaction,
+ int newState) throws SipException {
+ SipSessionImpl newSession = new SipSessionImpl(listener);
+ newSession.mServerTransaction = transaction;
+ newSession.mState = newState;
+ newSession.mDialog = newSession.mServerTransaction.getDialog();
+ newSession.mInviteReceived = event;
+ newSession.mPeerProfile = createPeerProfile((HeaderAddress)
+ event.getRequest().getHeader(FromHeader.NAME));
+ newSession.mPeerSessionDescription =
+ extractContent(event.getRequest());
+ return newSession;
+ }
+
private class SipSessionCallReceiverImpl extends SipSessionImpl {
public SipSessionCallReceiverImpl(ISipSessionListener listener) {
super(listener);
}
- private SipSessionImpl createNewSession(RequestEvent event,
- ISipSessionListener listener, ServerTransaction transaction)
- throws SipException {
- SipSessionImpl newSession = new SipSessionImpl(listener);
- newSession.mServerTransaction = transaction;
- newSession.mState = SipSession.State.INCOMING_CALL;
- newSession.mDialog = newSession.mServerTransaction.getDialog();
- newSession.mInviteReceived = event;
- newSession.mPeerProfile = createPeerProfile(event.getRequest());
- newSession.mPeerSessionDescription =
- extractContent(event.getRequest());
- return newSession;
- }
-
private int processInviteWithReplaces(RequestEvent event,
ReplacesHeader replaces) {
String callId = replaces.getCallId();
@@ -452,7 +459,8 @@
// got INVITE w/ replaces request.
newSession = createNewSession(event,
replacedSession.mProxy.getListener(),
- mSipHelper.getServerTransaction(event));
+ mSipHelper.getServerTransaction(event),
+ SipSession.State.INCOMING_CALL);
newSession.mProxy.onCallTransferring(newSession,
newSession.mPeerSessionDescription);
} else {
@@ -461,7 +469,8 @@
} else {
// New Incoming call.
newSession = createNewSession(event, mProxy,
- mSipHelper.sendRinging(event, generateTag()));
+ mSipHelper.sendRinging(event, generateTag()),
+ SipSession.State.INCOMING_CALL);
mProxy.onRinging(newSession, newSession.mPeerProfile,
newSession.mPeerSessionDescription);
}
@@ -507,6 +516,11 @@
private SipSessionImpl mKeepAliveSession;
+ // the following three members are used for handling refer request.
+ SipSessionImpl mReferSession;
+ ReferredByHeader mReferredBy;
+ String mReplaces;
+
// lightweight timer
class SessionTimer {
private boolean mRunning = true;
@@ -556,6 +570,9 @@
mInviteReceived = null;
mPeerSessionDescription = null;
mAuthenticationRetryCount = 0;
+ mReferSession = null;
+ mReferredBy = null;
+ mReplaces = null;
if (mDialog != null) mDialog.delete();
mDialog = null;
@@ -969,15 +986,26 @@
return (proxyAuth == null) ? null : proxyAuth.getNonce();
}
+ private String getResponseString(int statusCode) {
+ StatusLine statusLine = new StatusLine();
+ statusLine.setStatusCode(statusCode);
+ statusLine.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode));
+ return statusLine.encode();
+ }
+
private boolean readyForCall(EventObject evt) throws SipException {
// expect MakeCallCommand, RegisterCommand, DEREGISTER
if (evt instanceof MakeCallCommand) {
mState = SipSession.State.OUTGOING_CALL;
MakeCallCommand cmd = (MakeCallCommand) evt;
mPeerProfile = cmd.getPeerProfile();
- mClientTransaction = mSipHelper.sendInvite(mLocalProfile,
- mPeerProfile, cmd.getSessionDescription(),
- generateTag());
+ if (mReferSession != null) {
+ mSipHelper.sendReferNotify(mReferSession.mDialog,
+ getResponseString(Response.TRYING));
+ }
+ mClientTransaction = mSipHelper.sendInvite(
+ mLocalProfile, mPeerProfile, cmd.getSessionDescription(),
+ generateTag(), mReferredBy, mReplaces);
mDialog = mClientTransaction.getDialog();
addSipSession(this);
startSessionTimer(cmd.getTimeout());
@@ -1072,6 +1100,12 @@
}
return true;
case Response.OK:
+ if (mReferSession != null) {
+ mSipHelper.sendReferNotify(mReferSession.mDialog,
+ getResponseString(Response.OK));
+ // since we don't need to remember the session anymore.
+ mReferSession = null;
+ }
mSipHelper.sendInviteAck(event, mDialog);
mPeerSessionDescription = extractContent(response);
establishCall(true);
@@ -1087,6 +1121,10 @@
// rfc3261#section-14.1; re-schedule invite
return true;
default:
+ if (mReferSession != null) {
+ mSipHelper.sendReferNotify(mReferSession.mDialog,
+ getResponseString(Response.SERVICE_UNAVAILABLE));
+ }
if (statusCode >= 400) {
// error: an ack is sent automatically by the stack
onError(response);
@@ -1155,6 +1193,38 @@
return false;
}
+ private boolean processReferRequest(RequestEvent event)
+ throws SipException {
+ try {
+ ReferToHeader referto = (ReferToHeader) event.getRequest()
+ .getHeader(ReferTo.NAME);
+ Address address = referto.getAddress();
+ SipURI uri = (SipURI) address.getURI();
+ String replacesHeader = uri.getHeader(ReplacesHeader.NAME);
+ String username = uri.getUser();
+ if (username == null) {
+ mSipHelper.sendResponse(event, Response.BAD_REQUEST);
+ return false;
+ }
+ // send notify accepted
+ mSipHelper.sendResponse(event, Response.ACCEPTED);
+ SipSessionImpl newSession = createNewSession(event,
+ this.mProxy.getListener(),
+ mSipHelper.getServerTransaction(event),
+ SipSession.State.READY_TO_CALL);
+ newSession.mReferSession = this;
+ newSession.mReferredBy = (ReferredByHeader) event.getRequest()
+ .getHeader(ReferredByHeader.NAME);
+ newSession.mReplaces = replacesHeader;
+ newSession.mPeerProfile = createPeerProfile(referto);
+ newSession.mProxy.onCallTransferring(newSession,
+ null);
+ return true;
+ } catch (IllegalArgumentException e) {
+ throw new SipException("createPeerProfile()", e);
+ }
+ }
+
private boolean inCall(EventObject evt) throws SipException {
// expect END_CALL cmd, BYE request, hold call (MakeCallCommand)
// OK retransmission is handled in SipStack
@@ -1175,6 +1245,8 @@
mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
endCallNormally();
return true;
+ } else if (isRequestEvent(Request.REFER, evt)) {
+ return processReferRequest((RequestEvent) evt);
} else if (evt instanceof MakeCallCommand) {
// to change call
mState = SipSession.State.OUTGOING_CALL;
@@ -1182,6 +1254,8 @@
((MakeCallCommand) evt).getSessionDescription());
startSessionTimer(((MakeCallCommand) evt).getTimeout());
return true;
+ } else if (evt instanceof ResponseEvent) {
+ if (expectResponse(Request.NOTIFY, evt)) return true;
}
return false;
}
@@ -1558,12 +1632,10 @@
return false;
}
- private static SipProfile createPeerProfile(Request request)
+ private static SipProfile createPeerProfile(HeaderAddress header)
throws SipException {
try {
- FromHeader fromHeader =
- (FromHeader) request.getHeader(FromHeader.NAME);
- Address address = fromHeader.getAddress();
+ Address address = header.getAddress();
SipURI uri = (SipURI) address.getURI();
String username = uri.getUser();
if (username == null) username = ANONYMOUS;