diff options
101 files changed, 2815 insertions, 394 deletions
diff --git a/api/current.txt b/api/current.txt index b462695..6984b07 100644 --- a/api/current.txt +++ b/api/current.txt @@ -82,6 +82,8 @@ package android { field public static final java.lang.String READ_SMS = "android.permission.READ_SMS"; field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS"; field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS"; + field public static final java.lang.String READ_WRITE_ALL_VOICEMAIL = "com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL"; + field public static final java.lang.String READ_WRITE_OWN_VOICEMAIL = "com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL"; field public static final java.lang.String REBOOT = "android.permission.REBOOT"; field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED"; field public static final java.lang.String RECEIVE_MMS = "android.permission.RECEIVE_MMS"; @@ -673,6 +675,8 @@ package android { field public static final int minHeight = 16843072; // 0x1010140 field public static final int minLevel = 16843185; // 0x10101b1 field public static final int minLines = 16843094; // 0x1010156 + field public static final int minResizeHeight = 16843690; // 0x10103aa + field public static final int minResizeWidth = 16843689; // 0x10103a9 field public static final int minSdkVersion = 16843276; // 0x101020c field public static final int minWidth = 16843071; // 0x101013f field public static final int mode = 16843134; // 0x101017e @@ -3929,6 +3933,8 @@ package android.appwidget { field public int initialLayout; field public java.lang.String label; field public int minHeight; + field public int minResizeHeight; + field public int minResizeWidth; field public int minWidth; field public int previewImage; field public android.content.ComponentName provider; @@ -11287,6 +11293,7 @@ package android.net { method public static long getMobileRxPackets(); method public static long getMobileTxBytes(); method public static long getMobileTxPackets(); + method public static int getThreadStatsTag(); method public static long getTotalRxBytes(); method public static long getTotalRxPackets(); method public static long getTotalTxBytes(); @@ -11912,6 +11919,7 @@ package android.net.wifi { field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected"; field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError"; + field public static final java.lang.String EXTRA_WIFI_INFO = "wifiInfo"; field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state"; field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; @@ -14434,6 +14442,7 @@ package android.os { public class RecoverySystem { ctor public RecoverySystem(); method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException; + method public static void rebootWipeCache(android.content.Context) throws java.io.IOException; method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException; method public static void verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File) throws java.security.GeneralSecurityException, java.io.IOException; } @@ -16916,6 +16925,49 @@ package android.provider { field public static final java.lang.String _ID = "_id"; } + public class VoicemailContract { + field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL"; + field public static final java.lang.String AUTHORITY = "com.android.voicemail"; + field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE"; + field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package"; + } + + public static final class VoicemailContract.Status implements android.provider.BaseColumns { + method public static android.net.Uri buildSourceUri(java.lang.String); + field public static final java.lang.String CONFIGURATION_STATE = "configuration_state"; + field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2 + field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1 + field public static final int CONFIGURATION_STATE_OK = 0; // 0x0 + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state"; + field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1 + field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0 + field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status"; + field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status"; + field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state"; + field public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; // 0x2 + field public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1 + field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0 + field public static final java.lang.String SETTINGS_URI = "settings_uri"; + field public static final java.lang.String SOURCE_PACKAGE = "source_package"; + field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri"; + } + + public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns { + method public static android.net.Uri buildSourceUri(java.lang.String); + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String DATE = "date"; + field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails"; + field public static final java.lang.String DURATION = "duration"; + field public static final java.lang.String HAS_CONTENT = "has_content"; + field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail"; + field public static final java.lang.String MIME_TYPE = "mime_type"; + field public static final java.lang.String NEW = "new"; + field public static final java.lang.String NUMBER = "number"; + field public static final java.lang.String SOURCE_DATA = "source_data"; + field public static final java.lang.String SOURCE_PACKAGE = "source_package"; + } + } package android.renderscript { diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk index 56f1324..d602500 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -11,4 +11,9 @@ LOCAL_MODULE := dumpstate LOCAL_SHARED_LIBRARIES := libcutils +ifdef BOARD_LIB_DUMPSTATE +LOCAL_STATIC_LIBRARIES := $(BOARD_LIB_DUMPSTATE) +LOCAL_CFLAGS += -DBOARD_HAS_DUMPSTATE +endif + include $(BUILD_EXECUTABLE) diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 42c35af..4926db2 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -197,6 +197,15 @@ static void dumpstate() { dump_file(NULL, "/sys/class/leds/lcd-backlight/registers"); printf("\n"); +#ifdef BOARD_HAS_DUMPSTATE + printf("========================================================\n"); + printf("== Board\n"); + printf("========================================================\n"); + + dumpstate_board(); + printf("\n"); +#endif + printf("========================================================\n"); printf("== Android Framework Services\n"); printf("========================================================\n"); @@ -218,6 +227,9 @@ static void dumpstate() { run_command("APP SERVICES", 30, "dumpsys", "activity", "service", "all", NULL); + printf("========================================================\n"); + printf("== dumpstate: done\n"); + printf("========================================================\n"); } static void usage() { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 83b1d11..597ab1f 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -19,6 +19,7 @@ #include <time.h> #include <unistd.h> +#include <stdio.h> /* prints the contents of a file */ int dump_file(const char *title, const char* path); @@ -47,4 +48,7 @@ void show_wchan(int pid, const char *name); /* Play a sound via Stagefright */ void play_sound(const char* path); +/* Implemented by libdumpstate_board to dump board-specific info */ +void dumpstate_board(); + #endif /* _DUMPSTATE_H_ */ diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index fdf4a3a..2a731a3 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1514,6 +1514,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + Configuration config = Configuration.CREATOR.createFromParcel(data); + updatePersistentConfiguration(config); + reply.writeNoException(); + return true; + } + } return super.onTransact(code, data, reply, flags); @@ -3410,5 +3418,17 @@ class ActivityManagerProxy implements IActivityManager return res; } + public void updatePersistentConfiguration(Configuration values) throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + values.writeToParcel(data, 0); + mRemote.transact(UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 9e20764..93c821c 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -363,6 +363,8 @@ public interface IActivityManager extends IInterface { public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException; + public void updatePersistentConfiguration(Configuration values) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -590,4 +592,5 @@ public interface IActivityManager extends IInterface { int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+132; int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133; int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134; + int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135; } diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index 8204a4f..08bc0ac 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -261,6 +261,10 @@ public class AppWidgetHost { TypedValue.complexToDimensionPixelSize(appWidget.minWidth, mDisplayMetrics); appWidget.minHeight = TypedValue.complexToDimensionPixelSize(appWidget.minHeight, mDisplayMetrics); + appWidget.minResizeWidth = + TypedValue.complexToDimensionPixelSize(appWidget.minResizeWidth, mDisplayMetrics); + appWidget.minResizeHeight = + TypedValue.complexToDimensionPixelSize(appWidget.minResizeHeight, mDisplayMetrics); synchronized (mViews) { v = mViews.get(appWidgetId); diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index b46802e..b8c5b02 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -54,7 +54,8 @@ public class AppWidgetProviderInfo implements Parcelable { public ComponentName provider; /** - * Minimum width of the AppWidget, in dp. + * The default height of the widget when added to a host, in dp. The widget will get + * at least this width, and will often be given more, depending on the host. * * <p>This field corresponds to the <code>android:minWidth</code> attribute in * the AppWidget meta-data file. @@ -62,7 +63,8 @@ public class AppWidgetProviderInfo implements Parcelable { public int minWidth; /** - * Minimum height of the AppWidget, in dp. + * The default height of the widget when added to a host, in dp. The widget will get + * at least this height, and will often be given more, depending on the host. * * <p>This field corresponds to the <code>android:minHeight</code> attribute in * the AppWidget meta-data file. @@ -70,6 +72,24 @@ public class AppWidgetProviderInfo implements Parcelable { public int minHeight; /** + * Minimum width (in dp) which the widget can be resized to. This field has no effect if it + * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}). + * + * <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in + * the AppWidget meta-data file. + */ + public int minResizeWidth; + + /** + * Minimum height (in dp) which the widget can be resized to. This field has no effect if it + * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}). + * + * <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in + * the AppWidget meta-data file. + */ + public int minResizeHeight; + + /** * How often, in milliseconds, that this AppWidget wants to be updated. * The AppWidget manager may place a limit on how often a AppWidget is updated. * diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 2b59dba..e054930 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -97,6 +97,15 @@ public class TrafficStats { } /** + * Get the active tag used when accounting {@link Socket} traffic originating + * from the current thread. Only one active tag per thread is supported. + * {@link #tagSocket(Socket)}. + */ + public static int getThreadStatsTag() { + return NetworkManagementSocketTagger.getThreadSocketStatsTag(); + } + + /** * @deprecated unsupported, will eventually be removed */ @Deprecated diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index ae605fb..73e8d98 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -357,20 +357,11 @@ public class RecoverySystem { } /** - * Reboot into the recovery system to wipe the /data partition and toggle - * Encrypted File Systems on/off. - * @param extras to add to the RECOVERY_COMPLETED intent after rebooting. + * Reboot into the recovery system to wipe the /cache partition. * @throws IOException if something goes wrong. - * - * @hide */ - public static void rebootToggleEFS(Context context, boolean efsEnabled) - throws IOException { - if (efsEnabled) { - bootCommand(context, "--set_encrypted_filesystem=on"); - } else { - bootCommand(context, "--set_encrypted_filesystem=off"); - } + public static void rebootWipeCache(Context context) throws IOException { + bootCommand(context, "--wipe_cache"); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 34699e2..ad32047 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1045,6 +1045,14 @@ public final class Settings { } /** + * @hide Erase the fields in the Configuration that should be applied + * by the settings. + */ + public static void clearConfiguration(Configuration inoutConfig) { + inoutConfig.fontScale = 0; + } + + /** * Convenience function to write a batch of configuration-related * settings from a {@link Configuration} object. * diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index d0712d5..2ad7395 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -16,6 +16,9 @@ package android.provider; +import android.Manifest; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.content.Intent; import android.database.ContentObserver; import android.net.Uri; @@ -25,11 +28,26 @@ import android.provider.CallLog.Calls; * The contract between the voicemail provider and applications. Contains * definitions for the supported URIs and columns. * + * <P>The content providers exposes two tables through this interface: + * <ul> + * <li> Voicemails table: This stores the actual voicemail records. The + * columns and URIs for accessing this table are defined by the + * {@link Voicemails} class. + * </li> + * <li> Status table: This provides a way for the voicemail source application + * to convey its current state to the system. The columns and URIS for + * accessing this table are defined by the {@link Status} class. + * </li> + * </ul> + * + * <P> The minimum permission needed to access this content provider is + * {@link Manifest.permission#READ_WRITE_OWN_VOICEMAIL} + * * <P>Voicemails are inserted by what is called as a "voicemail source" * application, which is responsible for syncing voicemail data between a remote * server and the local voicemail content provider. "voicemail source" - * application should use the source specific {@link #CONTENT_URI_SOURCE} URI - * to insert and retrieve voicemails. + * application should always set the {@link #PARAM_KEY_SOURCE_PACKAGE} in the + * URI to identify its package. * * <P>In addition to the {@link ContentObserver} notifications the voicemail * provider also generates broadcast intents to notify change for applications @@ -43,9 +61,7 @@ import android.provider.CallLog.Calls; * made into the database, including new voicemail. * </li> * </ul> - * @hide */ -// TODO: unhide when the API is approved by android-api-council public class VoicemailContract { /** Not instantiable. */ private VoicemailContract() { @@ -59,18 +75,18 @@ public class VoicemailContract { */ public static final String PARAM_KEY_SOURCE_PACKAGE = "source_package"; - // TODO: Move ACTION_NEW_VOICEMAIL to the Intent class. /** Broadcast intent when a new voicemail record is inserted. */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL"; /** - * Extra included in {@value Intent#ACTION_PROVIDER_CHANGED} and - * {@value #ACTION_NEW_VOICEMAIL} broadcast intents to indicate if the receiving - * package made this change. + * Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the + * receiving package made this change. */ public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE"; /** * Name of the source package field, which must be same across all voicemail related tables. + * This is an internal field. * @hide */ public static final String SOURCE_PACKAGE_FIELD = "source_package"; @@ -85,9 +101,12 @@ public class VoicemailContract { public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/voicemail"); - /** The mime type for a collection of voicemails. */ + /** The MIME type for a collection of voicemails. */ public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails"; + /** The MIME type for a single voicemail. */ + public static final String ITEM_TYPE = "vnd.android.cursor.item/voicemail"; + /** * Phone number of the voicemail sender. * <P>Type: TEXT</P> @@ -109,17 +128,27 @@ public class VoicemailContract { */ public static final String NEW = Calls.NEW; /** - * The mail box state of the voicemail. + * The mail box state of the voicemail. This field is currently not used by the system. * <P> Possible values: {@link #STATE_INBOX}, {@link #STATE_DELETED}, * {@link #STATE_UNDELETED}. * <P>Type: INTEGER</P> + * @hide */ public static final String STATE = "state"; - /** Value of {@link #STATE} when the voicemail is in inbox. */ + /** + * Value of {@link #STATE} when the voicemail is in inbox. + * @hide + */ public static int STATE_INBOX = 0; - /** Value of {@link #STATE} when the voicemail has been marked as deleted. */ + /** + * Value of {@link #STATE} when the voicemail has been marked as deleted. + * @hide + */ public static int STATE_DELETED = 1; - /** Value of {@link #STATE} when the voicemail has marked as undeleted. */ + /** + * Value of {@link #STATE} when the voicemail has marked as undeleted. + * @hide + */ public static int STATE_UNDELETED = 2; /** * Package name of the source application that inserted the voicemail. @@ -166,9 +195,9 @@ public class VoicemailContract { public static final class Status implements BaseColumns { /** URI to insert/retrieve status of voicemail source. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/status"); - /** The mime type for a collection of voicemail source statuses. */ + /** The MIME type for a collection of voicemail source statuses. */ public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status"; - /** The mime type for a collection of voicemails. */ + /** The MIME type for a single voicemail source status entry. */ public static final String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status"; /** Not instantiable. */ @@ -201,10 +230,17 @@ public class VoicemailContract { * <P>Type: INTEGER</P> */ public static final String CONFIGURATION_STATE = "configuration_state"; + /** Value of {@link #CONFIGURATION_STATE} to indicate an all OK configuration status. */ public static final int CONFIGURATION_STATE_OK = 0; + /** + * Value of {@link #CONFIGURATION_STATE} to indicate the visual voicemail is not + * yet configured on this device. + */ public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; /** - * This state must be used when the source has verified that the current user can be + * Value of {@link #CONFIGURATION_STATE} to indicate the visual voicemail is not + * yet configured on this device but can be configured by the user. + * <p> This state must be used when the source has verified that the current user can be * upgraded to visual voicemail and would like to show a set up invitation message. */ public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; @@ -218,7 +254,14 @@ public class VoicemailContract { * <P>Type: INTEGER</P> */ public static final String DATA_CHANNEL_STATE = "data_channel_state"; + /** + * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel is working fine. + */ public static final int DATA_CHANNEL_STATE_OK = 0; + /** + * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel connection is not + * working. + */ public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; /** * The notification channel state of the voicemail source. This is the channel through which @@ -231,10 +274,20 @@ public class VoicemailContract { * <P>Type: INTEGER</P> */ public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state"; + /** + * Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that the notification channel is + * working fine. + */ public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; + /** + * Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that the notification channel + * connection is not working. + */ public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1; /** - * Use this state when the notification can only tell that there are pending messages on + * Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that there are messages waiting + * on the server but the details are not known. + * <p> Use this state when the notification can only tell that there are pending messages on * the server but no details of the sender/time etc are known. */ public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 2be5a49..5ab2024 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -118,6 +118,7 @@ public class Display { } else { // This is just for boot-strapping, initializing the // system process before the window manager is up. + outSize.x = getRealWidth(); outSize.y = getRealHeight(); } if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize); diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 9a2564f..b865b50 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -325,12 +325,15 @@ public abstract class HardwareRenderer { private static final int SURFACE_STATE_SUCCESS = 1; private static final int SURFACE_STATE_UPDATED = 2; - static EGLContext sEglContext; static EGL10 sEgl; static EGLDisplay sEglDisplay; static EGLConfig sEglConfig; + static final Object[] sEglLock = new Object[0]; - private static Thread sEglThread; + static final ThreadLocal<EGLContext> sEglContextStorage = new ThreadLocal<EGLContext>(); + + EGLContext mEglContext; + Thread mEglThread; EGLSurface mEglSurface; @@ -355,7 +358,7 @@ public abstract class HardwareRenderer { final boolean mTranslucent; private boolean mDestroyed; - + private final Rect mRedrawClip = new Rect(); GlRenderer(int glVersion, boolean translucent) { @@ -487,45 +490,48 @@ public abstract class HardwareRenderer { abstract GLES20Canvas createCanvas(); void initializeEgl() { - if (sEglContext != null) return; - - sEglThread = Thread.currentThread(); - sEgl = (EGL10) EGLContext.getEGL(); - - // Get to the default display. - sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - - if (sEglDisplay == EGL10.EGL_NO_DISPLAY) { - throw new RuntimeException("eglGetDisplay failed " - + getEGLErrorString(sEgl.eglGetError())); - } - - // We can now initialize EGL for that display - int[] version = new int[2]; - if (!sEgl.eglInitialize(sEglDisplay, version)) { - throw new RuntimeException("eglInitialize failed " + - getEGLErrorString(sEgl.eglGetError())); - } - - sEglConfig = chooseEglConfig(); - if (sEglConfig == null) { - // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without - if (sDirtyRegions) { - sDirtyRegions = false; + synchronized (sEglLock) { + if (sEgl == null && sEglConfig == null) { + sEgl = (EGL10) EGLContext.getEGL(); + + // Get to the default display. + sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + if (sEglDisplay == EGL10.EGL_NO_DISPLAY) { + throw new RuntimeException("eglGetDisplay failed " + + getEGLErrorString(sEgl.eglGetError())); + } + + // We can now initialize EGL for that display + int[] version = new int[2]; + if (!sEgl.eglInitialize(sEglDisplay, version)) { + throw new RuntimeException("eglInitialize failed " + + getEGLErrorString(sEgl.eglGetError())); + } + sEglConfig = chooseEglConfig(); if (sEglConfig == null) { - throw new RuntimeException("eglConfig not initialized"); + // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without + if (sDirtyRegions) { + sDirtyRegions = false; + sEglConfig = chooseEglConfig(); + if (sEglConfig == null) { + throw new RuntimeException("eglConfig not initialized"); + } + } else { + throw new RuntimeException("eglConfig not initialized"); + } } - } else { - throw new RuntimeException("eglConfig not initialized"); } } - - /* - * Create an EGL context. We want to do this as rarely as we can, because an - * EGL context is a somewhat heavy object. - */ - sEglContext = createContext(sEgl, sEglDisplay, sEglConfig); + + mEglContext = sEglContextStorage.get(); + mEglThread = Thread.currentThread(); + + if (mEglContext == null) { + mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); + sEglContextStorage.set(mEglContext); + } } private EGLConfig chooseEglConfig() { @@ -554,7 +560,7 @@ public abstract class HardwareRenderer { if (sEglConfig == null) { throw new RuntimeException("eglConfig not initialized"); } - if (Thread.currentThread() != sEglThread) { + if (Thread.currentThread() != mEglThread) { throw new IllegalStateException("HardwareRenderer cannot be used " + "from multiple threads"); } @@ -590,7 +596,7 @@ public abstract class HardwareRenderer { * Before we can issue GL commands, we need to make sure * the context is current and bound to a surface. */ - if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) { + if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { throw new Surface.OutOfResourcesException("eglMakeCurrent failed " + getEGLErrorString(sEgl.eglGetError())); } @@ -611,7 +617,7 @@ public abstract class HardwareRenderer { mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved(); } - return sEglContext.getGL(); + return mEglContext.getGL(); } EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { @@ -752,22 +758,22 @@ public abstract class HardwareRenderer { } /** - * Ensures the currnet EGL context is the one we expect. + * Ensures the current EGL context is the one we expect. * * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one */ private int checkCurrent() { - if (sEglThread != Thread.currentThread()) { + if (mEglThread != Thread.currentThread()) { throw new IllegalStateException("Hardware acceleration can only be used with a " + - "single UI thread.\nOriginal thread: " + sEglThread + "\n" + + "single UI thread.\nOriginal thread: " + mEglThread + "\n" + "Current thread: " + Thread.currentThread()); } - if (!sEglContext.equals(sEgl.eglGetCurrentContext()) || + if (!mEglContext.equals(sEgl.eglGetCurrentContext()) || !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { - if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) { + if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { fallback(true); Log.e(LOG_TAG, "eglMakeCurrent failed " + getEGLErrorString(sEgl.eglGetError())); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 59cb216..ff5fa7f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10317,6 +10317,26 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit } /** + * @hide + * @param offsetRequired + */ + protected int getFadeTop(boolean offsetRequired) { + int top = mPaddingTop; + if (offsetRequired) top += getTopPaddingOffset(); + return top; + } + + /** + * @hide + * @param offsetRequired + */ + protected int getFadeHeight(boolean offsetRequired) { + int padding = mPaddingTop; + if (offsetRequired) padding += getTopPaddingOffset(); + return mBottom - mTop - mPaddingBottom - padding; + } + + /** * <p>Indicates whether this view is attached to an hardware accelerated * window or not.</p> * @@ -10427,18 +10447,16 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit // Step 2, save the canvas' layers int paddingLeft = mPaddingLeft; - int paddingTop = mPaddingTop; final boolean offsetRequired = isPaddingOffsetRequired(); if (offsetRequired) { paddingLeft += getLeftPaddingOffset(); - paddingTop += getTopPaddingOffset(); } int left = mScrollX + paddingLeft; int right = left + mRight - mLeft - mPaddingRight - paddingLeft; - int top = mScrollY + paddingTop; - int bottom = top + mBottom - mTop - mPaddingBottom - paddingTop; + int top = mScrollY + getFadeTop(offsetRequired); + int bottom = top + getFadeHeight(offsetRequired); if (offsetRequired) { right += getRightPaddingOffset(); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index a6c158d..54fee3c 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -843,7 +843,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @param child * @param visibility */ - void onChildVisibilityChanged(View child, int visibility) { + protected void onChildVisibilityChanged(View child, int visibility) { if (mTransition != null) { if (visibility == VISIBLE) { mTransition.showChild(this, child); @@ -3964,7 +3964,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int left = mLeft; final int top = mTop; - if (dirty.intersect(0, 0, mRight - left, mBottom - top) || + if ((mGroupFlags & FLAG_CLIP_CHILDREN) != FLAG_CLIP_CHILDREN || + dirty.intersect(0, 0, mRight - left, mBottom - top) || (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) { mPrivateFlags &= ~DRAWING_CACHE_VALID; @@ -3982,8 +3983,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager location[CHILD_LEFT_INDEX] = mLeft; location[CHILD_TOP_INDEX] = mTop; - - dirty.set(0, 0, mRight - mLeft, mBottom - mTop); + if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { + dirty.set(0, 0, mRight - mLeft, mBottom - mTop); + } else { + // in case the dirty rect extends outside the bounds of this container + dirty.union(0, 0, mRight - mLeft, mBottom - mTop); + } if (mLayerType != LAYER_TYPE_NONE) { mLocalDirtyRect.union(dirty); diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 46fe407..5747fd3 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -775,6 +775,18 @@ public class GridLayout extends ViewGroup { invalidateStructure(); } + /** + * We need to call invalidateStructure() when a child's GONE flag changes state. + * This implementation is a catch-all, invalidating on any change in the visibility flags. + * + * @hide + */ + @Override + protected void onChildVisibilityChanged(View child, int visibility) { + super.onChildVisibilityChanged(child, visibility); + invalidateStructure(); + } + // Measurement private boolean isGone(View c) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 66a07d3..b116f0f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -117,12 +117,12 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.ViewRootImpl; import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; +import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -362,7 +362,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END; } - private boolean bResolvedDrawables = false; + private boolean mResolvedDrawables = false; /* * Kick-start the font cache for the zygote process (to pay the cost of @@ -3424,7 +3424,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mHint; } - private boolean isMultilineInputType(int type) { + private static boolean isMultilineInputType(int type) { return (type & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); } @@ -3500,7 +3500,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mTransformation instanceof PasswordTransformationMethod; } - private boolean isPasswordInputType(int inputType) { + private static boolean isPasswordInputType(int inputType) { final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION); return variation @@ -3511,7 +3511,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener == (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD); } - private boolean isVisiblePasswordInputType(int inputType) { + private static boolean isVisiblePasswordInputType(int inputType) { final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION); return variation @@ -5062,6 +5062,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getExtendedPaddingTop() + voffset + mLayout.getLineBaseline(0); } + /** + * @hide + * @param offsetRequired + */ + @Override + protected int getFadeTop(boolean offsetRequired) { + if (mLayout == null) return 0; + + int voffset = 0; + if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) { + voffset = getVerticalOffset(true); + } + + if (offsetRequired) voffset += getTopPaddingOffset(); + + return getExtendedPaddingTop() + voffset; + } + + /** + * @hide + * @param offsetRequired + */ + @Override + protected int getFadeHeight(boolean offsetRequired) { + return mLayout != null ? mLayout.getHeight() : 0; + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { int which = doKeyDown(keyCode, event, null); @@ -7592,7 +7619,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // mode (if any) as soon as this TextView is recycled. stopSelectionActionMode(); } - + @Override public void onFinishTemporaryDetach() { super.onFinishTemporaryDetach(); @@ -7600,7 +7627,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // usually because this instance is an editable field in a list if (!mDispatchTemporaryDetach) mTemporaryDetach = false; } - + @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { if (mTemporaryDetach) { @@ -9174,16 +9201,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Paste actions, depending on what this View supports. * * A custom implementation can add new entries in the default menu in its - * {@link ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The default actions - * can also be removed from the menu using {@link Menu#removeItem(int)} and passing - * {@link android.R.id#selectAll}, {@link android.R.id#cut}, {@link android.R.id#copy} or - * {@link android.R.id#paste} ids as parameters. + * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The + * default actions can also be removed from the menu using {@link Menu#removeItem(int)} and + * passing {@link android.R.id#selectAll}, {@link android.R.id#cut}, {@link android.R.id#copy} + * or {@link android.R.id#paste} ids as parameters. * - * Returning false from {@link ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will - * prevent the action mode from being started. + * Returning false from + * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent + * the action mode from being started. * * Action click events should be handled by the custom implementation of - * {@link ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}. + * {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}. * * Note that text selection mode is not started when a TextView receives focus and the * {@link android.R.attr#selectAllOnFocus} flag has been set. The content is highlighted in @@ -9739,9 +9767,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mLastParentX = mTempCoords[0]; mLastParentY = mTempCoords[1]; } - } - onHandleMoved(); + onHandleMoved(); + } if (isPositionVisible()) { mContainer.update(mContainerPositionX, mContainerPositionY, @@ -10184,7 +10212,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPreviousTapPositionX = x; mPreviousTapPositionY = y; - break; case MotionEvent.ACTION_POINTER_DOWN: @@ -10500,6 +10527,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mTextDir = TextDirectionHeuristics.RTL; break; } + } /** @@ -10511,7 +10539,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ protected void resolveDrawables() { // No need to resolve twice - if (bResolvedDrawables) { + if (mResolvedDrawables) { return; } // No drawable to resolve @@ -10520,7 +10548,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // No relative drawable to resolve if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) { - bResolvedDrawables = true; + mResolvedDrawables = true; return; } @@ -10557,11 +10585,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } break; } - bResolvedDrawables = true; + mResolvedDrawables = true; } protected void resetResolvedDrawables() { - bResolvedDrawables = false; + mResolvedDrawables = false; } @ViewDebug.ExportedProperty(category = "text") diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index f0a9441..95f1f98 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -76,7 +76,9 @@ public class ActionBarImpl extends ActionBar { private TabImpl mSelectedTab; private int mSavedTabPosition = INVALID_POSITION; - private ActionMode mActionMode; + ActionModeImpl mActionMode; + ActionMode mDeferredDestroyActionMode; + ActionMode.Callback mDeferredModeDestroyCallback; private boolean mLastMenuVisibility; private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = @@ -104,10 +106,12 @@ public class ActionBarImpl extends ActionBar { public void onAnimationEnd(Animator animation) { if (mContentView != null) { mContentView.setTranslationY(0); + mContainerView.setTranslationY(0); } mContainerView.setVisibility(View.GONE); mContainerView.setTransitioning(false); mCurrentShowAnim = null; + completeDeferredDestroyActionMode(); } }; @@ -207,6 +211,14 @@ public class ActionBarImpl extends ActionBar { mTabScrollView = tabScroller; } + void completeDeferredDestroyActionMode() { + if (mDeferredModeDestroyCallback != null) { + mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode); + mDeferredDestroyActionMode = null; + mDeferredModeDestroyCallback = null; + } + } + /** * Enables or disables animation between show/hide states. * If animation is disabled using this method, animations in progress @@ -357,14 +369,16 @@ public class ActionBarImpl extends ActionBar { } public ActionMode startActionMode(ActionMode.Callback callback) { + boolean wasHidden = false; if (mActionMode != null) { + wasHidden = mWasHiddenBeforeMode; mActionMode.finish(); } mContextView.killMode(); ActionModeImpl mode = new ActionModeImpl(callback); if (mode.dispatchOnCreate()) { - mWasHiddenBeforeMode = !isShowing(); + mWasHiddenBeforeMode = !isShowing() || wasHidden; mode.invalidate(); mContextView.initForMode(mode); animateToMode(true); @@ -577,7 +591,9 @@ public class ActionBarImpl extends ActionBar { } void animateToMode(boolean toActionMode) { - show(false); + if (toActionMode) { + show(false); + } if (mCurrentModeAnim != null) { mCurrentModeAnim.end(); } @@ -621,7 +637,16 @@ public class ActionBarImpl extends ActionBar { return; } - mCallback.onDestroyActionMode(this); + // If we were hidden before the mode was shown, defer the onDestroy + // callback until the animation is finished and associated relayout + // is about to happen. This lets apps better anticipate visibility + // and layout behavior. + if (mWasHiddenBeforeMode) { + mDeferredDestroyActionMode = this; + mDeferredModeDestroyCallback = mCallback; + } else { + mCallback.onDestroyActionMode(this); + } mCallback = null; animateToMode(false); diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java index c446cfb..59bef92 100644 --- a/core/java/com/android/server/NetworkManagementSocketTagger.java +++ b/core/java/com/android/server/NetworkManagementSocketTagger.java @@ -18,8 +18,8 @@ package com.android.server; import android.os.SystemProperties; import android.util.Log; - import dalvik.system.SocketTagger; +import libcore.io.IoUtils; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -28,8 +28,6 @@ import java.math.BigInteger; import java.net.SocketException; import java.nio.charset.Charsets; -import libcore.io.IoUtils; - /** * Assigns tags to sockets for traffic stats. */ @@ -59,6 +57,10 @@ public final class NetworkManagementSocketTagger extends SocketTagger { threadSocketTags.get().statsTag = tag; } + public static int getThreadSocketStatsTag() { + return threadSocketTags.get().statsTag; + } + public static void setThreadSocketStatsUid(int uid) { threadSocketTags.get().statsUid = uid; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 0397dfa..290f049 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -292,6 +292,23 @@ android:description="@string/permdesc_setAlarm" android:protectionLevel="normal" /> + <!-- Allows an application to read/write the voicemails owned by its own + package. --> + <permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:protectionLevel="dangerous" + android:label="@string/permlab_readWriteOwnVoicemail" + android:description="@string/permdesc_readWriteOwnVoicemail" /> + + <!-- Allows an application to read/write all voicemails. In order to be able + access all voicemails, this permission is needed in *addition* to + READ_WRITE_OWN_VOICEMAIL. --> + <permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:protectionLevel="signature" + android:label="@string/permlab_readWriteAllVoicemail" + android:description="@string/permdesc_readWriteAllVoicemail" /> + <!-- ======================================= --> <!-- Permissions for accessing location info --> <!-- ======================================= --> diff --git a/core/res/res/layout-sw600dp/preference_list_content.xml b/core/res/res/layout-sw600dp/preference_list_content.xml index a5320a7..5b67d71 100644 --- a/core/res/res/layout-sw600dp/preference_list_content.xml +++ b/core/res/res/layout-sw600dp/preference_list_content.xml @@ -46,7 +46,6 @@ android:layout_weight="1" android:paddingTop="16dp" android:paddingBottom="16dp" - android:drawSelectorOnTop="false" android:cacheColorHint="@android:color/transparent" android:listPreferredItemHeight="48dp" diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml index ec2313c..388eb38 100644 --- a/core/res/res/values-land/dimens.xml +++ b/core/res/res/values-land/dimens.xml @@ -25,8 +25,6 @@ <dimen name="password_keyboard_key_height_numeric">60dip</dimen> <!-- Default correction for the space key in the password keyboard --> <dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen> - <dimen name="preference_screen_side_margin">16dp</dimen> - <dimen name="preference_screen_side_margin_negative">-20dp</dimen> <dimen name="preference_widget_width">72dp</dimen> <!-- Default height of an action bar. --> diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml index 17bf561..553632b 100644 --- a/core/res/res/values-sw600dp/dimens.xml +++ b/core/res/res/values-sw600dp/dimens.xml @@ -45,6 +45,13 @@ <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen> <!-- Preference activity, vertical padding for the header list --> - <dimen name="reference_screen_header_vertical_padding">16dp</dimen> + <dimen name="preference_screen_header_vertical_padding">16dp</dimen> + + <!-- Reduce the margin when using dual pane --> + <!-- Preference activity side margins --> + <dimen name="preference_screen_side_margin">0dp</dimen> + <!-- Preference activity side margins negative--> + <dimen name="preference_screen_side_margin_negative">-4dp</dimen> + </resources> diff --git a/core/res/res/values-w1024dp/dimens.xml b/core/res/res/values-w1024dp/dimens.xml new file mode 100644 index 0000000..4d6a4da --- /dev/null +++ b/core/res/res/values-w1024dp/dimens.xml @@ -0,0 +1,23 @@ +<?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. +--> + +<resources> + <!-- Increase size (used to be 0 for dual pane --> + <!-- Preference activity side margins --> + <dimen name="preference_screen_side_margin">48dp</dimen> + <!-- Preference activity side margins negative--> + <dimen name="preference_screen_side_margin_negative">-52dp</dimen> +</resources> diff --git a/core/res/res/values-w1280dp/dimens.xml b/core/res/res/values-w1280dp/dimens.xml index e67b3a9..28aea55 100644 --- a/core/res/res/values-w1280dp/dimens.xml +++ b/core/res/res/values-w1280dp/dimens.xml @@ -18,6 +18,7 @@ --> <resources> <dimen name="preference_screen_side_margin">96dp</dimen> + <!-- Compensate for double margin : preference_screen_side_margin + 4 (frame background shadow) = -preference_screen_side_margin_negative --> <dimen name="preference_screen_side_margin_negative">-100dp</dimen> <dimen name="preference_widget_width">64dp</dimen> <!-- Preference fragment padding, bottom --> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d0361ca..082284a 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4913,6 +4913,10 @@ <attr name="minWidth"/> <!-- Minimum height of the AppWidget. --> <attr name="minHeight"/> + <!-- Minimum width that the AppWidget can be resized to. --> + <attr name="minResizeWidth" format="dimension"/> + <!-- Minimum height that the AppWidget can be resized to. --> + <attr name="minResizeHeight" format="dimension"/> <!-- Update period in milliseconds, or 0 if the AppWidget will update itself. --> <attr name="updatePeriodMillis" format="integer" /> <!-- A resource id of a layout. --> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 2ba4e66..0ed8076 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -67,9 +67,9 @@ <dimen name="multiwaveview_hit_radius">60dip</dimen> <!-- Preference activity side margins --> - <dimen name="preference_screen_side_margin">0dp</dimen> + <dimen name="preference_screen_side_margin">16dp</dimen> <!-- Preference activity side margins negative--> - <dimen name="preference_screen_side_margin_negative">0dp</dimen> + <dimen name="preference_screen_side_margin_negative">16dp</dimen> <!-- Preference activity top margin --> <dimen name="preference_screen_top_margin">0dp</dimen> <!-- Preference activity bottom margin --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index f464623..ba2a036 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1831,4 +1831,6 @@ <public type="color" name="holo_purple" /> <public type="color" name="holo_blue_bright" /> + <public type="attr" name="minResizeWidth" /> + <public type="attr" name="minResizeHeight" /> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d0e3f14..64f7316 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2152,6 +2152,22 @@ not implement this feature.</string> <!-- Title of an application permission, listed so the user can choose whether + they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permlab_readWriteOwnVoicemail">Access voicemails managed by this application</string> + <!-- Description of an application permission, listed so the user can choose whether + they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permdesc_readWriteOwnVoicemail">Allows the application to store and retrieve only + voicemails that its associated service can access.</string> + + <!-- Title of an application permission, listed so the user can choose whether + they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permlab_readWriteAllVoicemail">Access all voicemails</string> + <!-- Description of an application permission, listed so the user can choose whether + they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permdesc_readWriteAllVoicemail">Allows the application to store and retrieve all + voicemails that this device can access.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_writeGeolocationPermissions">Modify Browser geolocation permissions</string> <!-- Description of an application permission, listed so the user can choose whether diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java index 440aeb5..0b50af3 100644 --- a/core/tests/coretests/src/android/util/JsonReaderTest.java +++ b/core/tests/coretests/src/android/util/JsonReaderTest.java @@ -858,7 +858,7 @@ public final class JsonReaderTest extends TestCase { } public void testFailWithPosition() throws IOException { - testFailWithPosition("Expected literal value at line 6 column 3", + testFailWithPosition("Expected literal value at line 6 column 3", "[\n\n\n\n\n0,}]"); } diff --git a/data/fonts/DroidKufi-Bold.ttf b/data/fonts/DroidKufi-Bold.ttf Binary files differnew file mode 100644 index 0000000..650919e --- /dev/null +++ b/data/fonts/DroidKufi-Bold.ttf diff --git a/data/fonts/DroidKufi-Regular.ttf b/data/fonts/DroidKufi-Regular.ttf Binary files differnew file mode 100644 index 0000000..af85975 --- /dev/null +++ b/data/fonts/DroidKufi-Regular.ttf diff --git a/data/fonts/DroidNaskh-Bold.ttf b/data/fonts/DroidNaskh-Bold.ttf Binary files differnew file mode 100644 index 0000000..6b7d4f0 --- /dev/null +++ b/data/fonts/DroidNaskh-Bold.ttf diff --git a/data/fonts/DroidNaskh-Regular.ttf b/data/fonts/DroidNaskh-Regular.ttf Binary files differnew file mode 100644 index 0000000..d11e1ae --- /dev/null +++ b/data/fonts/DroidNaskh-Regular.ttf diff --git a/data/fonts/DroidSansArabic.ttf b/data/fonts/DroidSansArabic.ttf Binary files differdeleted file mode 100644 index bdefaac..0000000 --- a/data/fonts/DroidSansArabic.ttf +++ /dev/null diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml index c0d9153..6ac615d 100644 --- a/data/fonts/fallback_fonts.xml +++ b/data/fonts/fallback_fonts.xml @@ -25,7 +25,12 @@ <familyset> <family> <fileset> - <file>DroidSansArabic.ttf</file> + <file>DroidNaskh-Regular.ttf</file> + </fileset> + </family> + <family> + <fileset> + <file>DroidSansEthiopic-Regular.ttf</file> </fileset> </family> <family> diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk index 57a1bab..9a590bb 100644 --- a/data/fonts/fonts.mk +++ b/data/fonts/fonts.mk @@ -17,7 +17,8 @@ PRODUCT_COPY_FILES := \ frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \ frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \ - frameworks/base/data/fonts/DroidSansArabic.ttf:system/fonts/DroidSansArabic.ttf \ + frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \ + frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf \ frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \ frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \ frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \ diff --git a/docs/html/guide/practices/design/jni.jd b/docs/html/guide/practices/design/jni.jd index 3e9ddc4..39624f5 100644 --- a/docs/html/guide/practices/design/jni.jd +++ b/docs/html/guide/practices/design/jni.jd @@ -175,8 +175,8 @@ The global reference is guaranteed to be valid until you call <p>This pattern is commonly used when caching copies of class objects obtained from <code>FindClass</code>, e.g.:</p> -<pre>jclass* localClass = env->FindClass("MyClass"); -jclass* globalClass = (jclass*) env->NewGlobalRef(localClass);</pre> +<pre>jclass localClass = env->FindClass("MyClass"); +jclass globalClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass));</pre> <p>All JNI methods accept both local and global references as arguments. It's possible for references to the same object to have different values; @@ -215,10 +215,9 @@ to detach the thread soon.</p> <a name="UTF_8_and_UTF_16_strings" id="UTF_8_and_UTF_16_strings"></a> <h2>UTF-8 and UTF-16 Strings</h2> -<p>The Java programming language uses UTF-16. For convenience, JNI provides methods that work with "modified UTF-8" encoding -as well. (Some VMs use the modified UTF-8 internally to store strings; ours do not.) The -modified encoding only supports the 8- and 16-bit forms, and stores ASCII NUL values in a 16-bit encoding. -The nice thing about it is that you can count on having C-style zero-terminated strings, +<p>The Java programming language uses UTF-16. For convenience, JNI provides methods that work with <a href="http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8">Modified UTF-8</a> as well. The +modified encoding is useful for C code because it encodes \u0000 as 0xc0 0x80 instead of 0x00. +The nice thing about this is that you can count on having C-style zero-terminated strings, suitable for use with standard libc string functions. The down side is that you cannot pass arbitrary UTF-8 data into the VM and expect it to work correctly.</p> @@ -235,11 +234,11 @@ are C-style pointers to primitive data rather than local references. They are guaranteed valid until Release is called, which means they are not released when the native method returns.</p> -<p><strong>Data passed to NewStringUTF must be in "modified" UTF-8 format</strong>. A +<p><strong>Data passed to NewStringUTF must be in Modified UTF-8 format</strong>. A common mistake is reading character data from a file or network stream and handing it to <code>NewStringUTF</code> without filtering it. Unless you know the data is 7-bit ASCII, you need to strip out high-ASCII -characters or convert them to proper "modified" UTF-8 form. If you don't, +characters or convert them to proper Modified UTF-8 form. If you don't, the UTF-16 conversion will likely not be what you expect. The extended JNI checks will scan strings and warn you about invalid data, but they won't catch everything.</p> @@ -321,10 +320,10 @@ and <code>GetStringChars</code> that may be very helpful when all you want to do is copy data in or out. Consider the following:</p> <pre> - jbyte* data = env->GetByteArrayElements(array, NULL); + jbyte* data = env->GetByteArrayElements(array, NULL); if (data != NULL) { memcpy(buffer, data, len); - env->ReleaseByteArrayElements(array, data, JNI_ABORT); + env->ReleaseByteArrayElements(array, data, JNI_ABORT); }</pre> <p>This grabs the array, copies the first <code>len</code> byte @@ -335,7 +334,7 @@ we use <code>JNI_ABORT</code> so there's no chance of a third copy.</p> <p>We can accomplish the same thing with this:</p> <pre> - env->GetByteArrayRegion(array, 0, len, buffer);</pre> + env->GetByteArrayRegion(array, 0, len, buffer);</pre> <p>This has several advantages:</p> <ul> @@ -433,7 +432,7 @@ method call.</li> <li> Check for calls to inappropriate functions between Critical get/release calls.</li> <li> Check that JNIEnv structs aren't being shared between threads.</li> <li> Make sure local references aren't used outside their allowed lifespan.</li> -<li> UTF-8 strings contain only valid "modified UTF-8" data.</li> +<li> UTF-8 strings contain only valid <a href="http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8">Modified UTF-8</a> data.</li> </ul> <p>Accessibility of methods and fields (i.e. public vs. private) is not @@ -476,20 +475,21 @@ library name, e.g. to load "libfubar.so" you would pass in "fubar".</li> <li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code></li> <li>In <code>JNI_OnLoad</code>, register all of your native methods. You should declare -the methods "static" so the names don't take up space in the symbol table +the functions <code>static</code> so the names don't take up space in the symbol table on the device.</li> </ul> <p>The <code>JNI_OnLoad</code> function should look something like this if -written in C:</p> +written in C++:</p> <pre>jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { return -1; + } - /* get class with (*env)->FindClass */ - /* register methods with (*env)->RegisterNatives */ + // Get jclass with env->FindClass. + // Register methods with env->RegisterNatives. return JNI_VERSION_1_6; }</pre> @@ -603,7 +603,7 @@ Some common reasons for this are:</p> is commonly caused by: <ul> <li>For lazy method lookup, failing to declare C++ functions - with <code>extern C</code>. You can use <code>arm-eabi-nm</code> + with <code>extern "C"</code>. You can use <code>arm-eabi-nm</code> to see the symbols as they appear in the library; if they look mangled (e.g. <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code> rather than <code>Java_Foo_myfunc</code>) then you need to diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h index 5b5b731..e764425 100644 --- a/include/gui/ISurfaceTexture.h +++ b/include/gui/ISurfaceTexture.h @@ -78,7 +78,12 @@ protected: // client for this buffer. The timestamp is measured in nanoseconds, and // must be monotonically increasing. Its other properties (zero point, etc) // are client-dependent, and should be documented by the client. - virtual status_t queueBuffer(int slot, int64_t timestamp) = 0; + // + // outWidth, outHeight and outTransform are filed with the default width + // default height of the window and current transform applied to buffers, + // respectively. + virtual status_t queueBuffer(int slot, int64_t timestamp, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0; // cancelBuffer indicates that the client does not wish to fill in the // buffer associated with slot and transfers ownership of the slot back to @@ -87,6 +92,7 @@ protected: virtual status_t setCrop(const Rect& reg) = 0; virtual status_t setTransform(uint32_t transform) = 0; + virtual status_t setScalingMode(int mode) = 0; // getAllocator retrieves the binder object that must be referenced as long // as the GraphicBuffers dequeued from this ISurfaceTexture are referenced. diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 4080f27..945f4bc 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -84,10 +84,12 @@ public: // nanoseconds, and must be monotonically increasing. Its other semantics // (zero point, etc) are client-dependent and should be documented by the // client. - virtual status_t queueBuffer(int buf, int64_t timestamp); + virtual status_t queueBuffer(int buf, int64_t timestamp, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform); virtual void cancelBuffer(int buf); virtual status_t setCrop(const Rect& reg); virtual status_t setTransform(uint32_t transform); + virtual status_t setScalingMode(int mode); virtual int query(int what, int* value); @@ -185,6 +187,9 @@ public: // getCurrentTransform returns the transform of the current buffer uint32_t getCurrentTransform() const; + // getCurrentScalingMode returns the scaling mode of the current buffer + uint32_t getCurrentScalingMode() const; + // dump our state in a String void dump(String8& result) const; void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; @@ -220,6 +225,7 @@ private: mBufferState(BufferSlot::FREE), mRequestBufferCalled(false), mTransform(0), + mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0) { mCrop.makeInvalid(); } @@ -281,6 +287,11 @@ private: // slot. uint32_t mTransform; + // mScalingMode is the current scaling mode for this buffer slot. This + // gets set to mNextScalingMode each time queueBuffer gets called for + // this slot. + uint32_t mScalingMode; + // mTimestamp is the current timestamp for this buffer slot. This gets // to set by queueBuffer each time this slot is queued. int64_t mTimestamp; @@ -337,20 +348,24 @@ private: sp<GraphicBuffer> mCurrentTextureBuf; // mCurrentCrop is the crop rectangle that applies to the current texture. - // It gets set to mLastQueuedCrop each time updateTexImage is called. + // It gets set each time updateTexImage is called. Rect mCurrentCrop; // mCurrentTransform is the transform identifier for the current texture. It - // gets set to mLastQueuedTransform each time updateTexImage is called. + // gets set each time updateTexImage is called. uint32_t mCurrentTransform; + // mCurrentScalingMode is the scaling mode for the current texture. It gets + // set to each time updateTexImage is called. + uint32_t mCurrentScalingMode; + // mCurrentTransformMatrix is the transform matrix for the current texture. // It gets computed by computeTransformMatrix each time updateTexImage is // called. float mCurrentTransformMatrix[16]; // mCurrentTimestamp is the timestamp for the current texture. It - // gets set to mLastQueuedTimestamp each time updateTexImage is called. + // gets set each time updateTexImage is called. int64_t mCurrentTimestamp; // mNextCrop is the crop rectangle that will be used for the next buffer @@ -361,6 +376,10 @@ private: // buffer that gets queued. It is set by calling setTransform. uint32_t mNextTransform; + // mNextScalingMode is the scaling mode that will be used for the next + // buffers that get queued. It is set by calling setScalingMode. + int mNextScalingMode; + // mTexName is the name of the OpenGL texture to which streamed images will // be bound when updateTexImage is called. It is set at construction time // changed with a call to setTexName. diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index cfe2aa1..829d8ab 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -63,6 +63,7 @@ private: int dispatchSetBuffersGeometry(va_list args); int dispatchSetBuffersDimensions(va_list args); int dispatchSetBuffersFormat(va_list args); + int dispatchSetScalingMode(va_list args); int dispatchSetBuffersTransform(va_list args); int dispatchSetBuffersTimestamp(va_list args); int dispatchSetCrop(va_list args); @@ -84,6 +85,7 @@ protected: virtual int setBufferCount(int bufferCount); virtual int setBuffersDimensions(int w, int h); virtual int setBuffersFormat(int format); + virtual int setScalingMode(int mode); virtual int setBuffersTransform(int transform); virtual int setBuffersTimestamp(int64_t timestamp); virtual int setCrop(Rect const* rect); @@ -149,6 +151,18 @@ private: // dequeued format or to mReqFormat if no buffer was dequeued. uint32_t mQueryFormat; + // mDefaultWidth is default width of the window, regardless of the + // set_dimension call + uint32_t mDefaultWidth; + + // mDefaultHeight is default width of the window, regardless of the + // set_dimension call + uint32_t mDefaultHeight; + + // mTransformHint is the transform probably applied to buffers of this + // window. this is only a hint, actual transform may differ. + uint32_t mTransformHint; + // mMutex is the mutex used to prevent concurrent access to the member // variables of SurfaceTexture objects. It must be locked whenever the // member variables are accessed. diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index 41434a4..be90e2e 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -43,6 +43,7 @@ enum { SET_SYNCHRONOUS_MODE, CONNECT, DISCONNECT, + SET_SCALING_MODE, }; @@ -92,12 +93,16 @@ public: return result; } - virtual status_t queueBuffer(int buf, int64_t timestamp) { + virtual status_t queueBuffer(int buf, int64_t timestamp, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(buf); data.writeInt64(timestamp); remote()->transact(QUEUE_BUFFER, data, &reply); + *outWidth = reply.readInt32(); + *outHeight = reply.readInt32(); + *outTransform = reply.readInt32(); status_t result = reply.readInt32(); return result; } @@ -130,6 +135,15 @@ public: return result; } + virtual status_t setScalingMode(int mode) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(mode); + remote()->transact(SET_SCALING_MODE, data, &reply); + status_t result = reply.readInt32(); + return result; + } + virtual sp<IBinder> getAllocator() { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); @@ -216,7 +230,12 @@ status_t BnSurfaceTexture::onTransact( CHECK_INTERFACE(ISurfaceTexture, data, reply); int buf = data.readInt32(); int64_t timestamp = data.readInt64(); - status_t result = queueBuffer(buf, timestamp); + uint32_t outWidth, outHeight, outTransform; + status_t result = queueBuffer(buf, timestamp, + &outWidth, &outHeight, &outTransform); + reply->writeInt32(outWidth); + reply->writeInt32(outHeight); + reply->writeInt32(outTransform); reply->writeInt32(result); return NO_ERROR; } break; @@ -244,6 +263,13 @@ status_t BnSurfaceTexture::onTransact( reply->writeInt32(result); return NO_ERROR; } break; + case SET_SCALING_MODE: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int mode = data.readInt32(); + status_t result = setScalingMode(mode); + reply->writeInt32(result); + return NO_ERROR; + } break; case GET_ALLOCATOR: { CHECK_INTERFACE(ISurfaceTexture, data, reply); sp<IBinder> result = getAllocator(); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index a12d40a..0f08570 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -90,6 +90,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) : mCurrentTransform(0), mCurrentTimestamp(0), mNextTransform(0), + mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTexName(tex), mSynchronousMode(false), mAllowSynchronousMode(allowSynchronousMode), @@ -401,7 +402,8 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) { return err; } -status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { +status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { LOGV("SurfaceTexture::queueBuffer"); sp<FrameAvailableListener> listener; @@ -453,6 +455,7 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { mSlots[buf].mBufferState = BufferSlot::QUEUED; mSlots[buf].mCrop = mNextCrop; mSlots[buf].mTransform = mNextTransform; + mSlots[buf].mScalingMode = mNextScalingMode; mSlots[buf].mTimestamp = timestamp; mDequeueCondition.signal(); } // scope for the lock @@ -461,6 +464,11 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { if (listener != 0) { listener->onFrameAvailable(); } + + *outWidth = mDefaultWidth; + *outHeight = mDefaultHeight; + *outTransform = 0; + return OK; } @@ -542,6 +550,22 @@ status_t SurfaceTexture::disconnect(int api) { return err; } +status_t SurfaceTexture::setScalingMode(int mode) { + LOGV("SurfaceTexture::setScalingMode(%d)", mode); + + switch (mode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + break; + default: + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + mNextScalingMode = mode; + return OK; +} + status_t SurfaceTexture::updateTexImage() { LOGV("SurfaceTexture::updateTexImage"); Mutex::Autolock lock(mMutex); @@ -602,6 +626,7 @@ status_t SurfaceTexture::updateTexImage() { mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; mCurrentCrop = mSlots[buf].mCrop; mCurrentTransform = mSlots[buf].mTransform; + mCurrentScalingMode = mSlots[buf].mScalingMode; mCurrentTimestamp = mSlots[buf].mTimestamp; computeCurrentTransformMatrix(); @@ -809,6 +834,11 @@ uint32_t SurfaceTexture::getCurrentTransform() const { return mCurrentTransform; } +uint32_t SurfaceTexture::getCurrentScalingMode() const { + Mutex::Autolock lock(mMutex); + return mCurrentScalingMode; +} + int SurfaceTexture::query(int what, int* outValue) { Mutex::Autolock lock(mMutex); diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index d5b7c89..1dc6cd2 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -222,26 +222,38 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { if (i < 0) { return i; } - mSurfaceTexture->queueBuffer(i, timestamp); + mSurfaceTexture->queueBuffer(i, timestamp, + &mDefaultWidth, &mDefaultHeight, &mTransformHint); return OK; } int SurfaceTextureClient::query(int what, int* value) const { LOGV("SurfaceTextureClient::query"); - switch (what) { - case NATIVE_WINDOW_FORMAT: - if (mReqFormat) { - *value = mReqFormat; - return NO_ERROR; + { // scope for the lock + Mutex::Autolock lock(mMutex); + switch (what) { + case NATIVE_WINDOW_FORMAT: + if (mReqFormat) { + *value = mReqFormat; + return NO_ERROR; + } + break; + case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: + *value = 0; + return NO_ERROR; + case NATIVE_WINDOW_CONCRETE_TYPE: + *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_WIDTH: + *value = mDefaultWidth; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_HEIGHT: + *value = mDefaultHeight; + return NO_ERROR; + case NATIVE_WINDOW_TRANSFORM_HINT: + *value = mTransformHint; + return NO_ERROR; } - break; - case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: - // TODO: this is not needed anymore - *value = 0; - return NO_ERROR; - case NATIVE_WINDOW_CONCRETE_TYPE: - *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT; - return NO_ERROR; } return mSurfaceTexture->query(what, value); } @@ -286,6 +298,9 @@ int SurfaceTextureClient::perform(int operation, va_list args) case NATIVE_WINDOW_UNLOCK_AND_POST: res = dispatchUnlockAndPost(args); break; + case NATIVE_WINDOW_SET_SCALING_MODE: + res = dispatchSetScalingMode(args); + break; default: res = NAME_NOT_FOUND; break; @@ -340,6 +355,11 @@ int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) { return setBuffersFormat(f); } +int SurfaceTextureClient::dispatchSetScalingMode(va_list args) { + int m = va_arg(args, int); + return setScalingMode(m); +} + int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) { int transform = va_arg(args, int); return setBuffersTransform(transform); @@ -456,6 +476,18 @@ int SurfaceTextureClient::setBuffersFormat(int format) return NO_ERROR; } +int SurfaceTextureClient::setScalingMode(int mode) +{ + LOGV("SurfaceTextureClient::setScalingMode(%d)", mode); + Mutex::Autolock lock(mMutex); + // mode is validated on the server + status_t err = mSurfaceTexture->setScalingMode(mode); + LOGE_IF(err, "ISurfaceTexture::setScalingMode(%d) returned %s", + mode, strerror(-err)); + + return err; +} + int SurfaceTextureClient::setBuffersTransform(int transform) { LOGV("SurfaceTextureClient::setBuffersTransform"); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index a349121..85a9762 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -125,6 +125,7 @@ OpenGLRenderer::~OpenGLRenderer() { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setViewport(int width, int height) { + glDisable(GL_DITHER); glViewport(0, 0, width, height); mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); @@ -151,7 +152,6 @@ void OpenGLRenderer::prepareDirty(float left, float top, float right, float bott mSaveCount = 1; glViewport(0, 0, mWidth, mHeight); - glDisable(GL_DITHER); glEnable(GL_SCISSOR_TEST); glScissor(left, mSnapshot->height - bottom, right - left, bottom - top); diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index a8aa0c7..58d3e5c 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -128,7 +128,7 @@ LOCAL_SRC_FILES:= \ driver/rsdShaderCache.cpp \ driver/rsdVertexArray.cpp -LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc +LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc libbcinfo LOCAL_STATIC_LIBRARIES := libdex libft2 diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp index bbf2836..0c0aa10 100644 --- a/libs/rs/driver/rsdBcc.cpp +++ b/libs/rs/driver/rsdBcc.cpp @@ -19,6 +19,8 @@ #include "rsdBcc.h" #include "rsdRuntime.h" +#include <bcinfo/bcinfo.h> + #include "rsContext.h" #include "rsScriptC.h" @@ -38,22 +40,14 @@ struct DrvScript { BCCScriptRef mBccScript; - uint32_t mInvokeFunctionCount; + struct BCScriptMetadata *mScriptMetadata; + InvokeFunc_t *mInvokeFunctions; - uint32_t mFieldCount; void ** mFieldAddress; bool * mFieldIsObject; const uint8_t * mScriptText; uint32_t mScriptTextLength; - - //uint32_t * mObjectSlots; - //uint32_t mObjectSlotCount; - - uint32_t mPragmaCount; - const char ** mPragmaKeys; - const char ** mPragmaValues; - }; @@ -77,7 +71,7 @@ bool rsdScriptInit(const Context *rsc, pthread_mutex_lock(&rsdgInitMutex); char *cachePath = NULL; - uint32_t objectSlotCount = 0; + struct BCScriptMetadata *md = NULL; DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript)); if (drv == NULL) { @@ -90,6 +84,14 @@ bool rsdScriptInit(const Context *rsc, drv->mScriptText = bitcode; drv->mScriptTextLength = bitcodeSize; + md = bcinfoGetScriptMetadata((const char*)drv->mScriptText, + drv->mScriptTextLength, 0); + if (!md) { + LOGE("bcinfo: failed to read script metadata"); + goto error; + } + drv->mScriptMetadata = md; + //LOGE("mBccScript %p", script->mBccScript); if (bccRegisterSymbolCallback(drv->mBccScript, &rsdLookupRuntimeStub, script) != 0) { @@ -120,59 +122,42 @@ bool rsdScriptInit(const Context *rsc, drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root")); drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init")); - drv->mInvokeFunctionCount = bccGetExportFuncCount(drv->mBccScript); - if (drv->mInvokeFunctionCount <= 0) + if (md->exportFuncCount > 0) { + drv->mInvokeFunctions = (InvokeFunc_t*) calloc(md->exportFuncCount, + sizeof(InvokeFunc_t)); + bccGetExportFuncList(drv->mBccScript, + md->exportFuncCount, + (void **) drv->mInvokeFunctions); + } else { drv->mInvokeFunctions = NULL; - else { - drv->mInvokeFunctions = (InvokeFunc_t*) calloc(drv->mInvokeFunctionCount, sizeof(InvokeFunc_t)); - bccGetExportFuncList(drv->mBccScript, drv->mInvokeFunctionCount, (void **) drv->mInvokeFunctions); } - drv->mFieldCount = bccGetExportVarCount(drv->mBccScript); - if (drv->mFieldCount <= 0) { + if (md->exportVarCount > 0) { + drv->mFieldAddress = (void **) calloc(md->exportVarCount, + sizeof(void*)); + drv->mFieldIsObject = (bool *) calloc(md->exportVarCount, sizeof(bool)); + bccGetExportVarList(drv->mBccScript, + md->exportVarCount, + (void **) drv->mFieldAddress); + } else { drv->mFieldAddress = NULL; drv->mFieldIsObject = NULL; - } else { - drv->mFieldAddress = (void **) calloc(drv->mFieldCount, sizeof(void *)); - drv->mFieldIsObject = (bool *) calloc(drv->mFieldCount, sizeof(bool)); - bccGetExportVarList(drv->mBccScript, drv->mFieldCount, (void **) drv->mFieldAddress); } - objectSlotCount = bccGetObjectSlotCount(drv->mBccScript); - if (objectSlotCount) { - uint32_t * slots = new uint32_t[objectSlotCount]; - bccGetObjectSlotList(drv->mBccScript, objectSlotCount, slots); - for (uint32_t ct=0; ct < objectSlotCount; ct++) { - drv->mFieldIsObject[slots[ct]] = true; + if (md->objectSlotCount) { + for (uint32_t ct=0; ct < md->objectSlotCount; ct++) { + drv->mFieldIsObject[md->objectSlotList[ct]] = true; } - delete [] slots; } - uint32_t mPragmaCount; - const char ** mPragmaKeys; - const char ** mPragmaValues; - - drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript); - if (drv->mPragmaCount <= 0) { - drv->mPragmaKeys = NULL; - drv->mPragmaValues = NULL; - } else { - drv->mPragmaKeys = (const char **) calloc(drv->mPragmaCount, sizeof(const char *)); - drv->mPragmaValues = (const char **) calloc(drv->mPragmaCount, sizeof(const char *)); - bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues); - } - - - // Copy info over to runtime - script->mHal.info.exportedFunctionCount = drv->mInvokeFunctionCount; - script->mHal.info.exportedVariableCount = drv->mFieldCount; - script->mHal.info.exportedPragmaCount = drv->mPragmaCount; - script->mHal.info.exportedPragmaKeyList = drv->mPragmaKeys; - script->mHal.info.exportedPragmaValueList = drv->mPragmaValues; + script->mHal.info.exportedFunctionCount = md->exportFuncCount; + script->mHal.info.exportedVariableCount = md->exportVarCount; + script->mHal.info.exportedPragmaCount = md->pragmaCount; + script->mHal.info.exportedPragmaKeyList = md->pragmaKeyList; + script->mHal.info.exportedPragmaValueList = md->pragmaValueList; script->mHal.info.root = drv->mRoot; - pthread_mutex_unlock(&rsdgInitMutex); return true; @@ -460,9 +445,10 @@ void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slo void rsdScriptDestroy(const Context *dc, Script *script) { DrvScript *drv = (DrvScript *)script->mHal.drv; + struct BCScriptMetadata *md = drv->mScriptMetadata; if (drv->mFieldAddress) { - for (size_t ct=0; ct < drv->mFieldCount; ct++) { + for (size_t ct = 0; ct < md->exportVarCount; ct++) { if (drv->mFieldIsObject[ct]) { // The field address can be NULL if the script-side has // optimized the corresponding global variable away. @@ -471,18 +457,18 @@ void rsdScriptDestroy(const Context *dc, Script *script) { } } } - delete [] drv->mFieldAddress; - delete [] drv->mFieldIsObject; + free(drv->mFieldAddress); drv->mFieldAddress = NULL; - drv->mFieldIsObject = NULL; - drv->mFieldCount = 0; - } + free(drv->mFieldIsObject); + drv->mFieldIsObject = NULL; } if (drv->mInvokeFunctions) { - delete [] drv->mInvokeFunctions; + free(drv->mInvokeFunctions); drv->mInvokeFunctions = NULL; - drv->mInvokeFunctionCount = 0; } + + bcinfoReleaseScriptMetadata(&drv->mScriptMetadata); + free(drv); script->mHal.drv = NULL; diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 447a7ff..decd9f1 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -442,6 +442,7 @@ void Context::setSurface(uint32_t w, uint32_t h, RsNativeWindow sur) { if (mWidth && mHeight) { mStateVertex.updateSize(this); + mFBOCache.updateSize(); } } diff --git a/libs/rs/rsFBOCache.h b/libs/rs/rsFBOCache.h index f42e1f3..5d58ba4 100644 --- a/libs/rs/rsFBOCache.h +++ b/libs/rs/rsFBOCache.h @@ -38,6 +38,7 @@ public: void resetAll(Context *); void setup(Context *); + void updateSize() { mDirty = true; } struct Hal { mutable void *drv; diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 794747d..412552e 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -289,6 +289,18 @@ int FramebufferNativeWindow::query(const ANativeWindow* window, case NATIVE_WINDOW_CONCRETE_TYPE: *value = NATIVE_WINDOW_FRAMEBUFFER; return NO_ERROR; + case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: + *value = 0; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_WIDTH: + *value = fb->width; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_HEIGHT: + *value = fb->height; + return NO_ERROR; + case NATIVE_WINDOW_TRANSFORM_HINT: + *value = 0; + return NO_ERROR; } *value = 0; return BAD_VALUE; @@ -299,18 +311,38 @@ int FramebufferNativeWindow::perform(ANativeWindow* window, { switch (operation) { case NATIVE_WINDOW_SET_USAGE: - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + // TODO: we should implement this + return NO_ERROR; case NATIVE_WINDOW_CONNECT: + // TODO: we should implement this + return NO_ERROR; case NATIVE_WINDOW_DISCONNECT: - break; + // TODO: we should implement this + return NO_ERROR; case NATIVE_WINDOW_LOCK: return INVALID_OPERATION; case NATIVE_WINDOW_UNLOCK_AND_POST: return INVALID_OPERATION; - default: - return NAME_NOT_FOUND; + case NATIVE_WINDOW_SET_CROP: + return INVALID_OPERATION; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + // TODO: we should implement this + return INVALID_OPERATION; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + return INVALID_OPERATION; + case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: + return INVALID_OPERATION; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + return INVALID_OPERATION; + case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: + return INVALID_OPERATION; + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + // TODO: we should implement this + return NO_ERROR; + case NATIVE_WINDOW_SET_SCALING_MODE: + return INVALID_OPERATION; } - return NO_ERROR; + return NAME_NOT_FOUND; } // ---------------------------------------------------------------------------- diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 253010c..7258e11 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -297,6 +297,9 @@ public class AudioManager { */ public static final int RINGER_MODE_NORMAL = 2; + // maximum valid ringer mode value. Values must start from 0 and be contiguous. + private static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; + /** * Vibrate type that corresponds to the ringer. * @@ -540,6 +543,21 @@ public class AudioManager { } /** + * Checks valid ringer mode values. + * + * @return true if the ringer mode indicated is valid, false otherwise. + * + * @see #setRingerMode(int) + * @hide + */ + public static boolean isValidRingerMode(int ringerMode) { + if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { + return false; + } + return true; + } + + /** * Returns the maximum volume index for a particular stream. * * @param streamType The stream type whose maximum volume index is returned. @@ -601,6 +619,9 @@ public class AudioManager { * @see #getRingerMode() */ public void setRingerMode(int ringerMode) { + if (!isValidRingerMode(ringerMode)) { + return; + } IAudioService service = getService(); try { service.setRingerMode(ringerMode); diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index cdeb563..682560a 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -424,6 +424,12 @@ public class AudioService extends IAudioService.Stub { final ContentResolver cr = mContentResolver; mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); + // sanity check in case the settings are restored from a device with incompatible + // ringer modes + if (!AudioManager.isValidRingerMode(mRingerMode)) { + mRingerMode = AudioManager.RINGER_MODE_NORMAL; + System.putInt(cr, System.MODE_RINGER, mRingerMode); + } mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 178039c..ed6e3c7 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -84,6 +84,8 @@ void MediaPlayer::disconnect() if (p != 0) { p->disconnect(); } + + disconnectNativeWindow(); } // always call with lock held diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index d4d07b2..174ec92 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -445,6 +445,13 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { return err; } + err = native_window_set_scaling_mode(mNativeWindow.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + + if (err != OK) { + return err; + } + err = native_window_set_buffers_geometry( mNativeWindow.get(), def.format.video.nFrameWidth, diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp index b7c8e0c..1f7ee25 100644 --- a/media/libstagefright/ESDS.cpp +++ b/media/libstagefright/ESDS.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ESDS" +#include <utils/Log.h> + #include "include/ESDS.h" #include <string.h> @@ -87,6 +91,8 @@ status_t ESDS::skipDescriptorHeader( } while (more); + LOGV("tag=0x%02x data_size=%d", *tag, *data_size); + if (*data_size > size) { return ERROR_MALFORMED; } @@ -146,8 +152,20 @@ status_t ESDS::parseESDescriptor(size_t offset, size_t size) { if (OCRstreamFlag) { offset += 2; size -= 2; + + if ((offset >= size || mData[offset] != kTag_DecoderConfigDescriptor) + && offset - 2 < size + && mData[offset - 2] == kTag_DecoderConfigDescriptor) { + // Content found "in the wild" had OCRstreamFlag set but was + // missing OCR_ES_Id, the decoder config descriptor immediately + // followed instead. + offset -= 2; + size += 2; + + LOGW("Found malformed 'esds' atom, ignoring missing OCR_ES_Id."); + } } - + if (offset >= size) { return ERROR_MALFORMED; } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4f8336e..7bcbdcf 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1765,6 +1765,13 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { return err; } + err = native_window_set_scaling_mode(mNativeWindow.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + + if (err != OK) { + return err; + } + err = native_window_set_buffers_geometry( mNativeWindow.get(), def.format.video.nFrameWidth, diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index a4ca32d..3246021 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -93,6 +93,11 @@ SoftwareRenderer::SoftwareRenderer( GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP)); + CHECK_EQ(0, + native_window_set_scaling_mode( + mNativeWindow.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)); + // Width must be multiple of 32??? CHECK_EQ(0, native_window_set_buffers_geometry( mNativeWindow.get(), diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 73b3d5b..90d64ba 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -785,7 +785,10 @@ status_t LiveSession::decryptBuffer( keySource->setUID(mUID); } - status_t err = keySource->connect(keyURI.c_str()); + status_t err = + keySource->connect( + keyURI.c_str(), + mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); if (err == OK) { size_t offset = 0; diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 123fbf8..9df9f59 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -106,21 +106,38 @@ static bool MakeURL(const char *baseURL, const char *url, AString *out) { return true; } - size_t n = strlen(baseURL); - if (baseURL[n - 1] == '/') { - out->setTo(baseURL); - out->append(url); - } else { - const char *slashPos = strrchr(baseURL, '/'); + if (url[0] == '/') { + // URL is an absolute path. + + char *protocolEnd = strstr(baseURL, "//") + 2; + char *pathStart = strchr(protocolEnd, '/'); - if (slashPos > &baseURL[6]) { - out->setTo(baseURL, slashPos - baseURL); + if (pathStart != NULL) { + out->setTo(baseURL, pathStart - baseURL); } else { out->setTo(baseURL); } - out->append("/"); out->append(url); + } else { + // URL is a relative path + + size_t n = strlen(baseURL); + if (baseURL[n - 1] == '/') { + out->setTo(baseURL); + out->append(url); + } else { + const char *slashPos = strrchr(baseURL, '/'); + + if (slashPos > &baseURL[6]) { + out->setTo(baseURL, slashPos - baseURL); + } else { + out->setTo(baseURL); + } + + out->append("/"); + out->append(url); + } } LOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str()); diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp index 5c016c4..36fc9bf 100644 --- a/native/android/native_window.cpp +++ b/native/android/native_window.cpp @@ -76,7 +76,15 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window) { int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format) { - return native_window_set_buffers_geometry(window, width, height, format); + int32_t err = native_window_set_buffers_geometry(window, width, height, format); + if (!err) { + int mode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + if (width && height) { + mode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + } + err = native_window_set_scaling_mode(window, mode); + } + return err; } int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk new file mode 100644 index 0000000..bef1f90 --- /dev/null +++ b/opengl/tests/gl2_copyTexImage/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + gl2_copyTexImage.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libEGL \ + libGLESv2 \ + libui + +LOCAL_MODULE:= test-opengl-gl2_copyTexImage + +LOCAL_MODULE_TAGS := optional + +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES + +include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp new file mode 100644 index 0000000..c2bfdec --- /dev/null +++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <sched.h> +#include <sys/resource.h> + +#include <EGL/egl.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <utils/Timers.h> + +#include <ui/FramebufferNativeWindow.h> +#include <ui/EGLUtils.h> + +using namespace android; + +static void printGLString(const char *name, GLenum s) { + // fprintf(stderr, "printGLString %s, %d\n", name, s); + const char *v = (const char *) glGetString(s); + // int error = glGetError(); + // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, + // (unsigned int) v); + // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) + // fprintf(stderr, "GL %s = %s\n", name, v); + // else + // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); + fprintf(stderr, "GL %s = %s\n", name, v); +} + +static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { + if (returnVal != EGL_TRUE) { + fprintf(stderr, "%s() returned %d\n", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error + = eglGetError()) { + fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), + error); + } +} + +static void checkGlError(const char* op) { + for (GLint error = glGetError(); error; error + = glGetError()) { + fprintf(stderr, "after %s() glError (0x%x)\n", op, error); + } +} + +static const char gVertexShader[] = "attribute vec4 vPosition;\n" + "void main() {\n" + " gl_Position = vPosition;\n" + "}\n"; + +static const char gFragmentShader[] = "precision mediump float;\n" + "void main() {\n" + " gl_FragColor = vec4(0.0, 1.0, 0.0, 0.5);\n" + "}\n"; + +GLuint loadShader(GLenum shaderType, const char* pSource) { + GLuint shader = glCreateShader(shaderType); + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + fprintf(stderr, "Could not compile shader %d:\n%s\n", + shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } + return shader; +} + +GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + return 0; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + return 0; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + checkGlError("glAttachShader"); + glAttachShader(program, pixelShader); + checkGlError("glAttachShader"); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + fprintf(stderr, "Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + return program; +} + +GLuint gProgram; +GLuint gTextureProgram; +GLuint gvPositionHandle; +GLuint gvTexturePositionHandle; +GLuint gvTextureTexCoordsHandle; +GLuint gvTextureSamplerHandle; +GLuint gFbo; +GLuint gTexture; +GLuint gBufferTexture; + +static const char gSimpleVS[] = + "attribute vec4 position;\n" + "attribute vec2 texCoords;\n" + "varying vec2 outTexCoords;\n" + "\nvoid main(void) {\n" + " outTexCoords = texCoords;\n" + " gl_Position = position;\n" + "}\n\n"; +static const char gSimpleFS[] = + "precision mediump float;\n\n" + "varying vec2 outTexCoords;\n" + "uniform sampler2D texture;\n" + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(texture, outTexCoords);\n" + "}\n\n"; + +bool setupGraphics(int w, int h) { + gProgram = createProgram(gVertexShader, gFragmentShader); + if (!gProgram) { + return false; + } + gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); + checkGlError("glGetAttribLocation"); + fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); + + gTextureProgram = createProgram(gSimpleVS, gSimpleFS); + if (!gTextureProgram) { + return false; + } + gvTexturePositionHandle = glGetAttribLocation(gTextureProgram, "position"); + checkGlError("glGetAttribLocation"); + gvTextureTexCoordsHandle = glGetAttribLocation(gTextureProgram, "texCoords"); + checkGlError("glGetAttribLocation"); + gvTextureSamplerHandle = glGetUniformLocation(gTextureProgram, "texture"); + checkGlError("glGetAttribLocation"); + + glActiveTexture(GL_TEXTURE0); + + glGenTextures(1, &gTexture); + glBindTexture(GL_TEXTURE_2D, gTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glGenTextures(1, &gBufferTexture); + glBindTexture(GL_TEXTURE_2D, gBufferTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glGenFramebuffers(1, &gFbo); + glBindFramebuffer(GL_FRAMEBUFFER, gFbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gTexture, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, w, h); + checkGlError("glViewport"); + return true; +} + +const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, + 0.5f, -0.5f }; + +const GLint FLOAT_SIZE_BYTES = 4; +const GLint TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; +const GLfloat gTriangleVerticesData[] = { + // X, Y, Z, U, V + -1.0f, -1.0f, 0, 0.f, 0.f, + 1.0f, -1.0f, 0, 1.f, 0.f, + -1.0f, 1.0f, 0, 0.f, 1.f, + 1.0f, 1.0f, 0, 1.f, 1.f, +}; + +void renderFrame(GLint w, GLint h) { + glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + checkGlError("glClearColor"); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + checkGlError("glClear"); + + // Bind FBO and draw into it + glBindFramebuffer(GL_FRAMEBUFFER, gFbo); + checkGlError("glBindFramebuffer"); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + checkGlError("glClearColor"); + glClear(GL_COLOR_BUFFER_BIT); + checkGlError("glClear"); + + glUseProgram(gProgram); + checkGlError("glUseProgram"); + + glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); + checkGlError("glVertexAttribPointer"); + glEnableVertexAttribArray(gvPositionHandle); + checkGlError("glEnableVertexAttribArray"); + glDrawArrays(GL_TRIANGLES, 0, 3); + checkGlError("glDrawArrays"); + + // Copy content of FBO into a texture + glBindTexture(GL_TEXTURE_2D, gBufferTexture); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w / 2, h / 2); + checkGlError("glCopyTexSubImage2D"); + + // Back to the display + glBindFramebuffer(GL_FRAMEBUFFER, 0); + checkGlError("glBindFramebuffer"); + + // Draw copied content on the screen + glUseProgram(gTextureProgram); + checkGlError("glUseProgram"); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE, + TRIANGLE_VERTICES_DATA_STRIDE_BYTES, gTriangleVerticesData); + checkGlError("glVertexAttribPointer"); + glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE, + TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &gTriangleVerticesData[3]); + checkGlError("glVertexAttribPointer"); + glEnableVertexAttribArray(gvTexturePositionHandle); + glEnableVertexAttribArray(gvTextureTexCoordsHandle); + checkGlError("glEnableVertexAttribArray"); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + checkGlError("glDrawArrays"); +} + +void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { + +#define X(VAL) {VAL, #VAL} + struct {EGLint attribute; const char* name;} names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + printf(" %s: ", names[j].name); + printf("%d (0x%x)", value, value); + } + } + printf("\n"); +} + +int printEGLConfigurations(EGLDisplay dpy) { + EGLint numConfig = 0; + EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); + checkEglError("eglGetConfigs", returnVal); + if (!returnVal) { + return false; + } + + printf("Number of EGL configuration: %d\n", numConfig); + + EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig); + if (! configs) { + printf("Could not allocate configs.\n"); + return false; + } + + returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig); + checkEglError("eglGetConfigs", returnVal); + if (!returnVal) { + free(configs); + return false; + } + + for(int i = 0; i < numConfig; i++) { + printf("Configuration %d\n", i); + printEGLConfiguration(dpy, configs[i]); + } + + free(configs); + return true; +} + +int main(int argc, char** argv) { + EGLBoolean returnValue; + EGLConfig myConfig = {0}; + + EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + EGLint s_configAttribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_NONE }; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint w, h; + + EGLDisplay dpy; + + checkEglError("<init>"); + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + checkEglError("eglGetDisplay"); + if (dpy == EGL_NO_DISPLAY) { + printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); + return 0; + } + + returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); + checkEglError("eglInitialize", returnValue); + fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); + if (returnValue != EGL_TRUE) { + printf("eglInitialize failed\n"); + return 0; + } + + if (!printEGLConfigurations(dpy)) { + printf("printEGLConfigurations failed\n"); + return 0; + } + + checkEglError("printEGLConfigurations"); + + EGLNativeWindowType window = android_createDisplaySurface(); + EGLint numConfigs = -1, n = 0; + eglChooseConfig(dpy, s_configAttribs, 0, 0, &numConfigs); + if (numConfigs) { + EGLConfig* const configs = new EGLConfig[numConfigs]; + eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n); + myConfig = configs[0]; + delete[] configs; + } + + checkEglError("EGLUtils::selectConfigForNativeWindow"); + + printf("Chose this configuration:\n"); + printEGLConfiguration(dpy, myConfig); + + surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); + checkEglError("eglCreateWindowSurface"); + if (surface == EGL_NO_SURFACE) { + printf("gelCreateWindowSurface failed.\n"); + return 0; + } + + context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); + checkEglError("eglCreateContext"); + if (context == EGL_NO_CONTEXT) { + printf("eglCreateContext failed\n"); + return 0; + } + returnValue = eglMakeCurrent(dpy, surface, surface, context); + checkEglError("eglMakeCurrent", returnValue); + if (returnValue != EGL_TRUE) { + return 0; + } + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + checkEglError("eglQuerySurface"); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + checkEglError("eglQuerySurface"); + GLint dim = w < h ? w : h; + + fprintf(stderr, "Window dimensions: %d x %d\n", w, h); + + printGLString("Version", GL_VERSION); + printGLString("Vendor", GL_VENDOR); + printGLString("Renderer", GL_RENDERER); + printGLString("Extensions", GL_EXTENSIONS); + + if(!setupGraphics(w, h)) { + fprintf(stderr, "Could not set up graphics.\n"); + return 0; + } + + for (;;) { + renderFrame(w, h); + eglSwapBuffers(dpy, surface); + checkEglError("eglSwapBuffers"); + } + + return 0; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java index 981fb24..b4d2a14 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java @@ -236,6 +236,7 @@ public class NotificationRowLayout extends ViewGroup { @Override public void onAnimationEnd(Animator animation) { mAppearingViews.remove(childF); + requestLayout(); // pick up any final changes in position } }); a.start(); @@ -274,6 +275,7 @@ public class NotificationRowLayout extends ViewGroup { NotificationRowLayout.super.removeView(childF); childF.setAlpha(1f); mDisappearingViews.remove(childF); + requestLayout(); // pick up any final changes in position } }); @@ -372,7 +374,7 @@ public class NotificationRowLayout extends ViewGroup { final int width = right - left; final int height = bottom - top; - //if (DEBUG) Slog.d(TAG, "onLayout: height=" + height); + if (DEBUG) Slog.d(TAG, "onLayout: height=" + height); final int count = getChildCount(); int y = 0; @@ -381,20 +383,22 @@ public class NotificationRowLayout extends ViewGroup { if (child.getVisibility() == GONE) { continue; } -// final int thisRowHeight = (int)( -// ((mAppearingViews.contains(child) || mDisappearingViews.contains(child)) -// ? child.getScaleY() -// : 1.0f) -// * mRowHeight); final int thisRowHeight = (int)(child.getAlpha() * mRowHeight); -// child.layout(0, y, width, y + thisRowHeight); - child.layout(0, y, width, y + mRowHeight); + if (DEBUG) { + Slog.d(TAG, String.format( + "laying out child #%d: (0, %d, %d, %d) h=%d", + i, y, width, y + thisRowHeight, thisRowHeight)); + } + child.layout(0, y, width, y + thisRowHeight); y += thisRowHeight; } + if (DEBUG) { + Slog.d(TAG, "onLayout: final y=" + y); + } } public void setForcedHeight(int h) { - //if (DEBUG) Slog.d(TAG, "forcedHeight: " + h); + if (DEBUG) Slog.d(TAG, "forcedHeight: " + h); if (h != mHeight) { mHeight = h; requestLayout(); diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 0eff776..96b26e7 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -458,6 +458,17 @@ status_t CameraService::Client::connect(const sp<ICameraClient>& client) { return NO_ERROR; } +static void disconnectWindow(const sp<ANativeWindow>& window) { + if (window != 0) { + status_t result = native_window_disconnect(window.get(), + NATIVE_WINDOW_API_CAMERA); + if (result != NO_ERROR) { + LOGW("native_window_disconnect failed: %s (%d)", strerror(-result), + result); + } + } +} + void CameraService::Client::disconnect() { int callingPid = getCallingPid(); LOG1("disconnect E (pid %d)", callingPid); @@ -489,6 +500,7 @@ void CameraService::Client::disconnect() { // Release the held ANativeWindow resources. if (mPreviewWindow != 0) { + disconnectWindow(mPreviewWindow); mPreviewWindow = 0; mHardware->setPreviewWindow(mPreviewWindow); } @@ -502,17 +514,6 @@ void CameraService::Client::disconnect() { // ---------------------------------------------------------------------------- -static void disconnectWindow(const sp<ANativeWindow>& window) { - if (window != 0) { - status_t result = native_window_disconnect(window.get(), - NATIVE_WINDOW_API_CAMERA); - if (result != NO_ERROR) { - LOGW("native_window_disconnect failed: %s (%d)", strerror(-result), - result); - } - } -} - status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder, const sp<ANativeWindow>& window) { Mutex::Autolock lock(mLock); @@ -536,6 +537,8 @@ status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder, // If preview has been already started, register preview buffers now. if (mHardware->previewEnabled()) { if (window != 0) { + native_window_set_scaling_mode(window.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); native_window_set_buffers_transform(window.get(), mOrientation); result = mHardware->setPreviewWindow(window); } @@ -642,6 +645,8 @@ status_t CameraService::Client::startPreviewMode() { } if (mPreviewWindow != 0) { + native_window_set_scaling_mode(mPreviewWindow.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); native_window_set_buffers_transform(mPreviewWindow.get(), mOrientation); } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 0b15221..438883e 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -1022,6 +1022,12 @@ class AppWidgetService extends IAppWidgetService.Stub info.minWidth = value != null ? value.data : 0; value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); info.minHeight = value != null ? value.data : 0; + value = sa.peekValue( + com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth); + info.minResizeWidth = value != null ? value.data : info.minWidth; + value = sa.peekValue( + com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight); + info.minResizeHeight = value != null ? value.data : info.minHeight; info.updatePeriodMillis = sa.getInt( com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 55c92e8..b78424b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -248,7 +248,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // list of DeathRecipients used to make sure features are turned off when // a process dies - private List mFeatureUsers; + private List<FeatureUser> mFeatureUsers; private boolean mSystemReady; private Intent mInitialBroadcast; @@ -436,7 +436,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[i] = new ArrayList(); } - mFeatureUsers = new ArrayList(); + mFeatureUsers = new ArrayList<FeatureUser>(); mNumDnsEntries = 0; @@ -484,6 +484,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { continue; } mCurrentLinkProperties[netType] = null; + if (mNetConfigs[netType].isDefault()) mNetTrackers[netType].reconnect(); } IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); @@ -794,6 +795,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { stopUsingNetworkFeature(this, false); } + public boolean isSameUser(FeatureUser u) { + if (u == null) return false; + + return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature); + } + + public boolean isSameUser(int pid, int uid, int networkType, String feature) { + if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) && + TextUtils.equals(mFeature, feature)) { + return true; + } + return false; + } + public String toString() { return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + (System.currentTimeMillis() - mCreateTime) + " mSec ago"; @@ -844,16 +859,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType); + synchronized(this) { - mFeatureUsers.add(f); + boolean addToList = true; + if (restoreTimer < 0) { + // In case there is no timer is specified for the feature, + // make sure we don't add duplicate entry with the same request. + for (FeatureUser u : mFeatureUsers) { + if (u.isSameUser(f)) { + // Duplicate user is found. Do not add. + addToList = false; + break; + } + } + } + + if (addToList) mFeatureUsers.add(f); if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { // this gets used for per-pid dns when connected mNetRequestersPids[usedNetworkType].add(currentPid); } } - int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType); - if (restoreTimer >= 0) { mHandler.sendMessageDelayed( mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer); @@ -903,11 +931,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean found = false; synchronized(this) { - for (int i = 0; i < mFeatureUsers.size() ; i++) { - u = (FeatureUser)mFeatureUsers.get(i); - if (uid == u.mUid && pid == u.mPid && - networkType == u.mNetworkType && - TextUtils.equals(feature, u.mFeature)) { + for (FeatureUser x : mFeatureUsers) { + if (x.isSameUser(pid, uid, networkType, feature)) { + u = x; found = true; break; } @@ -959,11 +985,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // do not pay attention to duplicate requests - in effect the // API does not refcount and a single stop will counter multiple starts. if (ignoreDups == false) { - for (int i = 0; i < mFeatureUsers.size() ; i++) { - FeatureUser x = (FeatureUser)mFeatureUsers.get(i); - if (x.mUid == u.mUid && x.mPid == u.mPid && - x.mNetworkType == u.mNetworkType && - TextUtils.equals(x.mFeature, u.mFeature)) { + for (FeatureUser x : mFeatureUsers) { + if (x.isSameUser(u)) { if (DBG) log("ignoring stopUsingNetworkFeature as dup is found"); return 1; } diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java index bdb5a24..86f57d1 100644 --- a/services/java/com/android/server/MasterClearReceiver.java +++ b/services/java/com/android/server/MasterClearReceiver.java @@ -43,11 +43,7 @@ public class MasterClearReceiver extends BroadcastReceiver { @Override public void run() { try { - if (intent.hasExtra("enableEFS")) { - RecoverySystem.rebootToggleEFS(context, intent.getBooleanExtra("enableEFS", false)); - } else { - RecoverySystem.rebootWipeUserData(context); - } + RecoverySystem.rebootWipeUserData(context); Log.wtf(TAG, "Still running after master clear?!"); } catch (IOException e) { Slog.e(TAG, "Can't perform master clear/factory reset", e); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 94af46d..0924b86 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2439,7 +2439,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.mayFreezeScreenLocked(r.app) ? r : null); if (config != null) { r.frozenBeforeDestroy = true; - if (!updateConfigurationLocked(config, r)) { + if (!updateConfigurationLocked(config, r, false)) { mMainStack.resumeTopActivityLocked(null); } } @@ -12398,6 +12398,22 @@ public final class ActivityManagerService extends ActivityManagerNative return ci; } + public void updatePersistentConfiguration(Configuration values) { + enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, + "updateConfiguration()"); + enforceCallingPermission(android.Manifest.permission.WRITE_SETTINGS, + "updateConfiguration()"); + if (values == null) { + throw new NullPointerException("Configuration must not be null"); + } + + synchronized(this) { + final long origId = Binder.clearCallingIdentity(); + updateConfigurationLocked(values, null, true); + Binder.restoreCallingIdentity(origId); + } + } + public void updateConfiguration(Configuration values) { enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); @@ -12409,7 +12425,10 @@ public final class ActivityManagerService extends ActivityManagerNative } final long origId = Binder.clearCallingIdentity(); - updateConfigurationLocked(values, null); + if (values != null) { + Settings.System.clearConfiguration(values); + } + updateConfigurationLocked(values, null, false); Binder.restoreCallingIdentity(origId); } } @@ -12420,9 +12439,10 @@ public final class ActivityManagerService extends ActivityManagerNative * configuration. Returns true if the activity has been left running, or * false if <var>starting</var> is being destroyed to match the new * configuration. + * @param persistent TODO */ public boolean updateConfigurationLocked(Configuration values, - ActivityRecord starting) { + ActivityRecord starting, boolean persistent) { int changes = 0; boolean kept = true; @@ -12465,7 +12485,7 @@ public final class ActivityManagerService extends ActivityManagerNative // code is executed. mSystemThread.applyConfigurationToResources(newConfig); - if (Settings.System.hasInterestingConfigurationChanges(changes)) { + if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) { Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG); msg.obj = new Configuration(mConfiguration); mHandler.sendMessage(msg); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 93d8164..0d89081 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -518,7 +518,7 @@ final class ActivityStack { Configuration config = mService.mWindowManager.updateOrientationFromAppTokens( mService.mConfiguration, r.mayFreezeScreenLocked(app) ? r : null); - mService.updateConfigurationLocked(config, r); + mService.updateConfigurationLocked(config, r, false); } r.app = app; @@ -1424,7 +1424,7 @@ final class ActivityStack { if (config != null) { next.frozenBeforeDestroy = true; } - updated = mService.updateConfigurationLocked(config, next); + updated = mService.updateConfigurationLocked(config, next, false); } } if (!updated) { @@ -2817,7 +2817,7 @@ final class ActivityStack { mConfigWillChange = false; if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating to new configuration after starting activity."); - mService.updateConfigurationLocked(config, null); + mService.updateConfigurationLocked(config, null, false); } Binder.restoreCallingIdentity(origId); diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 5ed7988..f270003 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -1093,8 +1093,7 @@ final class Settings { serializer.attribute(null, "uidError", "true"); } if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, "enabled", - pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED ? "true" : "false"); + serializer.attribute(null, "enabled", Integer.toString(pkg.enabled)); } if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) { serializer.attribute(null, "installStatus", "false"); @@ -1644,17 +1643,21 @@ final class Settings { packageSetting.nativeLibraryPathString = nativeLibraryPathStr; final String enabledStr = parser.getAttributeValue(null, "enabled"); if (enabledStr != null) { - if (enabledStr.equalsIgnoreCase("true")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED; - } else if (enabledStr.equalsIgnoreCase("false")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED; - } else if (enabledStr.equalsIgnoreCase("default")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; - } else { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " + name - + " has bad enabled value: " + idStr + " at " - + parser.getPositionDescription()); + try { + packageSetting.enabled = Integer.parseInt(enabledStr); + } catch (NumberFormatException e) { + if (enabledStr.equalsIgnoreCase("true")) { + packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED; + } else if (enabledStr.equalsIgnoreCase("false")) { + packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED; + } else if (enabledStr.equalsIgnoreCase("default")) { + packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: package " + name + + " has bad enabled value: " + idStr + " at " + + parser.getPositionDescription()); + } } } else { packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f3b6c4d..e0268fa 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -44,10 +44,6 @@ namespace android { -template <typename T> inline T min(T a, T b) { - return a<b ? a : b; -} - // --------------------------------------------------------------------------- Layer::Layer(SurfaceFlinger* flinger, @@ -56,14 +52,14 @@ Layer::Layer(SurfaceFlinger* flinger, mTextureName(-1U), mQueuedFrames(0), mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentOpacity(true), mFormat(PIXEL_FORMAT_NONE), mGLExtensions(GLExtensions::getInstance()), mOpaqueLayer(true), mNeedsDithering(false), mSecure(false), - mProtectedByApp(false), - mFixedSize(false) + mProtectedByApp(false) { mCurrentCrop.makeInvalid(); glGenTextures(1, &mTextureName); @@ -400,14 +396,7 @@ uint32_t Layer::doTransaction(uint32_t flags) } bool Layer::isFixedSize() const { - Mutex::Autolock _l(mLock); - return mFixedSize; -} - -void Layer::setFixedSize(bool fixedSize) -{ - Mutex::Autolock _l(mLock); - mFixedSize = fixedSize; + return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; } bool Layer::isCropped() const { @@ -437,9 +426,14 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) const Rect crop(mSurfaceTexture->getCurrentCrop()); const uint32_t transform(mSurfaceTexture->getCurrentTransform()); - if ((crop != mCurrentCrop) || (transform != mCurrentTransform)) { + const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode()); + if ((crop != mCurrentCrop) || + (transform != mCurrentTransform) || + (scalingMode != mCurrentScalingMode)) + { mCurrentCrop = crop; mCurrentTransform = transform; + mCurrentScalingMode = scalingMode; mFlinger->invalidateHwcGeometry(); } @@ -459,13 +453,22 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // FIXME: mPostedDirtyRegion = dirty & bounds mPostedDirtyRegion.set(front.w, front.h); - sp<GraphicBuffer> newFrontBuffer(mActiveBuffer); - if ((newFrontBuffer->getWidth() == front.requested_w && - newFrontBuffer->getHeight() == front.requested_h) || - isFixedSize()) + + if ((front.w != front.requested_w) || + (front.h != front.requested_h)) { - if ((front.w != front.requested_w) || - (front.h != front.requested_h)) + // check that we received a buffer of the right size + // (Take the buffer's orientation into account) + sp<GraphicBuffer> newFrontBuffer(mActiveBuffer); + uint32_t bufWidth = newFrontBuffer->getWidth(); + uint32_t bufHeight = newFrontBuffer->getHeight(); + if (mCurrentTransform & Transform::ROT_90) { + swap(bufWidth, bufHeight); + } + + if (isFixedSize() || + (bufWidth == front.requested_w && + bufHeight == front.requested_h)) { // Here we pretend the transaction happened by updating the // current and drawing states. Drawing state is only accessed @@ -485,10 +488,10 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // recompute visible region recomputeVisibleRegions = true; - } - // we now have the correct size, unfreeze the screen - mFreezeLock.clear(); + // we now have the correct size, unfreeze the screen + mFreezeLock.clear(); + } } } } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e3fc13d..ddfc666 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -59,7 +59,6 @@ public: status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags=0); - // Set this Layer's buffers size bool isFixedSize() const; // LayerBase interface @@ -88,7 +87,6 @@ private: void onFrameQueued(); virtual sp<ISurface> createSurface(); uint32_t getEffectiveUsage(uint32_t usage) const; - void setFixedSize(bool fixedSize); bool isCropped() const; static bool getOpacityForFormat(uint32_t format); @@ -106,6 +104,7 @@ private: GLfloat mTextureMatrix[16]; Rect mCurrentCrop; uint32_t mCurrentTransform; + uint32_t mCurrentScalingMode; bool mCurrentOpacity; // constants @@ -124,7 +123,6 @@ private: // binder thread, transaction thread mutable Mutex mLock; - bool mFixedSize; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index 60fa965..11f61cc 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -52,6 +52,20 @@ status_t SurfaceTextureLayer::setBufferCount(int bufferCount) { return res; } +status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { + + status_t res = SurfaceTexture::queueBuffer(buf, timestamp, + outWidth, outHeight, outTransform); + + sp<Layer> layer(mLayer.promote()); + if (layer != NULL) { + *outTransform = layer->getOrientation(); + } + + return res; +} + status_t SurfaceTextureLayer::dequeueBuffer(int *buf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { @@ -64,9 +78,6 @@ status_t SurfaceTextureLayer::dequeueBuffer(int *buf, //LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x", // __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage); res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage); - if (res == NO_ERROR) { - layer->setFixedSize(w && h); - } } return res; } diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h index 7faff54..29a9cbe 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.h +++ b/services/surfaceflinger/SurfaceTextureLayer.h @@ -45,6 +45,9 @@ public: virtual status_t setBufferCount(int bufferCount); protected: + virtual status_t queueBuffer(int buf, int64_t timestamp, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform); + virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage); }; diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index 4cedcbf..24d5f9a 100644 --- a/services/surfaceflinger/Transform.cpp +++ b/services/surfaceflinger/Transform.cpp @@ -20,6 +20,7 @@ #include <utils/String8.h> #include <ui/Region.h> +#include "clz.h" #include "Transform.h" // --------------------------------------------------------------------------- @@ -28,42 +29,6 @@ namespace android { // --------------------------------------------------------------------------- -template <typename T> -static inline T min(T a, T b) { - return a<b ? a : b; -} -template <typename T> -static inline T min(T a, T b, T c) { - return min(a, min(b, c)); -} -template <typename T> -static inline T min(T a, T b, T c, T d) { - return min(a, b, min(c, d)); -} - -template <typename T> -static inline T max(T a, T b) { - return a>b ? a : b; -} -template <typename T> -static inline T max(T a, T b, T c) { - return max(a, max(b, c)); -} -template <typename T> -static inline T max(T a, T b, T c, T d) { - return max(a, b, max(c, d)); -} - -template <typename T> -static inline -void swap(T& a, T& b) { - T t(a); - a = b; - b = t; -} - -// --------------------------------------------------------------------------- - Transform::Transform() { reset(); } diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h index ca44555..a4c5262 100644 --- a/services/surfaceflinger/clz.h +++ b/services/surfaceflinger/clz.h @@ -24,6 +24,41 @@ int inline clz(int32_t x) { return __builtin_clz(x); } +template <typename T> +static inline T min(T a, T b) { + return a<b ? a : b; +} +template <typename T> +static inline T min(T a, T b, T c) { + return min(a, min(b, c)); +} +template <typename T> +static inline T min(T a, T b, T c, T d) { + return min(a, b, min(c, d)); +} + +template <typename T> +static inline T max(T a, T b) { + return a>b ? a : b; +} +template <typename T> +static inline T max(T a, T b, T c) { + return max(a, max(b, c)); +} +template <typename T> +static inline T max(T a, T b, T c, T d) { + return max(a, b, max(c, d)); +} + +template <typename T> +static inline +void swap(T& a, T& b) { + T t(a); + a = b; + b = t; +} + + }; // namespace android #endif /* ANDROID_SURFACE_FLINGER_CLZ_H */ diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java index 0d9d27d..ac66b48 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java @@ -141,6 +141,11 @@ public class CDMALTEPhone extends CDMAPhone { } @Override + public String getDeviceSvn() { + return mImeiSv; + } + + @Override protected void log(String s) { if (DBG) Log.d(LOG_TAG, "[CDMALTEPhone] " + s); diff --git a/tests/TileBenchmark/Android.mk b/tests/TileBenchmark/Android.mk new file mode 100644 index 0000000..430f0f1 --- /dev/null +++ b/tests/TileBenchmark/Android.mk @@ -0,0 +1,32 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := TileBenchmark + +include $(BUILD_PACKAGE) + +################################################## +include $(CLEAR_VARS) + +include $(BUILD_MULTI_PREBUILT) + +# Use the folloing include to make our test apk. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml new file mode 100644 index 0000000..663cc0d --- /dev/null +++ b/tests/TileBenchmark/AndroidManifest.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + android:versionCode="1" + android:versionName="1.0" package="com.test.tilebenchmark"> + <uses-permission android:name="android.permission.INTERNET"/> + <application android:icon="@drawable/icon" + android:label="@string/app_name" + android:hardwareAccelerated="true"> + <activity android:name=".ProfileActivity" + android:label="@string/profile_activity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name=".PlaybackActivity" + android:label="@string/playback_activity"> + </activity> + </application> +</manifest> diff --git a/tests/TileBenchmark/res/drawable-hdpi/icon.png b/tests/TileBenchmark/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..8074c4c --- /dev/null +++ b/tests/TileBenchmark/res/drawable-hdpi/icon.png diff --git a/tests/TileBenchmark/res/drawable-ldpi/icon.png b/tests/TileBenchmark/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 0000000..1095584 --- /dev/null +++ b/tests/TileBenchmark/res/drawable-ldpi/icon.png diff --git a/tests/TileBenchmark/res/drawable-mdpi/icon.png b/tests/TileBenchmark/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..a07c69f --- /dev/null +++ b/tests/TileBenchmark/res/drawable-mdpi/icon.png diff --git a/tests/TileBenchmark/res/layout/main.xml b/tests/TileBenchmark/res/layout/main.xml new file mode 100644 index 0000000..4a81da6 --- /dev/null +++ b/tests/TileBenchmark/res/layout/main.xml @@ -0,0 +1,53 @@ +<?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:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + <LinearLayout + android:id="@+id/top" + android:layout_width="match_parent" + android:layout_height="wrap_content" + > + <Button + android:id="@+id/inspect" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/inspect_log" + /> + <Spinner + android:id="@+id/velocity" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:prompt="@string/desired_scroll_velocity" + /> + <EditText + android:id="@+id/url" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:inputType="textUri" + android:imeOptions="actionGo" + android:layout_weight="1" + /> + </LinearLayout> + <com.test.tilebenchmark.ProfiledWebView + android:id="@+id/web" + android:layout_width="match_parent" + android:layout_height="match_parent" + /> +</LinearLayout> diff --git a/tests/TileBenchmark/res/layout/playback.xml b/tests/TileBenchmark/res/layout/playback.xml new file mode 100644 index 0000000..aa1c8a4 --- /dev/null +++ b/tests/TileBenchmark/res/layout/playback.xml @@ -0,0 +1,58 @@ +<?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:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + <LinearLayout + android:id="@+id/top" + android:layout_width="match_parent" + android:layout_height="wrap_content" + > + <Button + android:id="@+id/backward" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/backward" + /> + <TextView + android:id="@+id/frame_display" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:textAppearance="?android:attr/textAppearanceLarge" + android:layout_weight="1" + /> + <Button + android:id="@+id/forward" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/forward" + /> + <SeekBar + android:id="@+id/seek_bar" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="10" + /> + </LinearLayout> + <com.test.tilebenchmark.PlaybackView + android:id="@+id/playback" + android:layout_width="match_parent" + android:layout_height="match_parent" + /> +</LinearLayout> diff --git a/tests/TileBenchmark/res/values/colors.xml b/tests/TileBenchmark/res/values/colors.xml new file mode 100644 index 0000000..3958083 --- /dev/null +++ b/tests/TileBenchmark/res/values/colors.xml @@ -0,0 +1,25 @@ +<?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. +--> +<resources> + <!-- The color of tiles with valid textures --> + <color name="ready_tile">#ff4ac230</color> + <!-- The color of tiles with stale / invalid textures --> + <color name="unready_tile">#ff744400</color> + <!-- Background color for logged URLs --> + <color name="finished_url">#ff004000</color> + <!-- Background color for URLs with logging in progress --> + <color name="unfinished_url">#ff400000</color> +</resources> diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml new file mode 100644 index 0000000..f70ee2c --- /dev/null +++ b/tests/TileBenchmark/res/values/strings.xml @@ -0,0 +1,67 @@ +<?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. +--> +<resources> + <!-- Button, steps back a single frame [CHAR LIMIT=15] --> + <string name="backward">Backward</string> + <!-- Button, steps forward a single frame [CHAR LIMIT=15] --> + <string name="forward">Forward</string> + <!-- The name of the application [CHAR LIMIT=20] --> + <string name="app_name">TileBenchmark</string> + <!-- name of the auto-scroller / tile logger activity [CHAR LIMIT=100] --> + <string name="profile_activity">Webview Profiler</string> + <!-- name of the tile log playback activity [CHAR LIMIT=100] --> + <string name="playback_activity">Webview Tile Playback</string> + <!-- Button, loads another tile log [CHAR LIMIT=30] --> + <string name="loadbutton">Load</string> + <!-- Button, opens the playback activity [CHAR LIMIT=20] --> + <string name="inspect_log">Inspect Log</string> + <!-- The speed of auto-scrolling [CHAR LIMIT=30] --> + <string name="desired_scroll_velocity">Choose Scroll Velocity</string> + <!-- Pixels moved per frame [CHAR LIMIT=10] --> + <string-array name="velocity_array"> + <item>1</item> + <item>25</item> + <item>50</item> + <item>100</item> + <item>200</item> + <item>400</item> + </string-array> + <!-- 25th percentile - 25% of frames fall below this value [CHAR LIMIT=12] + --> + <string name="percentile_25">25%ile</string> + <!-- 50th percentile - 50% of frames fall below this value (aka median) + [CHAR LIMIT=12] --> + <string name="percentile_50">median</string> + <!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12] + --> + <string name="percentile_75">75%ile</string> + <!-- Frame rate [CHAR LIMIT=15] --> + <string name="frames_per_second">Frames/sec</string> + <!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] --> + <string name="viewport_coverage">Coverage</string> + <!-- Format string for stat value overlay [CHAR LIMIT=15] --> + <string name="format_stat">%4.4f</string> + <!-- Format string for displaying aggregate stats+values (nr of valid tiles, + etc.) [CHAR LIMIT=20] --> + <string name="format_stat_name">%1$9s %2$3d</string> + <!-- Text hovering over canvas, number of tiles ready [CHAR LIMIT=15] --> + <string name="ready_tiles">Ready Tiles</string> + <!-- Text hovering over canvas, number tiles not ready [CHAR LIMIT=15] --> + <string name="unready_tiles">Unready Tiles</string> + <!-- Text hovering over canvas, number of tiles that haven't been + allocated to a place on the page [CHAR LIMIT=15] --> + <string name="unplaced_tiles">Unplaced Tiles</string> +</resources> diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java new file mode 100644 index 0000000..5130f5d --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.test.tilebenchmark; + +import android.app.Activity; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * Interface for playing back WebView tile rendering status. Draws viewport and + * states of tiles and statistics for off-line analysis. + */ +public class PlaybackActivity extends Activity { + private static final float SCROLL_SCALER = 0.125f; + + PlaybackView mPlaybackView; + SeekBar mSeekBar; + Button mForward; + Button mBackward; + TextView mFrameDisplay; + + private int mFrame = -1; + private int mFrameMax; + + private class TouchFrameChangeListener extends SimpleOnGestureListener { + float mDist = 0; + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + // aggregate scrolls so that small ones can add up + mDist += distanceY * SCROLL_SCALER; + int intComponent = (int) Math.floor(Math.abs(mDist)); + if (intComponent >= 1) { + int scrollDist = (mDist > 0) ? intComponent : -intComponent; + setFrame(null, mFrame + scrollDist); + mDist -= scrollDist; + } + return super.onScroll(e1, e2, distanceX, distanceY); + } + }; + + private class SeekFrameChangeListener implements OnSeekBarChangeListener { + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, + boolean fromUser) { + setFrame(seekBar, progress); + } + }; + + private class LoadFileTask extends AsyncTask<String, Void, TileData[][]> { + @Override + protected TileData[][] doInBackground(String... params) { + TileData[][] data = null; + try { + FileInputStream fis = openFileInput(params[0]); + ObjectInputStream in = new ObjectInputStream(fis); + data = (TileData[][]) in.readObject(); + in.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + } + return data; + } + + @Override + protected void onPostExecute(TileData data[][]) { + if (data == null) { + data = genTestPattern(); + } + mPlaybackView.setData(data); + + mFrameMax = data.length - 1; + mSeekBar.setMax(mFrameMax); + + setFrame(null, 0); + } + } + + private void setFrame(View changer, int f) { + if (f < 0) { + f = 0; + } else if (f > mFrameMax) { + f = mFrameMax; + } + + if (mFrame == f) { + return; + } + + mFrame = f; + mForward.setEnabled(mFrame != mFrameMax); + mBackward.setEnabled(mFrame != 0); + if (changer != mSeekBar) { + mSeekBar.setProgress(mFrame); + } + mFrameDisplay.setText(Integer.toString(mFrame)); + mPlaybackView.setFrame(mFrame); + }; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.playback); + + mPlaybackView = (PlaybackView) findViewById(R.id.playback); + mSeekBar = (SeekBar) findViewById(R.id.seek_bar); + mForward = (Button) findViewById(R.id.forward); + mBackward = (Button) findViewById(R.id.backward); + mFrameDisplay = (TextView) findViewById(R.id.frame_display); + + mForward.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + setFrame(v, mFrame + 1); + } + }); + + mBackward.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + setFrame(v, mFrame - 1); + } + }); + + mSeekBar.setOnSeekBarChangeListener(new SeekFrameChangeListener()); + + mPlaybackView.setOnGestureListener(new TouchFrameChangeListener()); + + new LoadFileTask().execute(ProfileActivity.TEMP_FILENAME); + } + + private TileData[][] genTestPattern() { + final int XMAX = 5; + final int FRAMEMAX = 99; + + TileData example[][] = new TileData[FRAMEMAX][]; + for (int frame = 0; frame < FRAMEMAX; frame++) { + int numTiles = frame + 10; + + example[frame] = new TileData[numTiles]; + for (int t = 0; t < numTiles; t++) { + int x = t % XMAX; + int y = t / XMAX; + boolean isReady = y * 10 < frame; + example[frame][t] = new TileData(x, y, isReady, 0); + } + } + return example; + } +} diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java new file mode 100644 index 0000000..db4a341 --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.test.tilebenchmark; + +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.ShapeDrawable; +import android.os.Bundle; + +import java.util.ArrayList; +import java.util.Arrays; + +public class PlaybackGraphs { + private static final int BAR_WIDTH = PlaybackView.TILEX * 3; + private static final float CANVAS_SCALE = 0.2f; + private static final double IDEAL_FRAMES = 60; + private static final int LABELOFFSET = 100; + private static Paint whiteLabels; + + private static double viewportCoverage(int l, int b, int r, int t, + int tileIndexX, + int tileIndexY) { + if (tileIndexX * PlaybackView.TILEX < r + && (tileIndexX + 1) * PlaybackView.TILEX >= l + && tileIndexY * PlaybackView.TILEY < t + && (tileIndexY + 1) * PlaybackView.TILEY >= b) { + return 1.0f; + } + return 0.0f; + } + + private interface MetricGen { + public double getValue(TileData[] frame); + + public double getMax(); + + public int getLabelId(); + }; + + private static MetricGen[] Metrics = new MetricGen[] { + new MetricGen() { + // framerate graph + @Override + public double getValue(TileData[] frame) { + int renderTimeUS = frame[0].level; + return 1.0e6f / renderTimeUS; + } + + @Override + public double getMax() { + return IDEAL_FRAMES; + } + + @Override + public int getLabelId() { + return R.string.frames_per_second; + } + }, new MetricGen() { + // coverage graph + @Override + public double getValue(TileData[] frame) { + int l = frame[0].x, b = frame[0].y; + int r = frame[1].x, t = frame[1].y; + double total = 0, totalCount = 0; + for (int tileID = 2; tileID < frame.length; tileID++) { + TileData data = frame[tileID]; + double coverage = viewportCoverage(l, b, r, t, data.x, + data.y); + total += coverage * (data.isReady ? 1 : 0); + totalCount += coverage; + } + if (totalCount == 0) { + return -1; + } + return total / totalCount; + } + + @Override + public double getMax() { + return 1; + } + + @Override + public int getLabelId() { + return R.string.viewport_coverage; + } + } + }; + + private interface StatGen { + public double getValue(double sortedValues[]); + + public int getLabelId(); + } + + public static double getPercentile(double sortedValues[], double ratioAbove) { + double index = ratioAbove * (sortedValues.length - 1); + int intIndex = (int) Math.floor(index); + if (index == intIndex) { + return sortedValues[intIndex]; + } + double alpha = index - intIndex; + return sortedValues[intIndex] * (1 - alpha) + + sortedValues[intIndex + 1] * (alpha); + } + + private static StatGen[] Stats = new StatGen[] { + new StatGen() { + @Override + public double getValue(double[] sortedValues) { + return getPercentile(sortedValues, 0.25); + } + + @Override + public int getLabelId() { + return R.string.percentile_25; + } + }, new StatGen() { + @Override + public double getValue(double[] sortedValues) { + return getPercentile(sortedValues, 0.5); + } + + @Override + public int getLabelId() { + return R.string.percentile_50; + } + }, new StatGen() { + @Override + public double getValue(double[] sortedValues) { + return getPercentile(sortedValues, 0.75); + } + + @Override + public int getLabelId() { + return R.string.percentile_75; + } + }, + }; + + public PlaybackGraphs() { + whiteLabels = new Paint(); + whiteLabels.setColor(Color.WHITE); + whiteLabels.setTextSize(PlaybackView.TILEY / 3); + } + + private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>(); + private double[][] mStats = new double[Metrics.length][Stats.length]; + + public void setData(TileData[][] tileProfilingData) { + mShapes.clear(); + double metricValues[] = new double[tileProfilingData.length]; + + if (tileProfilingData.length == 0) { + return; + } + + for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { + // create graph out of rectangles, one per frame + int lastBar = 0; + for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) { + TileData frame[] = tileProfilingData[frameIndex]; + int newBar = (frame[0].y + frame[1].y) / 2; + + MetricGen s = Metrics[metricIndex]; + double absoluteValue = s.getValue(frame); + double relativeValue = absoluteValue / s.getMax(); + int rightPos = (int) (-BAR_WIDTH * metricIndex); + int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue)); + + ShapeDrawable graphBar = new ShapeDrawable(); + graphBar.getPaint().setColor(Color.BLUE); + graphBar.setBounds(leftPos, lastBar, rightPos, newBar); + + mShapes.add(graphBar); + metricValues[frameIndex] = absoluteValue; + lastBar = newBar; + } + + // store aggregate statistics per metric (median, and similar) + Arrays.sort(metricValues); + for (int statIndex = 0; statIndex < Stats.length; statIndex++) { + mStats[metricIndex][statIndex] = Stats[statIndex] + .getValue(metricValues); + } + } + } + + public void drawVerticalShiftedShapes(Canvas canvas, + ArrayList<ShapeDrawable> shapes) { + // Shapes drawn here are drawn relative to the viewRect + Rect viewRect = shapes.get(shapes.size() - 1).getBounds(); + canvas.translate(0, 5 * PlaybackView.TILEY - viewRect.top); + + for (ShapeDrawable shape : mShapes) { + shape.draw(canvas); + } + for (ShapeDrawable shape : shapes) { + shape.draw(canvas); + } + } + + public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes, + String[] strings, Resources resources) { + canvas.scale(CANVAS_SCALE, CANVAS_SCALE); + + canvas.translate(BAR_WIDTH * Metrics.length, 0); + + canvas.save(); + drawVerticalShiftedShapes(canvas, shapes); + canvas.restore(); + + for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { + String label = resources.getString( + Metrics[metricIndex].getLabelId()); + int xPos = (metricIndex + 1) * -BAR_WIDTH; + int yPos = LABELOFFSET; + canvas.drawText(label, xPos, yPos, whiteLabels); + for (int statIndex = 0; statIndex < Stats.length; statIndex++) { + label = resources.getString(R.string.format_stat, mStats[metricIndex][statIndex]); + yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILEY / 2; + canvas.drawText(label, xPos, yPos, whiteLabels); + } + } + for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) { + int yPos = LABELOFFSET + stringIndex * PlaybackView.TILEY / 2; + canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels); + } + } + + public Bundle getStatBundle(Resources resources) { + Bundle b = new Bundle(); + + for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { + for (int statIndex = 0; statIndex < Stats.length; statIndex++) { + String metricLabel = resources.getString( + Metrics[metricIndex].getLabelId()); + String statLabel = resources.getString( + Stats[statIndex].getLabelId()); + double value = mStats[metricIndex][statIndex]; + b.putDouble(metricLabel + " " + statLabel, value); + } + } + + return b; + } +} diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java new file mode 100644 index 0000000..f104eac --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.test.tilebenchmark; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.ShapeDrawable; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.GestureDetector.OnGestureListener; +import android.view.MotionEvent; +import android.view.View; + +import java.util.ArrayList; + +public class PlaybackView extends View { + public static final int TILEX = 300; + public static final int TILEY = 300; + + private Paint levelPaint = null, coordPaint = null, goldPaint = null; + private PlaybackGraphs mGraphs; + + private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>(); + private TileData mProfData[][] = null; + private GestureDetector mGestureDetector = null; + private String mRenderStrings[] = new String[3]; + + private class TileDrawable extends ShapeDrawable { + TileData tile; + + public TileDrawable(TileData t) { + int tileColorId = t.isReady ? R.color.ready_tile + : R.color.unready_tile; + getPaint().setColor(getResources().getColor(tileColorId)); + + setBounds(t.x * TILEX, t.y * TILEY, (t.x + 1) * TILEX, (t.y + 1) + * TILEY); + this.tile = t; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + canvas.drawText(Integer.toString(tile.level), getBounds().left, + getBounds().bottom, levelPaint); + canvas.drawText(tile.x + "," + tile.y, getBounds().left, + ((getBounds().bottom + getBounds().top) / 2), coordPaint); + } + } + + public PlaybackView(Context context) { + super(context); + init(); + } + + public PlaybackView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public PlaybackView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public void setOnGestureListener(OnGestureListener gl) { + mGestureDetector = new GestureDetector(getContext(), gl); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + mGestureDetector.onTouchEvent(event); + return true; + } + + private void init() { + levelPaint = new Paint(); + levelPaint.setColor(Color.WHITE); + levelPaint.setTextSize(TILEY / 2); + coordPaint = new Paint(); + coordPaint.setColor(Color.BLACK); + coordPaint.setTextSize(TILEY / 3); + goldPaint = new Paint(); + goldPaint.setColor(0xffa0e010); + mGraphs = new PlaybackGraphs(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mTempShapes == null || mTempShapes.isEmpty()) { + return; + } + + mGraphs.draw(canvas, mTempShapes, mRenderStrings, getResources()); + } + + public int setFrame(int frame) { + if (mProfData == null || mProfData.length == 0) { + return 0; + } + + int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0; + mTempShapes.clear(); + + // draw actual tiles + for (int tileID = 2; tileID < mProfData[frame].length; tileID++) { + TileData t = mProfData[frame][tileID]; + mTempShapes.add(new TileDrawable(t)); + if (t.isReady) { + readyTiles++; + } else { + unreadyTiles++; + } + if (t.x < 0 || t.y < 0) { + unplacedTiles++; + } + } + mRenderStrings[0] = getResources().getString(R.string.format_stat_name, + getResources().getString(R.string.ready_tiles), readyTiles); + mRenderStrings[1] = getResources().getString(R.string.format_stat_name, + getResources().getString(R.string.unready_tiles), unreadyTiles); + mRenderStrings[2] = getResources().getString(R.string.format_stat_name, + getResources().getString(R.string.unplaced_tiles), unplacedTiles); + + // draw view rect (using first two TileData objects) + ShapeDrawable viewShape = new ShapeDrawable(); + viewShape.getPaint().setColor(0xff0000ff); + viewShape.setAlpha(64); + viewShape.setBounds(mProfData[frame][0].x, mProfData[frame][0].y, + mProfData[frame][1].x, mProfData[frame][1].y); + mTempShapes.add(viewShape); + this.invalidate(); + return frame; + } + + public void setData(TileData[][] tileProfilingData) { + mProfData = tileProfilingData; + + mGraphs.setData(mProfData); + } +} diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java new file mode 100644 index 0000000..23b6275 --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.test.tilebenchmark; + +import android.app.Activity; +import android.content.Intent; +import android.content.Context; +import android.graphics.Bitmap; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.util.Pair; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; + +/** + * Interface for profiling the webview's scrolling, with simple controls on how + * to scroll, and what content to load. + */ +public class ProfileActivity extends Activity { + + public interface ProfileCallback { + public void profileCallback(TileData data[][]); + } + + public static final String TEMP_FILENAME = "profile.tiles"; + private static final int LOAD_TEST_DELAY = 2000; // nr of millis after load, + // before test + + Button mInspectButton; + Spinner mVelocitySpinner; + EditText mUrl; + ProfiledWebView mWeb; + ProfileCallback mCallback; + + private class VelocitySelectedListener implements OnItemSelectedListener { + @Override + public void onItemSelected(AdapterView<?> parent, View view, + int position, long id) { + String speedStr = parent.getItemAtPosition(position).toString(); + int speedInt = Integer.parseInt(speedStr); + mWeb.setAutoScrollSpeed(speedInt); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + } + } + + private class LoggingWebViewClient extends WebViewClient { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + return false; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + mUrl.setText(url); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + view.requestFocus(); + new CountDownTimer(LOAD_TEST_DELAY, LOAD_TEST_DELAY) { + @Override + public void onTick(long millisUntilFinished) { + } + + @Override + public void onFinish() { + mWeb.startScrollTest(mCallback); + } + }.start(); + } + } + + private class StoreFileTask extends + AsyncTask<Pair<String, TileData[][]>, Void, Void> { + + @Override + protected Void doInBackground(Pair<String, TileData[][]>... params) { + try { + FileOutputStream fos = openFileOutput(params[0].first, + Context.MODE_PRIVATE); + ObjectOutputStream out = new ObjectOutputStream(fos); + out.writeObject(params[0].second); + out.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + return null; + } + + @Override + protected void onPostExecute(Void v) { + mUrl.setBackgroundResource(R.color.finished_url); + } + } + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + mInspectButton = (Button) findViewById(R.id.inspect); + mVelocitySpinner = (Spinner) findViewById(R.id.velocity); + mUrl = (EditText) findViewById(R.id.url); + mWeb = (ProfiledWebView) findViewById(R.id.web); + mCallback = new ProfileCallback() { + @SuppressWarnings("unchecked") + @Override + public void profileCallback(TileData[][] data) { + new StoreFileTask().execute(new Pair<String, TileData[][]>(TEMP_FILENAME, data)); + } + }; + + // Inspect button (opens PlaybackActivity) + mInspectButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ProfileActivity.this, + PlaybackActivity.class)); + } + }); + + // Velocity spinner + ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( + this, R.array.velocity_array, + android.R.layout.simple_spinner_item); + adapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mVelocitySpinner.setAdapter(adapter); + mVelocitySpinner.setOnItemSelectedListener( + new VelocitySelectedListener()); + mVelocitySpinner.setSelection(3); + + // Custom profiling WebView + WebSettings settings = mWeb.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setSupportZoom(true); + settings.setEnableSmoothTransition(true); + settings.setBuiltInZoomControls(true); + settings.setLoadWithOverviewMode(true); + mWeb.setWebViewClient(new LoggingWebViewClient()); + + // URL text entry + mUrl.setOnEditorActionListener(new OnEditorActionListener() { + public boolean onEditorAction(TextView v, int actionId, + KeyEvent event) { + String url = mUrl.getText().toString(); + mUrl.setBackgroundResource(R.color.unfinished_url); + mWeb.loadUrl(url); + mWeb.requestFocus(); + return true; + } + }); + } + + public void setCallback(ProfileCallback callback) { + mCallback = callback; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if ((keyCode == KeyEvent.KEYCODE_BACK) && mWeb.canGoBack()) { + mWeb.goBack(); + return true; + } + return super.onKeyDown(keyCode, event); + } +} diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java new file mode 100644 index 0000000..6560624 --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.test.tilebenchmark; + +import android.content.Context; +import android.util.AttributeSet; +import android.webkit.WebView; + +import com.test.tilebenchmark.ProfileActivity.ProfileCallback; + +public class ProfiledWebView extends WebView { + private int mSpeed; + + private boolean isScrolling = false; + private ProfileCallback mCallback; + + public ProfiledWebView(Context context) { + super(context); + } + + public ProfiledWebView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ProfiledWebView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public ProfiledWebView(Context context, AttributeSet attrs, int defStyle, + boolean privateBrowsing) { + super(context, attrs, defStyle, privateBrowsing); + } + + @Override + protected void onDraw(android.graphics.Canvas canvas) { + if (isScrolling) { + if (canScrollVertically(1)) { + scrollBy(0, mSpeed); + } else { + stopScrollTest(); + isScrolling = false; + } + } + super.onDraw(canvas); + } + + /* + * Called once the page is loaded to start scrolling for evaluating tiles + */ + public void startScrollTest(ProfileCallback callback) { + isScrolling = true; + mCallback = callback; + super.tileProfilingStart(); + invalidate(); + } + + /* + * Called once the page has stopped scrolling + */ + public void stopScrollTest() { + float testRatio = super.tileProfilingStop(); + + TileData data[][] = new TileData[super.tileProfilingNumFrames()][]; + for (int frame = 0; frame < data.length; frame++) { + data[frame] = new TileData[ + super.tileProfilingNumTilesInFrame(frame)]; + for (int tile = 0; tile < data[frame].length; tile++) { + int x = super.tileProfilingGetX(frame, tile); + int y = super.tileProfilingGetY(frame, tile); + boolean isReady = super.tileProfilingGetReady(frame, tile); + int level = super.tileProfilingGetLevel(frame, tile); + + data[frame][tile] = new TileData(x, y, isReady, level); + } + } + super.tileProfilingClear(); + + mCallback.profileCallback(data); + } + + @Override + public void loadUrl(String url) { + if (!url.startsWith("http://")) { + url = "http://" + url; + } + super.loadUrl(url); + } + + public void setAutoScrollSpeed(int speedInt) { + mSpeed = speedInt; + } +} diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java new file mode 100644 index 0000000..7d4bb9f --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.test.tilebenchmark; + +import java.io.Serializable; + +public class TileData implements Serializable { + public int x, y; + public boolean isReady; + public int level; + + public TileData(int x, int y, boolean isReady, int level) { + this.x = x; + this.y = y; + this.isReady = isReady; + this.level = level; + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index b4448a9..8e3ed93 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -1093,33 +1093,6 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - /*package*/ static void native_drawTextWithGlyphs(int nativeCanvas, char[] text, - int index, int count, float x, - float y, int flags, int paint) { - native_drawText(nativeCanvas, text, index, count, x, y, flags, paint); - } - - @LayoutlibDelegate - /*package*/ static void native_drawTextWithGlyphs(int nativeCanvas, String text, - int start, int end, float x, - float y, int flags, int paint) { - int count = end - start; - char[] buffer = TemporaryBuffer.obtain(count); - TextUtils.getChars(text, start, end, buffer, 0); - - native_drawText(nativeCanvas, text, 0, count, x, y, flags, paint); - } - - @LayoutlibDelegate - /*package*/ static void native_drawGlyphs(int nativeCanvas, char[] glyphs, - int index, int count, float x, - float y, int flags, int paint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawGlyphs is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate /*package*/ static void native_drawPosText(int nativeCanvas, char[] text, int index, int count, float[] pos, diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java new file mode 100644 index 0000000..52b8f34 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text; + +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + + +/** + * Delegate used to provide new implementation for the native methods of {@link AndroidBidi} + * + * Through the layoutlib_create tool, the original methods of AndroidBidi have been replaced + * by calls to methods of the same name in this delegate class. + * + */ +public class AndroidBidi_Delegate { + + @LayoutlibDelegate + /*package*/ static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) { + // return the equivalent of Layout.DIR_LEFT_TO_RIGHT + // TODO: actually figure the direction. + return 0; + } +} diff --git a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java index ec7a67e..f056040 100644 --- a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java +++ b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java @@ -19,6 +19,7 @@ package android.view.inputmethod; import com.android.layoutlib.bridge.android.BridgeIInputMethodManager; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; +import android.content.Context; import android.os.Looper; @@ -44,6 +45,18 @@ public class InputMethodManager_Delegate { mainLooper); } return InputMethodManager.mInstance; + } + + @LayoutlibDelegate + /*package*/ static InputMethodManager getInstance(Context context) { + synchronized (InputMethodManager.mInstanceSync) { + if (InputMethodManager.mInstance != null) { + return InputMethodManager.mInstance; + } + InputMethodManager.mInstance = new InputMethodManager(new BridgeIInputMethodManager(), + Looper.myLooper()); + } + return InputMethodManager.mInstance; } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java index 2519ebc..23e0ca1 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java @@ -188,4 +188,10 @@ public class BridgeIInputMethodManager implements IInputMethodManager { return null; } + public boolean setAdditionalInputMethodSubtypes(IBinder arg0, InputMethodSubtype[] arg1) + throws RemoteException { + // TODO Auto-generated method stub + return false; + } + } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index df7e04f..93a35cc 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -155,6 +155,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.Typeface", "android.graphics.Xfermode", "android.os.SystemClock", + "android.text.AndroidBidi", "android.util.FloatMath", "android.view.Display", "libcore.icu.ICU", diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index e3661bf..7bb927b 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -81,6 +81,24 @@ public class WifiInfo implements Parcelable { mHiddenSSID = false; } + /** + * Copy constructor + * @hide + */ + public WifiInfo(WifiInfo source) { + if (source != null) { + mSupplicantState = source.mSupplicantState; + mBSSID = source.mBSSID; + mSSID = source.mSSID; + mNetworkId = source.mNetworkId; + mHiddenSSID = source.mHiddenSSID; + mRssi = source.mRssi; + mLinkSpeed = source.mLinkSpeed; + mIpAddress = source.mIpAddress; + mMacAddress = source.mMacAddress; + } + } + void setSSID(String SSID) { mSSID = SSID; // network is considered not hidden by default diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9d1bdd4..cd6621f 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -230,11 +230,13 @@ public class WifiManager { /** * Broadcast intent action indicating that the state of Wi-Fi connectivity * has changed. One extra provides the new state - * in the form of a {@link android.net.NetworkInfo} object. If the new state is - * CONNECTED, a second extra may provide the BSSID of the access point, + * in the form of a {@link android.net.NetworkInfo} object. If the new + * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of + * the access point. * as a {@code String}. * @see #EXTRA_NETWORK_INFO * @see #EXTRA_BSSID + * @see #EXTRA_WIFI_INFO */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; @@ -252,6 +254,13 @@ public class WifiManager { */ public static final String EXTRA_BSSID = "bssid"; /** + * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the + * information about the access point to which we are connected. Only present + * when the new state is CONNECTED. Retrieve with + * {@link android.content.Intent#getParcelableExtra(String)}. + */ + public static final String EXTRA_WIFI_INFO = "wifiInfo"; + /** * Broadcast intent action indicating that the state of establishing a connection to * an access point has changed.One extra provides the new * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 8c28319..12efeb1 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -1374,6 +1374,8 @@ public class WifiStateMachine extends StateMachine { intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); if (bssid != null) intent.putExtra(WifiManager.EXTRA_BSSID, bssid); + if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) + intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); mContext.sendStickyBroadcast(intent); } |