Merge "Update tilebenchmark to work with current drawing infrastructure"
diff --git a/api/15.txt b/api/15.txt
index bca8e01..ddf5baf 100644
--- a/api/15.txt
+++ b/api/15.txt
@@ -83,6 +83,7 @@
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
field public static final java.lang.String READ_PROFILE = "android.permission.READ_PROFILE";
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
+ field public static final java.lang.String READ_SOCIAL_STREAM = "android.permission.READ_SOCIAL_STREAM";
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 REBOOT = "android.permission.REBOOT";
@@ -127,6 +128,7 @@
field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
field public static final java.lang.String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
field public static final java.lang.String WRITE_SMS = "android.permission.WRITE_SMS";
+ field public static final java.lang.String WRITE_SOCIAL_STREAM = "android.permission.WRITE_SOCIAL_STREAM";
field public static final java.lang.String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
}
@@ -3235,6 +3237,7 @@
method public final android.app.Fragment getTargetFragment();
method public final int getTargetRequestCode();
method public final java.lang.CharSequence getText(int);
+ method public boolean getUserVisibleHint();
method public android.view.View getView();
method public final int hashCode();
method public static android.app.Fragment instantiate(android.content.Context, java.lang.String);
@@ -3281,6 +3284,7 @@
method public void setMenuVisibility(boolean);
method public void setRetainInstance(boolean);
method public void setTargetFragment(android.app.Fragment, int);
+ method public void setUserVisibleHint(boolean);
method public void startActivity(android.content.Intent);
method public void startActivityForResult(android.content.Intent, int);
method public void unregisterForContextMenu(android.view.View);
@@ -4143,6 +4147,7 @@
ctor public AppWidgetHostView(android.content.Context, int, int);
method public int getAppWidgetId();
method public android.appwidget.AppWidgetProviderInfo getAppWidgetInfo();
+ method public static android.graphics.Rect getDefaultPaddingForWidget(android.content.Context, android.content.ComponentName, android.graphics.Rect);
method protected android.view.View getDefaultView();
method protected android.view.View getErrorView();
method protected void prepareView(android.view.View);
@@ -4472,10 +4477,12 @@
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public int describeContents();
+ method public boolean fetchUuidsWithSdp();
method public java.lang.String getAddress();
method public android.bluetooth.BluetoothClass getBluetoothClass();
method public int getBondState();
method public java.lang.String getName();
+ method public android.os.ParcelUuid[] getUuids();
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
field public static final java.lang.String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
@@ -4484,6 +4491,7 @@
field public static final java.lang.String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
field public static final java.lang.String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
field public static final java.lang.String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
+ field public static final java.lang.String ACTION_UUID = "android.bluetooth.device.action.UUID";
field public static final int BOND_BONDED = 12; // 0xc
field public static final int BOND_BONDING = 11; // 0xb
field public static final int BOND_NONE = 10; // 0xa
@@ -4495,6 +4503,7 @@
field public static final java.lang.String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
field public static final java.lang.String EXTRA_PREVIOUS_BOND_STATE = "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
field public static final java.lang.String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
+ field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -5325,6 +5334,7 @@
method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
method public T getParcelableExtra(java.lang.String);
method public java.lang.String getScheme();
+ method public android.content.Intent getSelector();
method public java.io.Serializable getSerializableExtra(java.lang.String);
method public short[] getShortArrayExtra(java.lang.String);
method public short getShortExtra(java.lang.String, short);
@@ -5337,6 +5347,7 @@
method public boolean hasExtra(java.lang.String);
method public boolean hasFileDescriptors();
method public static android.content.Intent makeMainActivity(android.content.ComponentName);
+ method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException;
@@ -5390,6 +5401,7 @@
method public void setExtrasClassLoader(java.lang.ClassLoader);
method public android.content.Intent setFlags(int);
method public android.content.Intent setPackage(java.lang.String);
+ method public void setSelector(android.content.Intent);
method public void setSourceBounds(android.graphics.Rect);
method public android.content.Intent setType(java.lang.String);
method public deprecated java.lang.String toURI();
@@ -5493,7 +5505,16 @@
field public static final java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
field public static final java.lang.String CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE";
+ field public static final java.lang.String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
+ field public static final java.lang.String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
+ field public static final java.lang.String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
+ field public static final java.lang.String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
+ field public static final java.lang.String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+ field public static final java.lang.String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
+ field public static final java.lang.String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
field public static final java.lang.String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
+ field public static final java.lang.String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
+ field public static final java.lang.String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
field public static final java.lang.String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
field public static final java.lang.String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
field public static final java.lang.String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
@@ -5559,6 +5580,7 @@
field public static final int FILL_IN_COMPONENT = 8; // 0x8
field public static final int FILL_IN_DATA = 2; // 0x2
field public static final int FILL_IN_PACKAGE = 16; // 0x10
+ field public static final int FILL_IN_SELECTOR = 64; // 0x40
field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
@@ -6782,6 +6804,13 @@
method public abstract boolean onMove(int, int);
}
+ public class CrossProcessCursorWrapper extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
+ ctor public CrossProcessCursorWrapper(android.database.Cursor);
+ method public void fillWindow(int, android.database.CursorWindow);
+ method public android.database.CursorWindow getWindow();
+ method public boolean onMove(int, int);
+ }
+
public abstract interface Cursor {
method public abstract void close();
method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -6851,7 +6880,8 @@
}
public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
- ctor public CursorWindow(boolean);
+ ctor public CursorWindow(java.lang.String);
+ ctor public deprecated CursorWindow(boolean);
method public boolean allocRow();
method public void clear();
method public void close();
@@ -8782,6 +8812,7 @@
method public long getTimestamp();
method public void getTransformMatrix(float[]);
method public void release();
+ method public void setDefaultBufferSize(int, int);
method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
method public void updateTexImage();
}
@@ -9356,6 +9387,7 @@
method public java.util.List<android.hardware.Camera.Size> getSupportedVideoSizes();
method public java.util.List<java.lang.String> getSupportedWhiteBalance();
method public float getVerticalViewAngle();
+ method public boolean getVideoStabilization();
method public java.lang.String getWhiteBalance();
method public int getZoom();
method public java.util.List<java.lang.Integer> getZoomRatios();
@@ -9363,6 +9395,7 @@
method public boolean isAutoWhiteBalanceLockSupported();
method public boolean isSmoothZoomSupported();
method public boolean isVideoSnapshotSupported();
+ method public boolean isVideoStabilizationSupported();
method public boolean isZoomSupported();
method public void remove(java.lang.String);
method public void removeGpsData();
@@ -9394,6 +9427,7 @@
method public void setRecordingHint(boolean);
method public void setRotation(int);
method public void setSceneMode(java.lang.String);
+ method public void setVideoStabilization(boolean);
method public void setWhiteBalance(java.lang.String);
method public void setZoom(int);
method public void unflatten(java.lang.String);
@@ -10529,6 +10563,7 @@
field public static final int QUALITY_HIGH = 1; // 0x1
field public static final int QUALITY_LOW = 0; // 0x0
field public static final int QUALITY_QCIF = 2; // 0x2
+ field public static final int QUALITY_QVGA = 7; // 0x7
field public static final int QUALITY_TIME_LAPSE_1080P = 1006; // 0x3ee
field public static final int QUALITY_TIME_LAPSE_480P = 1004; // 0x3ec
field public static final int QUALITY_TIME_LAPSE_720P = 1005; // 0x3ed
@@ -10536,6 +10571,7 @@
field public static final int QUALITY_TIME_LAPSE_HIGH = 1001; // 0x3e9
field public static final int QUALITY_TIME_LAPSE_LOW = 1000; // 0x3e8
field public static final int QUALITY_TIME_LAPSE_QCIF = 1002; // 0x3ea
+ field public static final int QUALITY_TIME_LAPSE_QVGA = 1007; // 0x3ef
field public int audioBitRate;
field public int audioChannels;
field public int audioCodec;
@@ -10675,6 +10711,7 @@
field public static final int METADATA_KEY_GENRE = 6; // 0x6
field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+ field public static final int METADATA_KEY_LOCATION = 23; // 0x17
field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
field public static final int METADATA_KEY_TITLE = 7; // 0x7
@@ -13609,16 +13646,19 @@
field public static final int GL_RENDERBUFFER_RED_SIZE_OES = 36176; // 0x8d50
field public static final int GL_RENDERBUFFER_STENCIL_SIZE_OES = 36181; // 0x8d55
field public static final int GL_RENDERBUFFER_WIDTH_OES = 36162; // 0x8d42
+ field public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 36200; // 0x8d68
field public static final int GL_RGB565_OES = 36194; // 0x8d62
field public static final int GL_RGB5_A1_OES = 32855; // 0x8057
field public static final int GL_RGB8_OES = 32849; // 0x8051
field public static final int GL_RGBA4_OES = 32854; // 0x8056
field public static final int GL_RGBA8_OES = 32856; // 0x8058
+ field public static final int GL_SAMPLER_EXTERNAL_OES = 36198; // 0x8d66
field public static final int GL_STENCIL_ATTACHMENT_OES = 36128; // 0x8d20
field public static final int GL_STENCIL_INDEX1_OES = 36166; // 0x8d46
field public static final int GL_STENCIL_INDEX4_OES = 36167; // 0x8d47
field public static final int GL_STENCIL_INDEX8_OES = 36168; // 0x8d48
field public static final int GL_TEXTURE_BINDING_CUBE_MAP_OES = 34068; // 0x8514
+ field public static final int GL_TEXTURE_BINDING_EXTERNAL_OES = 36199; // 0x8d67
field public static final int GL_TEXTURE_CROP_RECT_OES = 35741; // 0x8b9d
field public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES = 34070; // 0x8516
field public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES = 34072; // 0x8518
@@ -13627,6 +13667,7 @@
field public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES = 34069; // 0x8515
field public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES = 34071; // 0x8517
field public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES = 34073; // 0x8519
+ field public static final int GL_TEXTURE_EXTERNAL_OES = 36197; // 0x8d65
field public static final int GL_TEXTURE_GEN_MODE_OES = 9472; // 0x2500
field public static final int GL_TEXTURE_GEN_STR_OES = 36192; // 0x8d60
field public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 35215; // 0x898f
@@ -14384,6 +14425,7 @@
field public static final int HONEYCOMB_MR1 = 12; // 0xc
field public static final int HONEYCOMB_MR2 = 13; // 0xd
field public static final int ICE_CREAM_SANDWICH = 14; // 0xe
+ field public static final int ICE_CREAM_SANDWICH_MR1 = 15; // 0xf
}
public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -14749,6 +14791,7 @@
field public static final int FLAG_ONEWAY = 1; // 0x1
field public static final int INTERFACE_TRANSACTION = 1598968902; // 0x5f4e5446
field public static final int LAST_CALL_TRANSACTION = 16777215; // 0xffffff
+ field public static final int LIKE_TRANSACTION = 1598835019; // 0x5f4c494b
field public static final int PING_TRANSACTION = 1599098439; // 0x5f504e47
field public static final int TWEET_TRANSACTION = 1599362900; // 0x5f545754
}
@@ -15110,6 +15153,7 @@
public class RemoteException extends android.util.AndroidException {
ctor public RemoteException();
+ ctor public RemoteException(java.lang.String);
}
public class ResultReceiver implements android.os.Parcelable {
@@ -15204,6 +15248,10 @@
method public abstract void released();
}
+ public class TransactionTooLargeException extends android.os.RemoteException {
+ ctor public TransactionTooLargeException();
+ }
+
public class Vibrator {
method public void cancel();
method public boolean hasVibrator();
@@ -15720,6 +15768,7 @@
field public static final int TYPE_NONE = 0; // 0x0
field public static final int TYPE_OPTIONAL = 2; // 0x2
field public static final int TYPE_REQUIRED = 1; // 0x1
+ field public static final int TYPE_RESOURCE = 3; // 0x3
}
public static final class CalendarContract.CalendarAlerts implements android.provider.BaseColumns android.provider.CalendarContract.CalendarAlertsColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns {
@@ -15758,9 +15807,12 @@
}
protected static abstract interface CalendarContract.CalendarColumns {
+ field public static final java.lang.String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes";
+ field public static final java.lang.String ALLOWED_AVAILABILITY = "allowedAvailability";
field public static final java.lang.String ALLOWED_REMINDERS = "allowedReminders";
field public static final java.lang.String CALENDAR_ACCESS_LEVEL = "calendar_access_level";
field public static final java.lang.String CALENDAR_COLOR = "calendar_color";
+ field public static final java.lang.String CALENDAR_COLOR_KEY = "calendar_color_index";
field public static final java.lang.String CALENDAR_DISPLAY_NAME = "calendar_displayName";
field public static final java.lang.String CALENDAR_TIME_ZONE = "calendar_timezone";
field public static final int CAL_ACCESS_CONTRIBUTOR = 500; // 0x1f4
@@ -15805,6 +15857,18 @@
field public static final java.lang.String NAME = "name";
}
+ public static final class CalendarContract.Colors implements android.provider.CalendarContract.ColorsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
+ protected static abstract interface CalendarContract.ColorsColumns implements android.provider.SyncStateContract.Columns {
+ field public static final java.lang.String COLOR = "color";
+ field public static final java.lang.String COLOR_KEY = "color_index";
+ field public static final java.lang.String COLOR_TYPE = "color_type";
+ field public static final int TYPE_CALENDAR = 0; // 0x0
+ field public static final int TYPE_EVENT = 1; // 0x1
+ }
+
public static final class CalendarContract.EventDays implements android.provider.CalendarContract.EventDaysColumns {
method public static final android.database.Cursor query(android.content.ContentResolver, int, int, java.lang.String[]);
field public static final android.net.Uri CONTENT_URI;
@@ -15830,6 +15894,7 @@
field public static final java.lang.String AVAILABILITY = "availability";
field public static final int AVAILABILITY_BUSY = 0; // 0x0
field public static final int AVAILABILITY_FREE = 1; // 0x1
+ field public static final int AVAILABILITY_TENTATIVE = 2; // 0x2
field public static final java.lang.String CALENDAR_ID = "calendar_id";
field public static final java.lang.String CAN_INVITE_OTHERS = "canInviteOthers";
field public static final java.lang.String DESCRIPTION = "description";
@@ -15837,6 +15902,7 @@
field public static final java.lang.String DTSTART = "dtstart";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String EVENT_COLOR = "eventColor";
+ field public static final java.lang.String EVENT_COLOR_KEY = "eventColor_index";
field public static final java.lang.String EVENT_END_TIMEZONE = "eventEndTimezone";
field public static final java.lang.String EVENT_LOCATION = "eventLocation";
field public static final java.lang.String EVENT_TIMEZONE = "eventTimezone";
@@ -16572,6 +16638,10 @@
field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
+ public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String CONTENT_DIRECTORY = "stream_items";
+ }
+
protected static abstract interface ContactsContract.ContactsColumns {
field public static final java.lang.String DISPLAY_NAME = "display_name";
field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number";
@@ -16829,6 +16899,10 @@
field public static final java.lang.String DATA_ID = "data_id";
}
+ public static final class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String CONTENT_DIRECTORY = "stream_items";
+ }
+
protected static abstract interface ContactsContract.RawContactsColumns {
field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode";
field public static final java.lang.String CONTACT_ID = "contact_id";
@@ -16892,6 +16966,56 @@
field public static final android.net.Uri PROFILE_CONTENT_URI;
}
+ public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
+ field public static final java.lang.String PHOTO = "photo";
+ }
+
+ protected static abstract interface ContactsContract.StreamItemPhotosColumns {
+ field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id";
+ field public static final java.lang.String PHOTO_URI = "photo_uri";
+ field public static final java.lang.String SORT_INDEX = "sort_index";
+ field public static final java.lang.String STREAM_ITEM_ID = "stream_item_id";
+ field public static final java.lang.String SYNC1 = "stream_item_photo_sync1";
+ field public static final java.lang.String SYNC2 = "stream_item_photo_sync2";
+ field public static final java.lang.String SYNC3 = "stream_item_photo_sync3";
+ field public static final java.lang.String SYNC4 = "stream_item_photo_sync4";
+ }
+
+ public static final class ContactsContract.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item";
+ field public static final android.net.Uri CONTENT_LIMIT_URI;
+ field public static final android.net.Uri CONTENT_PHOTO_URI;
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String MAX_ITEMS = "max_items";
+ }
+
+ public static final class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
+ field public static final java.lang.String CONTENT_DIRECTORY = "photo";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
+ }
+
+ protected static abstract interface ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String ACCOUNT_NAME = "account_name";
+ field public static final java.lang.String ACCOUNT_TYPE = "account_type";
+ field public static final java.lang.String COMMENTS = "comments";
+ field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String CONTACT_LOOKUP_KEY = "contact_lookup";
+ field public static final java.lang.String DATA_SET = "data_set";
+ field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id";
+ field public static final java.lang.String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id";
+ field public static final java.lang.String RES_ICON = "icon";
+ field public static final java.lang.String RES_LABEL = "label";
+ field public static final java.lang.String RES_PACKAGE = "res_package";
+ field public static final java.lang.String SYNC1 = "stream_item_sync1";
+ field public static final java.lang.String SYNC2 = "stream_item_sync2";
+ field public static final java.lang.String SYNC3 = "stream_item_sync3";
+ field public static final java.lang.String SYNC4 = "stream_item_sync4";
+ field public static final java.lang.String TEXT = "text";
+ field public static final java.lang.String TIMESTAMP = "timestamp";
+ }
+
protected static abstract interface ContactsContract.SyncColumns implements android.provider.ContactsContract.BaseSyncColumns {
field public static final java.lang.String ACCOUNT_NAME = "account_name";
field public static final java.lang.String ACCOUNT_TYPE = "account_type";
@@ -16946,7 +17070,7 @@
field public static final java.lang.String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
field public static final java.lang.String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH";
field public static final java.lang.String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
- field public static final java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
+ field public static final deprecated java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
field public static final java.lang.String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
field public static final java.lang.String MEDIA_IGNORE_FILENAME = ".nomedia";
@@ -17309,6 +17433,7 @@
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
method public static final void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
+ field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
field public static final java.lang.String ADB_ENABLED = "adb_enabled";
field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
field public static final java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
@@ -18603,6 +18728,7 @@
method public android.os.Bundle getBundle();
method public java.lang.String getLocale();
method public void onCancel();
+ method public void onClose();
method public abstract void onCreate();
method public abstract android.view.textservice.SuggestionsInfo onGetSuggestions(android.view.textservice.TextInfo, int);
method public android.view.textservice.SuggestionsInfo[] onGetSuggestionsMultiple(android.view.textservice.TextInfo[], int, boolean);
@@ -18639,6 +18765,7 @@
method public void onSurfaceRedrawNeeded(android.view.SurfaceHolder);
method public void onTouchEvent(android.view.MotionEvent);
method public void onVisibilityChanged(boolean);
+ method public void setOffsetNotificationsEnabled(boolean);
method public void setTouchEventsEnabled(boolean);
}
@@ -18777,6 +18904,7 @@
method public boolean areDefaultsEnforced();
method public java.lang.String getDefaultEngine();
method public java.util.List<android.speech.tts.TextToSpeech.EngineInfo> getEngines();
+ method public java.util.Set<java.lang.String> getFeatures(java.util.Locale);
method public java.util.Locale getLanguage();
method public int isLanguageAvailable(java.util.Locale);
method public boolean isSpeaking();
@@ -18784,7 +18912,8 @@
method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
method public deprecated int setEngineByPackageName(java.lang.String);
method public int setLanguage(java.util.Locale);
- method public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+ method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+ method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
method public int setPitch(float);
method public int setSpeechRate(float);
method public void shutdown();
@@ -18822,6 +18951,8 @@
field public static final java.lang.String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
field public static final java.lang.String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
field public static final java.lang.String INTENT_ACTION_TTS_SERVICE = "android.intent.action.TTS_SERVICE";
+ field public static final java.lang.String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
+ field public static final java.lang.String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
field public static final java.lang.String KEY_PARAM_PAN = "pan";
field public static final java.lang.String KEY_PARAM_STREAM = "streamType";
field public static final java.lang.String KEY_PARAM_UTTERANCE_ID = "utteranceId";
@@ -18847,6 +18978,7 @@
public abstract class TextToSpeechService extends android.app.Service {
ctor public TextToSpeechService();
method public android.os.IBinder onBind(android.content.Intent);
+ method protected java.util.Set<java.lang.String> onGetFeaturesForLanguage(java.lang.String, java.lang.String, java.lang.String);
method protected abstract java.lang.String[] onGetLanguage();
method protected abstract int onIsLanguageAvailable(java.lang.String, java.lang.String, java.lang.String);
method protected abstract int onLoadLanguage(java.lang.String, java.lang.String, java.lang.String);
@@ -18854,6 +18986,13 @@
method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
}
+ public abstract class UtteranceProgressListener {
+ ctor public UtteranceProgressListener();
+ method public abstract void onDone(java.lang.String);
+ method public abstract void onError(java.lang.String);
+ method public abstract void onStart(java.lang.String);
+ }
+
}
package android.telephony {
@@ -21018,6 +21157,7 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int FLAG_AUTO_CORRECTION = 4; // 0x4
field public static final int FLAG_EASY_CORRECT = 1; // 0x1
field public static final int FLAG_MISSPELLED = 2; // 0x2
field public static final int SUGGESTIONS_MAX_SIZE = 5; // 0x5
@@ -22090,6 +22230,8 @@
field public static final int KEYCODE_BUTTON_Y = 100; // 0x64
field public static final int KEYCODE_BUTTON_Z = 101; // 0x65
field public static final int KEYCODE_C = 31; // 0x1f
+ field public static final int KEYCODE_CALCULATOR = 210; // 0xd2
+ field public static final int KEYCODE_CALENDAR = 208; // 0xd0
field public static final int KEYCODE_CALL = 5; // 0x5
field public static final int KEYCODE_CAMERA = 27; // 0x1b
field public static final int KEYCODE_CAPS_LOCK = 115; // 0x73
@@ -22098,6 +22240,7 @@
field public static final int KEYCODE_CHANNEL_UP = 166; // 0xa6
field public static final int KEYCODE_CLEAR = 28; // 0x1c
field public static final int KEYCODE_COMMA = 55; // 0x37
+ field public static final int KEYCODE_CONTACTS = 207; // 0xcf
field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
field public static final int KEYCODE_D = 32; // 0x20
@@ -22165,6 +22308,7 @@
field public static final int KEYCODE_MINUS = 69; // 0x45
field public static final int KEYCODE_MOVE_END = 123; // 0x7b
field public static final int KEYCODE_MOVE_HOME = 122; // 0x7a
+ field public static final int KEYCODE_MUSIC = 209; // 0xd1
field public static final int KEYCODE_MUTE = 91; // 0x5b
field public static final int KEYCODE_N = 42; // 0x2a
field public static final int KEYCODE_NOTIFICATION = 83; // 0x53
@@ -22814,6 +22958,7 @@
method public void buildDrawingCache();
method public void buildDrawingCache(boolean);
method public void buildLayer();
+ method public boolean callOnClick();
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
method public void cancelLongPress();
@@ -22965,6 +23110,7 @@
method public float getY();
method public boolean hasFocus();
method public boolean hasFocusable();
+ method public boolean hasOnClickListeners();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
method protected void initializeFadingEdge(android.content.res.TypedArray);
@@ -24082,6 +24228,8 @@
method public int getCurrentItemIndex();
method public int getFromIndex();
method public int getItemCount();
+ method public int getMaxScrollX();
+ method public int getMaxScrollY();
method public android.os.Parcelable getParcelableData();
method public int getRemovedCount();
method public int getScrollX();
@@ -24108,6 +24256,8 @@
method public void setFromIndex(int);
method public void setFullScreen(boolean);
method public void setItemCount(int);
+ method public void setMaxScrollX(int);
+ method public void setMaxScrollY(int);
method public void setParcelableData(android.os.Parcelable);
method public void setPassword(boolean);
method public void setRemovedCount(int);
@@ -24713,6 +24863,7 @@
}
public class SpellCheckerSession {
+ method public void cancel();
method public void close();
method public android.view.textservice.SpellCheckerInfo getSpellChecker();
method public void getSuggestions(android.view.textservice.TextInfo, int);
@@ -24749,6 +24900,7 @@
method public void setCookieAndSequence(int, int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4
field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
}
@@ -25018,7 +25170,7 @@
method public synchronized java.lang.String getFixedFontFamily();
method public synchronized boolean getJavaScriptCanOpenWindowsAutomatically();
method public synchronized boolean getJavaScriptEnabled();
- method public deprecated synchronized android.webkit.WebSettings.LayoutAlgorithm getLayoutAlgorithm();
+ method public synchronized android.webkit.WebSettings.LayoutAlgorithm getLayoutAlgorithm();
method public boolean getLightTouchEnabled();
method public boolean getLoadWithOverviewMode();
method public synchronized boolean getLoadsImagesAutomatically();
@@ -25065,7 +25217,7 @@
method public synchronized void setGeolocationEnabled(boolean);
method public synchronized void setJavaScriptCanOpenWindowsAutomatically(boolean);
method public synchronized void setJavaScriptEnabled(boolean);
- method public deprecated synchronized void setLayoutAlgorithm(android.webkit.WebSettings.LayoutAlgorithm);
+ method public synchronized void setLayoutAlgorithm(android.webkit.WebSettings.LayoutAlgorithm);
method public void setLightTouchEnabled(boolean);
method public void setLoadWithOverviewMode(boolean);
method public synchronized void setLoadsImagesAutomatically(boolean);
@@ -25100,12 +25252,12 @@
field public static final int LOAD_NO_CACHE = 2; // 0x2
}
- public static final deprecated class WebSettings.LayoutAlgorithm extends java.lang.Enum {
+ public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
- enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+ enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
}
public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -26770,6 +26922,7 @@
method public void setChar(int, java.lang.String, char);
method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
method public void setChronometer(int, long, java.lang.String, boolean);
+ method public void setContentDescription(int, java.lang.CharSequence);
method public void setDisplayedChild(int, int);
method public void setDouble(int, java.lang.String, double);
method public void setEmptyView(int, int);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 0ec007c..c0ba543 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -212,6 +212,7 @@
int getFlags = 0;
boolean listDisabled = false, listEnabled = false;
boolean listSystem = false, listThirdParty = false;
+ boolean listInstaller = false;
try {
String opt;
while ((opt=nextOption()) != null) {
@@ -229,6 +230,8 @@
listSystem = true;
} else if (opt.equals("-3")) {
listThirdParty = true;
+ } else if (opt.equals("-i")) {
+ listInstaller = true;
} else if (opt.equals("-u")) {
getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
} else {
@@ -265,7 +268,12 @@
System.out.print(info.applicationInfo.sourceDir);
System.out.print("=");
}
- System.out.println(info.packageName);
+ System.out.print(info.packageName);
+ if (listInstaller) {
+ System.out.print(" installer=");
+ System.out.print(mPm.getInstallerPackageName(info.packageName));
+ }
+ System.out.println();
}
}
} catch (RemoteException e) {
@@ -1109,7 +1117,7 @@
}
private static void showUsage() {
- System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]");
+ System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [FILTER]");
System.err.println(" pm list permission-groups");
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
@@ -1134,6 +1142,7 @@
System.err.println(" -e: filter to only show enabled packages.");
System.err.println(" -s: filter to only show system packages.");
System.err.println(" -3: filter to only show third party packages.");
+ System.err.println(" -i: see the installer for the packages.");
System.err.println(" -u: also include uninstalled packages.");
System.err.println("");
System.err.println("pm list permission-groups: prints all known permission groups.");
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 473a2d1..f427e78 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -181,7 +181,8 @@
*
* While the Fragment API was introduced in
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
- * is also available for use on older platforms. See the blog post
+ * at is also available for use on older platforms through
+ * {@link android.support.v4.app.FragmentActivity}. See the blog post
* <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
* Fragments For All</a> for more details.
*
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index a8c9cba..1abb7de 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -51,6 +51,13 @@
* <p>For more information about using fragments, read the
* <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
* </div>
+ *
+ * While the FragmentManager API was introduced in
+ * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
+ * at is also available for use on older platforms through
+ * {@link android.support.v4.app.FragmentActivity}. See the blog post
+ * <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
+ * Fragments For All</a> for more details.
*/
public abstract class FragmentManager {
/**
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 1b8a4f5..d83d2e6 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -36,7 +36,8 @@
*
* While the LoaderManager API was introduced in
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
- * is also available for use on older platforms. See the blog post
+ * at is also available for use on older platforms through
+ * {@link android.support.v4.app.FragmentActivity}. See the blog post
* <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
* Fragments For All</a> for more details.
*
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index d71a8d6..b609c26 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -28,11 +28,21 @@
/**
* Base class for code that will receive intents sent by sendBroadcast().
- * You can either dynamically register an instance of this class with
+ *
+ * <p>If you don't need to send broadcasts across applications, consider using
+ * this class with {@link android.support.v4.content.LocalBroadcastManager} instead
+ * of the more general facilities described below. This will give you a much
+ * more efficient implementation (no cross-process communication needed) and allow
+ * you to avoid thinking about any security issues related to other applications
+ * being able to receive or send your broadcasts.
+ *
+ * <p>You can either dynamically register an instance of this class with
* {@link Context#registerReceiver Context.registerReceiver()}
* or statically publish an implementation through the
* {@link android.R.styleable#AndroidManifestReceiver <receiver>}
- * tag in your <code>AndroidManifest.xml</code>. <em><strong>Note:</strong></em>
+ * tag in your <code>AndroidManifest.xml</code>.
+ *
+ * <p><em><strong>Note:</strong></em>
* If registering a receiver in your
* {@link android.app.Activity#onResume() Activity.onResume()}
* implementation, you should unregister it in
@@ -86,8 +96,8 @@
*
* <p>Topics covered here:
* <ol>
+ * <li><a href="#Security">Security</a>
* <li><a href="#ReceiverLifecycle">Receiver Lifecycle</a>
- * <li><a href="#Permissions">Permissions</a>
* <li><a href="#ProcessLifecycle">Process Lifecycle</a>
* </ol>
*
@@ -98,6 +108,63 @@
* developer guide.</p>
* </div>
*
+ * <a name="Security"></a>
+ * <h3>Security</h3>
+ *
+ * <p>Receivers used with the {@link Context} APIs are by their nature a
+ * cross-application facility, so you must consider how other applications
+ * may be able to abuse your use of them. Some things to consider are:
+ *
+ * <ul>
+ * <li><p>The Intent namespace is global. Make sure that Intent action names and
+ * other strings are written in a namespace you own, or else you may inadvertantly
+ * conflict with other applications.
+ * <li><p>When you use {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)},
+ * <em>any</em> application may send broadcasts to that registered receiver. You can
+ * control who can send broadcasts to it through permissions described below.
+ * <li><p>When you publish a receiver in your application's manifest and specify
+ * intent-filters for it, any other application can send broadcasts to it regardless
+ * of the filters you specify. To prevent others from sending to it, make it
+ * unavailable to them with <code>android:exported="false"</code>.
+ * <li><p>When you use {@link Context#sendBroadcast(Intent)} or related methods,
+ * normally any other application can receive these broadcasts. You can control who
+ * can receive such broadcasts through permissions described below. Alternatively,
+ * starting with {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, you
+ * can also safely restrict the broadcast to a single application with
+ * {@link Intent#setPackage(String) Intent.setPackage}
+ * </ul>
+ *
+ * <p>None of these issues exist when using
+ * {@link android.support.v4.content.LocalBroadcastManager}, since intents
+ * broadcast it never go outside of the current process.
+ *
+ * <p>Access permissions can be enforced by either the sender or receiver
+ * of a broadcast.
+ *
+ * <p>To enforce a permission when sending, you supply a non-null
+ * <var>permission</var> argument to
+ * {@link Context#sendBroadcast(Intent, String)} or
+ * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)}.
+ * Only receivers who have been granted this permission
+ * (by requesting it with the
+ * {@link android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
+ * tag in their <code>AndroidManifest.xml</code>) will be able to receive
+ * the broadcast.
+ *
+ * <p>To enforce a permission when receiving, you supply a non-null
+ * <var>permission</var> when registering your receiver -- either when calling
+ * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)}
+ * or in the static
+ * {@link android.R.styleable#AndroidManifestReceiver <receiver>}
+ * tag in your <code>AndroidManifest.xml</code>. Only broadcasters who have
+ * been granted this permission (by requesting it with the
+ * {@link android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
+ * tag in their <code>AndroidManifest.xml</code>) will be able to send an
+ * Intent to the receiver.
+ *
+ * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
+ * document for more information on permissions and security in general.
+ *
* <a name="ReceiverLifecycle"></a>
* <h3>Receiver Lifecycle</h3>
*
@@ -117,37 +184,7 @@
* {@link android.app.NotificationManager} API. For the latter, you can
* use {@link android.content.Context#startService Context.startService()} to
* send a command to the service.
- *
- * <a name="Permissions"></a>
- * <h3>Permissions</h3>
- *
- * <p>Access permissions can be enforced by either the sender or receiver
- * of an Intent.
- *
- * <p>To enforce a permission when sending, you supply a non-null
- * <var>permission</var> argument to
- * {@link Context#sendBroadcast(Intent, String)} or
- * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)}.
- * Only receivers who have been granted this permission
- * (by requesting it with the
- * {@link android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
- * tag in their <code>AndroidManifest.xml</code>) will be able to receive
- * the broadcast.
- *
- * <p>To enforce a permission when receiving, you supply a non-null
- * <var>permission</var> when registering your receiver -- either when calling
- * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)}
- * or in the static
- * {@link android.R.styleable#AndroidManifestReceiver <receiver>}
- * tag in your <code>AndroidManifest.xml</code>. Only broadcasters who have
- * been granted this permission (by requesting it with the
- * {@link android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
- * tag in their <code>AndroidManifest.xml</code>) will be able to send an
- * Intent to the receiver.
- *
- * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
- * document for more information on permissions and security in general.
- *
+ *
* <a name="ProcessLifecycle"></a>
* <h3>Process Lifecycle</h3>
*
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 2d2a90d..ac05682 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -58,6 +58,13 @@
boolean mReset = true;
boolean mContentChanged = false;
+ /**
+ * An implementation of a ContentObserver that takes care of connecting
+ * it to the Loader to have the loader re-load its data when the observer
+ * is told it has changed. You do not normally need to use this yourself;
+ * it is used for you by {@link CursorLoader} to take care of executing
+ * an update when the cursor's backing data changes.
+ */
public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
super(new Handler());
@@ -74,6 +81,14 @@
}
}
+ /**
+ * Interface that is implemented to discover when a Loader has finished
+ * loading its data. You do not normally need to implement this yourself;
+ * it is used in the implementation of {@link android.app.LoaderManager}
+ * to find out when a Loader it is managing has completed so that this can
+ * be reported to its client. This interface should only be used if a
+ * Loader is not being used in conjunction with LoaderManager.
+ */
public interface OnLoadCompleteListener<D> {
/**
* Called on the thread that created the Loader when the load is complete.
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index f4a390e..ed59b03 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -360,13 +360,13 @@
boolean retValue = HANDLED;
switch(message.what) {
case USER_TURN_ON:
+ broadcastState(BluetoothAdapter.STATE_TURNING_ON);
if ((Boolean) message.obj) {
persistSwitchSetting(true);
}
// let it fall to TURN_ON_CONTINUE:
//$FALL-THROUGH$
case TURN_ON_CONTINUE:
- broadcastState(BluetoothAdapter.STATE_TURNING_ON);
mBluetoothService.switchConnectable(true);
transitionTo(mSwitching);
break;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index b73d900..303a30e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -59,6 +59,12 @@
private boolean mCharsValid;
private Spanned mSpanned;
private final TextPaint mWorkPaint = new TextPaint();
+ private final SpanSet<MetricAffectingSpan> mMetricAffectingSpanSpanSet =
+ new SpanSet<MetricAffectingSpan>(MetricAffectingSpan.class);
+ private final SpanSet<CharacterStyle> mCharacterStyleSpanSet =
+ new SpanSet<CharacterStyle>(CharacterStyle.class);
+ private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet =
+ new SpanSet<ReplacementSpan>(ReplacementSpan.class);
private static final TextLine[] sCached = new TextLine[3];
@@ -96,6 +102,11 @@
tl.mText = null;
tl.mPaint = null;
tl.mDirections = null;
+
+ tl.mMetricAffectingSpanSpanSet.recycle();
+ tl.mCharacterStyleSpanSet.recycle();
+ tl.mReplacementSpanSpanSet.recycle();
+
synchronized(sCached) {
for (int i = 0; i < sCached.length; ++i) {
if (sCached[i] == null) {
@@ -119,7 +130,6 @@
* @param hasTabs true if the line might contain tabs or emoji
* @param tabStops the tabStops. Can be null.
*/
- @SuppressWarnings("null")
void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
Directions directions, boolean hasTabs, TabStops tabStops) {
mPaint = paint;
@@ -135,12 +145,10 @@
mSpanned = null;
boolean hasReplacement = false;
- SpanSet<ReplacementSpan> replacementSpans = null;
if (text instanceof Spanned) {
mSpanned = (Spanned) text;
- replacementSpans = new SpanSet<ReplacementSpan>(mSpanned, start, limit,
- ReplacementSpan.class);
- hasReplacement = replacementSpans.numberOfSpans > 0;
+ mReplacementSpanSpanSet.init(mSpanned, start, limit);
+ hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0;
}
mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
@@ -158,9 +166,8 @@
// zero-width characters.
char[] chars = mChars;
for (int i = start, inext; i < limit; i = inext) {
- // replacementSpans cannot be null if hasReplacement is true
- inext = replacementSpans.getNextTransition(i, limit);
- if (replacementSpans.hasSpansIntersecting(i, inext)) {
+ inext = mReplacementSpanSpanSet.getNextTransition(i, limit);
+ if (mReplacementSpanSpanSet.hasSpansIntersecting(i, inext)) {
// transition into a span
chars[i - start] = '\ufffc';
for (int j = i - start + 1, e = inext - start; j < e; ++j) {
@@ -854,21 +861,30 @@
}
private static class SpanSet<E> {
- final int numberOfSpans;
- final E[] spans;
- final int[] spanStarts;
- final int[] spanEnds;
- final int[] spanFlags;
+ int numberOfSpans;
+ E[] spans;
+ int[] spanStarts;
+ int[] spanEnds;
+ int[] spanFlags;
+ final Class<? extends E> classType;
+
+ SpanSet(Class<? extends E> type) {
+ classType = type;
+ numberOfSpans = 0;
+ }
@SuppressWarnings("unchecked")
- SpanSet(Spanned spanned, int start, int limit, Class<? extends E> type) {
- final E[] allSpans = spanned.getSpans(start, limit, type);
+ public void init(Spanned spanned, int start, int limit) {
+ final E[] allSpans = spanned.getSpans(start, limit, classType);
final int length = allSpans.length;
- // These arrays may end up being too large because of empty spans
- spans = (E[]) Array.newInstance(type, length);
- spanStarts = new int[length];
- spanEnds = new int[length];
- spanFlags = new int[length];
+
+ if (length > 0 && (spans == null || spans.length < length)) {
+ // These arrays may end up being too large because of empty spans
+ spans = (E[]) Array.newInstance(classType, length);
+ spanStarts = new int[length];
+ spanEnds = new int[length];
+ spanFlags = new int[length];
+ }
int count = 0;
for (int i = 0; i < length; i++) {
@@ -879,30 +895,11 @@
if (spanStart == spanEnd) continue;
final int spanFlag = spanned.getSpanFlags(span);
- final int priority = spanFlag & Spanned.SPAN_PRIORITY;
- if (priority != 0 && count != 0) {
- int j;
- for (j = 0; j < count; j++) {
- final int otherPriority = spanFlags[j] & Spanned.SPAN_PRIORITY;
- if (priority > otherPriority) break;
- }
-
- System.arraycopy(spans, j, spans, j + 1, count - j);
- System.arraycopy(spanStarts, j, spanStarts, j + 1, count - j);
- System.arraycopy(spanEnds, j, spanEnds, j + 1, count - j);
- System.arraycopy(spanFlags, j, spanFlags, j + 1, count - j);
-
- spans[j] = span;
- spanStarts[j] = spanStart;
- spanEnds[j] = spanEnd;
- spanFlags[j] = spanFlag;
- } else {
- spans[i] = span;
- spanStarts[i] = spanStart;
- spanEnds[i] = spanEnd;
- spanFlags[i] = spanFlag;
- }
+ spans[i] = span;
+ spanStarts[i] = spanStart;
+ spanEnds[i] = spanEnd;
+ spanFlags[i] = spanFlag;
count++;
}
@@ -927,6 +924,12 @@
}
return limit;
}
+
+ public void recycle() {
+ for (int i = 0; i < numberOfSpans; i++) {
+ spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled
+ }
+ }
}
/**
@@ -970,10 +973,8 @@
y, bottom, fmi, needWidth || mlimit < measureLimit);
}
- final SpanSet<MetricAffectingSpan> metricAffectingSpans = new SpanSet<MetricAffectingSpan>(
- mSpanned, mStart + start, mStart + limit, MetricAffectingSpan.class);
- final SpanSet<CharacterStyle> characterStyleSpans = new SpanSet<CharacterStyle>(
- mSpanned, mStart + start, mStart + limit, CharacterStyle.class);
+ mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
+ mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);
// Shaping needs to take into account context up to metric boundaries,
// but rendering needs to take into account character style boundaries.
@@ -985,17 +986,18 @@
TextPaint wp = mWorkPaint;
wp.set(mPaint);
- inext = metricAffectingSpans.getNextTransition(mStart + i, mStart + limit) - mStart;
+ inext = mMetricAffectingSpanSpanSet.getNextTransition(mStart + i, mStart + limit) -
+ mStart;
int mlimit = Math.min(inext, measureLimit);
ReplacementSpan replacement = null;
- for (int j = 0; j < metricAffectingSpans.numberOfSpans; j++) {
+ for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
// Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT
// empty by construction. This special case in getSpans() explains the >= & <= tests
- if ((metricAffectingSpans.spanStarts[j] >= mStart + mlimit) ||
- (metricAffectingSpans.spanEnds[j] <= mStart + i)) continue;
- MetricAffectingSpan span = metricAffectingSpans.spans[j];
+ if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) ||
+ (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue;
+ MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
if (span instanceof ReplacementSpan) {
replacement = (ReplacementSpan)span;
} else {
@@ -1016,16 +1018,16 @@
y, bottom, fmi, needWidth || mlimit < measureLimit);
} else {
for (int j = i, jnext; j < mlimit; j = jnext) {
- jnext = characterStyleSpans.getNextTransition(mStart + j, mStart + mlimit) -
+ jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) -
mStart;
wp.set(mPaint);
- for (int k = 0; k < characterStyleSpans.numberOfSpans; k++) {
+ for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
// Intentionally using >= and <= as explained above
- if ((characterStyleSpans.spanStarts[k] >= mStart + jnext) ||
- (characterStyleSpans.spanEnds[k] <= mStart + j)) continue;
+ if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) ||
+ (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue;
- CharacterStyle span = characterStyleSpans.spans[k];
+ CharacterStyle span = mCharacterStyleSpanSet.spans[k];
span.updateDrawState(wp);
}
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 5ae65df..121c6f2 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -21,7 +21,7 @@
/**
* Utility class to aid in formatting common values that are not covered
- * by {@link java.util.Formatter}
+ * by the {@link java.util.Formatter} class in {@link java.util}
*/
public final class Formatter {
diff --git a/core/java/android/text/format/package.html b/core/java/android/text/format/package.html
new file mode 100644
index 0000000..b9e6a44
--- /dev/null
+++ b/core/java/android/text/format/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+This package contains alternative classes for some text formatting classes
+defined in {@link java.util} and {@link java.text}. It also contains additional text formatting
+classes for situations not covered by {@link java.util} or {@link java.text}.
+</BODY>
+</HTML>
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1102a47..0d34b90 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4190,10 +4190,10 @@
* {@inheritDoc}
*/
public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
- // The View is not attached to a window, 'visible' does not make sense, return false
- if (mAttachInfo == null) return false;
-
- final RectF rect = mAttachInfo.mTmpTransformRect;
+ // It doesn't make a whole lot of sense to call this on a view that isn't attached,
+ // but for some simple tests it can be useful. If we don't have attach info this
+ // will allocate memory.
+ final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
rect.set(r);
if (!child.hasIdentityMatrix()) {
@@ -4207,7 +4207,8 @@
if (offset != null) {
if (!child.hasIdentityMatrix()) {
- float[] position = mAttachInfo.mTmpTransformLocation;
+ float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
+ : new float[2];
position[0] = offset.x;
position[1] = offset.y;
child.getMatrix().mapPoints(position);
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 31da5b5..e9a2644 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -45,14 +45,15 @@
// No more than this number of words will be parsed on each iteration to ensure a minimum
// lock of the UI thread
- public static final int MAX_NUMBER_OF_WORDS = 10;
+ public static final int MAX_NUMBER_OF_WORDS = 50;
- // Safe estimate, will ensure that the interval below usually does not have to be updated
- public static final int AVERAGE_WORD_LENGTH = 10;
+ // Rough estimate, such that the word iterator interval usually does not need to be shifted
+ public static final int AVERAGE_WORD_LENGTH = 7;
// When parsing, use a character window of that size. Will be shifted if needed
public static final int WORD_ITERATOR_INTERVAL = AVERAGE_WORD_LENGTH * MAX_NUMBER_OF_WORDS;
+ // Pause between each spell check to keep the UI smooth
private final static int SPELL_PAUSE_DURATION = 400; // milliseconds
private final TextView mTextView;
@@ -75,6 +76,14 @@
private Locale mCurrentLocale;
+ // Shared by all SpellParsers. Cannot be shared with TextView since it may be used
+ // concurrently due to the asynchronous nature of onGetSuggestions.
+ private WordIterator mWordIterator;
+
+ private TextServicesManager mTextServicesManager;
+
+ private Runnable mSpellRunnable;
+
public SpellChecker(TextView textView) {
mTextView = textView;
@@ -136,6 +145,10 @@
for (int i = 0; i < length; i++) {
mSpellParsers[i].stop();
}
+
+ if (mSpellRunnable != null) {
+ mTextView.removeCallbacks(mSpellRunnable);
+ }
}
private int nextSpellCheckSpanIndex() {
@@ -285,18 +298,29 @@
}
}
- mTextView.postDelayed(new Runnable() {
- @Override
- public void run() {
- final int length = mSpellParsers.length;
- for (int i = 0; i < length; i++) {
- final SpellParser spellParser = mSpellParsers[i];
- if (spellParser.isParsing()) {
- spellParser.parse();
+ scheduleNewSpellCheck();
+ }
+
+ private void scheduleNewSpellCheck() {
+ if (mSpellRunnable == null) {
+ mSpellRunnable = new Runnable() {
+ @Override
+ public void run() {
+ final int length = mSpellParsers.length;
+ for (int i = 0; i < length; i++) {
+ final SpellParser spellParser = mSpellParsers[i];
+ if (!spellParser.isParsing()) {
+ spellParser.parse();
+ break; // run one spell parser at a time to bound running time
+ }
}
}
- }
- }, SPELL_PAUSE_DURATION);
+ };
+ } else {
+ mTextView.removeCallbacks(mSpellRunnable);
+ }
+
+ mTextView.postDelayed(mSpellRunnable, SPELL_PAUSE_DURATION);
}
private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
@@ -361,7 +385,7 @@
SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- mTextView.invalidateRegion(start, end);
+ mTextView.invalidateRegion(start, end, false /* No cursor involved */);
}
private class SpellParser {
@@ -393,20 +417,19 @@
final int start = editable.getSpanStart(mRange);
final int end = editable.getSpanEnd(mRange);
- final WordIterator wordIterator = mTextView.getWordIterator();
int wordIteratorWindowEnd = Math.min(end, start + WORD_ITERATOR_INTERVAL);
- wordIterator.setCharSequence(editable, start, wordIteratorWindowEnd);
+ mWordIterator.setCharSequence(editable, start, wordIteratorWindowEnd);
// Move back to the beginning of the current word, if any
- int wordStart = wordIterator.preceding(start);
+ int wordStart = mWordIterator.preceding(start);
int wordEnd;
if (wordStart == BreakIterator.DONE) {
- wordEnd = wordIterator.following(start);
+ wordEnd = mWordIterator.following(start);
if (wordEnd != BreakIterator.DONE) {
- wordStart = wordIterator.getBeginning(wordEnd);
+ wordStart = mWordIterator.getBeginning(wordEnd);
}
} else {
- wordEnd = wordIterator.getEnd(wordStart);
+ wordEnd = mWordIterator.getEnd(wordStart);
}
if (wordEnd == BreakIterator.DONE) {
removeRangeSpan(editable);
@@ -472,15 +495,15 @@
// iterate word by word
int originalWordEnd = wordEnd;
- wordEnd = wordIterator.following(wordEnd);
+ wordEnd = mWordIterator.following(wordEnd);
if ((wordIteratorWindowEnd < end) &&
(wordEnd == BreakIterator.DONE || wordEnd >= wordIteratorWindowEnd)) {
wordIteratorWindowEnd = Math.min(end, originalWordEnd + WORD_ITERATOR_INTERVAL);
- wordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd);
- wordEnd = wordIterator.following(originalWordEnd);
+ mWordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd);
+ wordEnd = mWordIterator.following(originalWordEnd);
}
if (wordEnd == BreakIterator.DONE) break;
- wordStart = wordIterator.getBeginning(wordEnd);
+ wordStart = mWordIterator.getBeginning(wordEnd);
if (wordStart == BreakIterator.DONE) {
break;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5b73a74..66fd06d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -339,7 +339,7 @@
private int mCursorDrawableRes;
private final Drawable[] mCursorDrawable = new Drawable[2];
- private int mCursorCount; // Actual current number of used mCursorDrawable: 0, 1 or 2
+ private int mCursorCount; // Actual current number of used mCursorDrawable: 0, 1 or 2 (split)
private Drawable mSelectHandleLeft;
private Drawable mSelectHandleRight;
@@ -3210,7 +3210,6 @@
}
boolean needEditableForNotification = false;
- boolean startSpellCheck = false;
if (mListeners != null && mListeners.size() != 0) {
needEditableForNotification = true;
@@ -3222,7 +3221,6 @@
setFilters(t, mFilters);
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
- startSpellCheck = true;
} else if (type == BufferType.SPANNABLE || mMovement != null) {
text = mSpannableFactory.newSpannable(text);
} else if (!(text instanceof CharWrapper)) {
@@ -3311,11 +3309,6 @@
sendOnTextChanged(text, 0, oldlen, textLength);
onTextChanged(text, 0, oldlen, textLength);
- if (startSpellCheck && mSpellChecker != null) {
- // This view has to have been previously attached for mSpellChecker to exist
- updateSpellCheckSpans(0, textLength);
- }
-
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
}
@@ -4329,7 +4322,7 @@
if (a >= 0 || b >= 0 || c >= 0) {
int start = Math.min(Math.min(a, b), c);
int end = Math.max(Math.max(a, b), c);
- invalidateRegion(start, end);
+ invalidateRegion(start, end, true /* Also invalidates blinking cursor */);
}
}
@@ -4338,7 +4331,7 @@
*
* @hide
*/
- void invalidateRegion(int start, int end) {
+ void invalidateRegion(int start, int end, boolean invalidateCursor) {
if (mLayout == null) {
invalidate();
} else {
@@ -4364,11 +4357,19 @@
int bottom = mLayout.getLineBottom(lineEnd);
+ if (invalidateCursor) {
+ for (int i = 0; i < mCursorCount; i++) {
+ Rect bounds = mCursorDrawable[i].getBounds();
+ top = Math.min(top, bounds.top);
+ bottom = Math.max(bottom, bounds.bottom);
+ }
+ }
+
final int compoundPaddingLeft = getCompoundPaddingLeft();
final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true);
int left, right;
- if (lineStart == lineEnd) {
+ if (lineStart == lineEnd && !invalidateCursor) {
left = (int) mLayout.getPrimaryHorizontal(start);
right = (int) (mLayout.getPrimaryHorizontal(end) + 1.0);
left += compoundPaddingLeft;
@@ -4482,8 +4483,8 @@
// Resolve drawables as the layout direction has been resolved
resolveDrawables();
-
- updateSpellCheckSpans(0, mText.length());
+
+ updateSpellCheckSpans(0, mText.length(), true /* create the spell checker if needed */);
}
@Override
@@ -7636,7 +7637,7 @@
}
}
- updateSpellCheckSpans(start, start + after);
+ updateSpellCheckSpans(start, start + after, false);
// Hide the controllers as soon as text is modified (typing, procedural...)
// We do not hide the span controllers, since they can be added when a new text is
@@ -7794,17 +7795,22 @@
}
}
- if (newStart < 0 && what instanceof SpellCheckSpan) {
- getSpellChecker().removeSpellCheckSpan((SpellCheckSpan) what);
+ if (mSpellChecker != null && newStart < 0 && what instanceof SpellCheckSpan) {
+ mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what);
}
}
/**
* Create new SpellCheckSpans on the modified region.
*/
- private void updateSpellCheckSpans(int start, int end) {
+ private void updateSpellCheckSpans(int start, int end, boolean createSpellChecker) {
if (isTextEditable() && isSuggestionsEnabled()) {
- getSpellChecker().spellCheck(start, end);
+ if (mSpellChecker == null && createSpellChecker) {
+ mSpellChecker = new SpellChecker(this);
+ }
+ if (mSpellChecker != null) {
+ mSpellChecker.spellCheck(start, end);
+ }
}
}
@@ -8976,13 +8982,6 @@
return packRangeInLong(offset, offset);
}
- private SpellChecker getSpellChecker() {
- if (mSpellChecker == null) {
- mSpellChecker = new SpellChecker(this);
- }
- return mSpellChecker;
- }
-
private long getLastTouchOffsets() {
SelectionModifierCursorController selectionController = getSelectionController();
final int minOffset = selectionController.getMinTouchOffset();
@@ -9937,7 +9936,7 @@
// There is no way to know if the word was indeed added. Re-check.
// TODO The ExtractEditText should remove the span in the original text instead
editable.removeSpan(suggestionInfo.suggestionSpan);
- updateSpellCheckSpans(spanStart, spanEnd);
+ updateSpellCheckSpans(spanStart, spanEnd, false);
} else {
// SuggestionSpans are removed by replace: save them before
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
index c65dd83..0b94fc1 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
@@ -93,17 +93,6 @@
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip">
- <Button android:id="@+id/ok"
- android:text="@android:string/ok"
- android:layout_alignParentBottom="true"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1.0"
- android:layout_marginBottom="8dip"
- android:layout_marginRight="8dip"
- android:textSize="18sp"
- />
-
<Button android:id="@+id/emergencyCallButton"
android:text="@android:string/lockscreen_emergency_call"
android:layout_alignParentBottom="true"
@@ -112,11 +101,22 @@
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
android:textSize="18sp"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
+
+ <Button android:id="@+id/ok"
+ android:text="@android:string/ok"
+ android:layout_alignParentBottom="true"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:layout_marginBottom="8dip"
+ android:layout_marginLeft="8dip"
+ android:textSize="18sp"
+ />
</LinearLayout>
</RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
index 59065e1..3cb19c3 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
@@ -91,17 +91,6 @@
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip">
- <Button android:id="@+id/ok"
- android:text="@android:string/ok"
- android:layout_alignParentBottom="true"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1.0"
- android:layout_marginBottom="8dip"
- android:layout_marginRight="8dip"
- android:textSize="18sp"
- />
-
<Button android:id="@+id/emergencyCallButton"
android:text="@android:string/lockscreen_emergency_call"
android:layout_alignParentBottom="true"
@@ -110,11 +99,22 @@
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
android:textSize="18sp"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="4dip"
/>
+
+ <Button android:id="@+id/ok"
+ android:text="@android:string/ok"
+ android:layout_alignParentBottom="true"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:layout_marginBottom="8dip"
+ android:layout_marginLeft="8dip"
+ android:textSize="18sp"
+ />
</LinearLayout>
</RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
index b662e82..722dc26 100644
--- a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
@@ -153,17 +153,6 @@
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip">
- <Button android:id="@+id/ok"
- android:text="@android:string/ok"
- android:layout_alignParentBottom="true"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1.0"
- android:layout_marginBottom="8dip"
- android:layout_marginRight="8dip"
- android:textSize="18sp"
- />
-
<Button android:id="@+id/emergencyCallButton"
android:text="@android:string/lockscreen_emergency_call"
android:layout_alignParentBottom="true"
@@ -172,11 +161,22 @@
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
android:textSize="18sp"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="4dip"
/>
+
+ <Button android:id="@+id/ok"
+ android:text="@android:string/ok"
+ android:layout_alignParentBottom="true"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:layout_marginBottom="8dip"
+ android:layout_marginLeft="8dip"
+ android:textSize="18sp"
+ />
</LinearLayout>
</RelativeLayout>
diff --git a/core/res/res/layout/twelve_key_entry.xml b/core/res/res/layout/twelve_key_entry.xml
index 46301cd..09c749d 100644
--- a/core/res/res/layout/twelve_key_entry.xml
+++ b/core/res/res/layout/twelve_key_entry.xml
@@ -144,7 +144,7 @@
android:layout_marginRight="2dip"
android:orientation="horizontal">
- <Button android:id="@+id/ok"
+ <Button android:id="@+id/cancel"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
@@ -152,7 +152,7 @@
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
- android:text="@android:string/ok"
+ android:text="@android:string/cancel"
/>
<Button android:id="@+id/zero"
@@ -165,7 +165,7 @@
android:textStyle="bold"
/>
- <Button android:id="@+id/cancel"
+ <Button android:id="@+id/ok"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
@@ -173,7 +173,7 @@
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
- android:text="@android:string/cancel"
+ android:text="@android:string/ok"
/>
</LinearLayout>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
index e22b018..e44023b 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
@@ -271,4 +271,46 @@
}
+ // Test case 6: test configured network status
+ @LargeTest
+ public void testWifiConfiguredNetworkStatus() {
+
+ /* Initialize */
+ mWifiManager.setWifiEnabled(false);
+ sleepAfterWifiEnable();
+
+ /* Ensure no network is CURRENT */
+ List<WifiConfiguration> configList = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration c : configList) {
+ assertTrue(c.status != WifiConfiguration.Status.CURRENT);
+ }
+
+ /* Enable wifi */
+ mWifiManager.setWifiEnabled(true);
+ sleepAfterWifiEnable();
+
+ /* Ensure connected network is CURRENT */
+ String connectedSSID = mWifiManager.getConnectionInfo().getSSID();
+ configList = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration c : configList) {
+ if (c.SSID.contains(connectedSSID)) {
+ assertTrue(c.status == WifiConfiguration.Status.CURRENT);
+ } else {
+ assertTrue(c.status != WifiConfiguration.Status.CURRENT);
+ }
+ }
+
+ /* Disable wifi */
+ mWifiManager.setWifiEnabled(false);
+ sleepAfterWifiEnable();
+
+ /* Ensure no network is CURRENT */
+ configList = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration c : configList) {
+ assertTrue(c.status != WifiConfiguration.Status.CURRENT);
+ }
+ }
+
+
+
}
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index e886bdf..7161b03 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -65,26 +65,42 @@
<p>To determine what revision of the Android {@sdkPlatformVersion} platform you
have installed, refer to the "Installed Packages" listing in the Android SDK Manager.</p>
+<p class="caution"><strong>Important:</strong> To download the new Android
+4.0 system components from the Android SDK Manager, you must first update the
+SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
+the Android 4.0 system components will not be available for download.</p>
<div class="toggle-content opened" style="padding-left:1em;">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png"
class="toggle-content-img" alt="" />
+ Android {@sdkPlatformVersion}, Revision 2</a> <em>(December 2011)</em>
+ </a></p>
+
+ <div class="toggle-content-toggleme" style="padding-left:2em;">
+ <p>Maintenance update. The system version is 4.0.2.</p>
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>SDK Tools r14 or higher is required.</dd>
+ </dl>
+ </div>
+</div>
+
+<div class="toggle-content closed" style="padding-left:1em;">
+
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png"
+class="toggle-content-img" alt="" />
Android {@sdkPlatformVersion}, Revision 1</a> <em>(October 2011)</em>
</a></p>
<div class="toggle-content-toggleme" style="padding-left:2em;">
-
-<dl>
-<dt>Initial release. SDK Tools r14 or higher is required.
- <p class="caution"><strong>Important:</strong> To download the new Android
- 4.0 system components from the Android SDK Manager, you must first update the
- SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
- the Android 4.0 system components will not be available for download.</p>
-</dt>
-</dl>
-
+ <p>Initial release. The system version is 4.0.1.</p>
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>SDK Tools r14 or higher is required.</dd>
+ </dl>
</div>
</div>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 50b20ce..2445bff 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -1,8 +1,8 @@
page.title=ADT Plugin for Eclipse
-adt.zip.version=15.0.1
-adt.zip.download=ADT-15.0.1.zip
-adt.zip.bytes=6752327
-adt.zip.checksum=2c12a71d7124aa512b8ee016e19c0e69
+adt.zip.version=16.0.0
+adt.zip.download=ADT-16.0.0.zip
+adt.zip.bytes=6999205
+adt.zip.checksum=b7e512572580291279469845386b31b6
@jd:body
@@ -109,18 +109,49 @@
</style>
-
<div class="toggleable opened">
<a href="#" onclick="return toggleDiv(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
width="9px" />
+ADT 16.0.0</a> <em>(December 2011)</em>
+ <div class="toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Eclipse Helios (Version 3.6) or higher is required for ADT
+16.0.0.</li>
+ <li>ADT 16.0.0 is designed for use with <a
+href="{@docRoot}sdk/tools-notes.html">SDK Tools r16</a>. If you haven't already installed SDK Tools
+r16 into your SDK, use the Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General improvements:</dt>
+ <dd>
+ <ul>
+ <li>Added Lint tools to detect common errors in Android projects. (<a
+href="http://tools.android.com/recent/lint">more info</a>)</li>
+ </ul>
+ </dd>
+</dl>
+
+</div>
+</div>
+
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+width="9px" />
ADT 15.0.1</a> <em>(November 2011)</em>
<div class="toggleme">
<dl>
<dt>Dependencies:</dt>
<dd>ADT 15.0.1 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r15</a>.
- If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK and AVD Manager to
+ If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
do so.</dd>
<dt>Bug fixes:</dt>
@@ -154,7 +185,7 @@
<dt>Dependencies:</dt>
<dd>ADT 15.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r15</a>.
-If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK and AVD Manager to
+If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
do so.</dd>
<dt>Bug fixes:</dt>
@@ -185,10 +216,10 @@
<dt>Dependencies:</dt>
<dd>ADT 14.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r14</a>.
-If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK and AVD Manager to
+If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK Manager to
do so.</dd>
-<dt>Build system</dt>
+<dt>Build system:</dt>
<dd>
<ul>
<li>Changed <code>default.properties</code> to <code>project.properties</code> and
@@ -211,7 +242,7 @@
site</a>.</p>
</dd>
-<dt>General improvements</dt>
+<dt>General improvements:</dt>
<dd>
<ul>
@@ -236,7 +267,7 @@
</ul>
</dd>
-<dt>XML and Java editors</dt>
+<dt>XML and Java editors:</dt>
<dd>
<ul>
<li>Added a new XML formatter that formats all XML files according to the
@@ -255,7 +286,7 @@
</ul>
</dd>
-<dt>Layout editor</dt>
+<dt>Layout editor:</dt>
<dd>
<ul>
<li>Added tooltip feedback for dragging and resizing operations. For
@@ -281,7 +312,7 @@
</ul>
</dd>
-<dt>Bug fixes</dt>
+<dt>Bug fixes:</dt>
<dd>Fixed many bugs and added <a
href="http://tools.android.com/recent/miscellaneousrecentfixes">minor improvements</a>, in
particular some <a href="http://tools.android.com/recent/linuxfixes">critical bug fixes on
@@ -324,7 +355,7 @@
</ul>
</dd>
-<dt>Build system</dt>
+<dt>Build system:</dt>
<dd>
<ul>
<li id="build-option">A new option lets you disable the packaging step in the automatic
@@ -336,7 +367,7 @@
</ul>
</dd>
-<dt>Bug fixes</dt>
+<dt>Bug fixes:</dt>
<dd>Many bug fixes are part of this release
(<a href="http://tools.android.com/recent/adt12bugfixroundup">more info</a>).</dd>
@@ -928,7 +959,7 @@
see <a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p>
</dd>
-<dt>General Notes:</dt>
+<dt>General notes:</dt>
<dd>
<ul>
<li>AVD Launch dialog now shows scale value.</li>
@@ -974,7 +1005,7 @@
</ul>
</dd>
-<dt>DDMS Integration:</dt>
+<dt>DDMS integration:</dt>
<dd>
<ul>
<li>Includes the improvements from the standlone DDMS, revision 3.</li>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 193066b..65a1f46 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,21 +1,21 @@
page.title=Android SDK
sdk.redirect=0
-sdk.win_installer=installer_r15-windows.exe
-sdk.win_installer_bytes=33902520
-sdk.win_installer_checksum=ee8481cb86a6646a4d963d5142902c5c
+sdk.win_installer=installer_r16-windows.exe
+sdk.win_installer_bytes=29561554
+sdk.win_installer_checksum=3521dda4904886b05980590f83cf3469
-sdk.win_download=android-sdk_r15-windows.zip
-sdk.win_bytes=33895447
-sdk.win_checksum=cc2aadf7120d12b574981461736a96e9
+sdk.win_download=android-sdk_r16-windows.zip
+sdk.win_bytes=29562413
+sdk.win_checksum=6b926d0c0a871f1a946e65259984701a
-sdk.mac_download=android-sdk_r15-macosx.zip
-sdk.mac_bytes=30469921
-sdk.mac_checksum=03d2cdd3565771e8c7a438f1c40cc8a5
+sdk.mac_download=android-sdk_r16-macosx.zip
+sdk.mac_bytes=26158334
+sdk.mac_checksum=d1dc2b6f13eed5e3ce5cf26c4e4c47aa
-sdk.linux_download=android-sdk_r15-linux.tgz
-sdk.linux_bytes=26124434
-sdk.linux_checksum=f529681fd1eda11c6e1e1d44b42c1432
+sdk.linux_download=android-sdk_r16-linux.tgz
+sdk.linux_bytes=22048174
+sdk.linux_checksum=3ba457f731d51da3741c29c8830a4583
@jd:body
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index f12d0aa..c970f6c9 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -24,8 +24,8 @@
<h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
<ul>
- <li>Eclipse 3.5 (Galileo) or greater
-<p class="note"><strong>Note:</strong> Eclipse 3.4 (Ganymede) is no longer
+ <li>Eclipse 3.6 (Helios) or greater
+<p class="note"><strong>Note:</strong> Eclipse 3.5 (Galileo) is no longer
supported with the latest version of ADT.</p></li>
<li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
in most Eclipse IDE packages) </li>
@@ -37,7 +37,7 @@
packages: </p>
<ul>
<li>Eclipse IDE for Java Developers</li>
- <li>Eclipse Classic (versions 3.5.1 and higher)</li>
+ <li>Eclipse Classic</li>
<li>Eclipse IDE for Java EE Developers</li>
</ul>
</li>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 0ae2c6d..791e7aa 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -150,7 +150,7 @@
</li>
</ul>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r15</a> <span
+ <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r16</a> <span
class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li>
<li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Support Package, r4</a>
@@ -169,7 +169,7 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 15.0.1
+ <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 16.0.0
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
<span style="display:none" class="fr"></span>
diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd
index cd03d9f..9a63467 100644
--- a/docs/html/sdk/tools-notes.jd
+++ b/docs/html/sdk/tools-notes.jd
@@ -9,7 +9,7 @@
latest revision of the SDK Tools in the <code><sdk>/tools</code> directory.</p>
<p>If you are already using the SDK and you want to update to the latest version
-of the SDK Tools, use the <em>Android SDK and AVD Manager</em> to get the
+of the SDK Tools, use the <em>Android SDK Manager</em> to get the
update, rather than downloading a new SDK starter package. For more information
about how to update, see <a
href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK
@@ -20,8 +20,7 @@
<p>The sections below provide notes about successive releases of
the SDK Tools, as denoted by revision number. To determine what revision of the SDK
-Tools you are using, refer to the "Installed Packages" listing in the Android SDK
-and AVD Manager. </p>
+Tools you are using, refer to the "Installed Packages" listing in the Android SDK Manager. </p>
<p>For a summary of all known issues in SDK Tools, see <a
href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
@@ -69,7 +68,57 @@
<div class="toggleable opened">
<a href="#" onclick="return toggleDiv(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
- width="9px" />SDK Tools, Revision 15</a> <em>(October 2011)</em>
+ width="9px" />
+ SDK Tools, Revision 16</a> <em>(December 2011)</em>
+
+ <div class="toggleme">
+ <p class="caution"><strong>Important:</strong> To download the new Android
+ 4.0 system components from the Android SDK Manager, you must first update the
+ SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
+ the Android 4.0 system components will not be available for download.</p>
+
+<dl>
+<dt>Dependencies:</dt>
+<dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 9 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that the SDK Tools r16 is designed for use
+ with ADT 16.0.0 and later. If you haven't already, we highly recommend updating your
+ <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin</a> to 16.0.0.</li>
+ <li>If you are developing outside Eclipse, you must have <a href="http://ant.apache.org/">Apache
+ Ant</a> 1.8 or later.</li>
+</ul>
+</dd>
+<dt>General notes:</dt>
+<dd>
+ <ul>
+ <li>Added Lint tools to detect common errors in Android projects. (<a
+href="http://tools.android.com/recent/lint">more info</a>)</li>
+ <li>Added sensor emulation support, which allows the emulator to read sensor data from a
+physical Android device.</li>
+ <li>Added support for using a webcam to emulate a camera on Mac OS X.</li>
+ </ul>
+</dd>
+<dt>Bug fixes:</dt>
+<dd>
+ <ul>
+ <li>Snapshots now work for Android 4.0 system images.</li>
+ <li>Fixed several small issues for the build file.
+ (<a href="http://code.google.com/p/android/issues/detail?id=21023">Issue 21023</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=21267">Issue 21267</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=21465">Issue 21465</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=21525">Issue 21525</a>).</li>
+ </ul>
+</dd>
+</dl>
+</div>
+</div>
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+ width="9px" />
+ SDK Tools, Revision 15</a> <em>(October 2011)</em>
<div class="toggleme">
<p class="caution"><strong>Important:</strong> To download the new Android
@@ -116,7 +165,8 @@
<div class="toggleable closed">
<a href="#" onclick="return toggleDiv(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
- width="9px" />SDK Tools, Revision 14</a> <em>(October 2011)</em>
+ width="9px" />
+ SDK Tools, Revision 14</a> <em>(October 2011)</em>
<div class="toggleme">
<p class="note"><strong>Important:</strong> To download the new Android
@@ -137,10 +187,11 @@
<dt>General notes:</dt>
<dd>
<ul>
- <li>Added webcam support to Android 4.0 or later platforms to emulate rear-facing cameras when one webcam is present,
- and to emulate both rear-facing and front-facing cameras when two webcams are present. Webcam suport is for Windows and Linux only.
+ <li>Added webcam support to Android 4.0 or later platforms to emulate rear-facing cameras when
+ one webcam is present, and to emulate both rear-facing and front-facing cameras when two
+ webcams are present. Webcam support is for Windows and Linux only.
Mac support will come in a later release.</li>
- <li>Changed <code>default.properties</code> to <code>project.properties</code> and
+ <li>Changed <code>default.properties</code> to <code>project.properties</code> and
<code>build.properties</code> to <code>ant.properties</code>. Any existing
projects that you build with Ant must be updated with the <code>android update project</code>
command.</li>
@@ -428,7 +479,7 @@
for more information.</li>
<li>Fixes location control in DDMS to work in any locale not using '.' as a
decimal point.</li>
-</li>
+</ul>
</ul>
</dd>
</dl>
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 3abf3d3..f6552dd 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -99,11 +99,12 @@
status_t DrmManager::loadPlugIns() {
+ String8 pluginDirPath("/system/lib/drm");
+ loadPlugIns(pluginDirPath);
+
String8 vendorPluginDirPath("/vendor/lib/drm");
loadPlugIns(vendorPluginDirPath);
- String8 pluginDirPath("/system/lib/drm");
- loadPlugIns(pluginDirPath);
return DRM_NO_ERROR;
}
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 6f3051a..4310bed 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -500,8 +500,8 @@
eglDestroySyncKHR(dpy, fence);
}
- ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
- mSlots[buf].mGraphicBuffer->handle, returnFlags);
+ ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
+ mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
return returnFlags;
}
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f293cba..4da576d 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -73,6 +73,9 @@
glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
mCurrentBuffer = meshBuffer;
+ mCurrentPositionPointer = this;
+ mCurrentTexCoordsPointer = this;
+
mRegionMesh = NULL;
blend = false;
@@ -218,22 +221,49 @@
// VBO
///////////////////////////////////////////////////////////////////////////////
-void Caches::bindMeshBuffer() {
- bindMeshBuffer(meshBuffer);
+bool Caches::bindMeshBuffer() {
+ return bindMeshBuffer(meshBuffer);
}
-void Caches::bindMeshBuffer(const GLuint buffer) {
+bool Caches::bindMeshBuffer(const GLuint buffer) {
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
mCurrentBuffer = buffer;
+ return true;
}
+ return false;
}
-void Caches::unbindMeshBuffer() {
+bool Caches::unbindMeshBuffer() {
if (mCurrentBuffer) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
mCurrentBuffer = 0;
+ return true;
}
+ return false;
+}
+
+void Caches::bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices, GLsizei stride) {
+ if (force || vertices != mCurrentPositionPointer) {
+ glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+ mCurrentPositionPointer = vertices;
+ }
+}
+
+void Caches::bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices) {
+ if (force || vertices != mCurrentTexCoordsPointer) {
+ glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
+ mCurrentTexCoordsPointer = vertices;
+ }
+}
+
+void Caches::resetVertexPointers() {
+ mCurrentPositionPointer = this;
+ mCurrentTexCoordsPointer = this;
+}
+
+void Caches::resetTexCoordsVertexPointer() {
+ mCurrentTexCoordsPointer = this;
}
TextureVertex* Caches::getRegionMesh() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 5e58a9e..7ca198a 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -91,15 +91,6 @@
CacheLogger mLogger;
- GLuint mCurrentBuffer;
-
- // Used to render layers
- TextureVertex* mRegionMesh;
- GLuint mRegionMeshIndices;
-
- mutable Mutex mGarbageLock;
- Vector<Layer*> mLayerGarbage;
-
public:
enum FlushMode {
kFlushMode_Layers = 0,
@@ -147,17 +138,36 @@
/**
* Binds the VBO used to render simple textured quads.
*/
- void bindMeshBuffer();
+ bool bindMeshBuffer();
/**
* Binds the specified VBO if needed.
*/
- void bindMeshBuffer(const GLuint buffer);
+ bool bindMeshBuffer(const GLuint buffer);
/**
* Unbinds the VBO used to render simple textured quads.
*/
- void unbindMeshBuffer();
+ bool unbindMeshBuffer();
+
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gMeshStride and a size of 2.
+ */
+ void bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices,
+ GLsizei stride = gMeshStride);
+
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gMeshStride and a size of 2.
+ */
+ void bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices);
+
+ /**
+ * Resets the vertex pointers.
+ */
+ void resetVertexPointers();
+ void resetTexCoordsVertexPointer();
/**
* Returns the mesh used to draw regions. Calling this method will
@@ -203,6 +213,17 @@
ResourceCache resourceCache;
private:
+ GLuint mCurrentBuffer;
+ void* mCurrentPositionPointer;
+ void* mCurrentTexCoordsPointer;
+
+ // Used to render layers
+ TextureVertex* mRegionMesh;
+ GLuint mRegionMeshIndices;
+
+ mutable Mutex mGarbageLock;
+ Vector<Layer*> mLayerGarbage;
+
DebugLevel mDebugLevel;
bool mInitialized;
}; // class Caches
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 158f785..f04ea6f 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -104,10 +104,10 @@
int width = (int) glyph->mBitmapWidth;
int height = (int) glyph->mBitmapHeight;
- mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
- nPenX + width, nPenY, 0, u2, v2,
- nPenX + width, nPenY - height, 0, u2, v1,
- nPenX, nPenY - height, 0, u1, v1);
+ mState->appendMeshQuad(nPenX, nPenY, u1, v2,
+ nPenX + width, nPenY, u2, v2,
+ nPenX + width, nPenY - height, u2, v1,
+ nPenX, nPenY - height, u1, v1);
}
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
@@ -325,8 +325,6 @@
mTextTexture = NULL;
mIndexBufferID = 0;
- mPositionAttrSlot = -1;
- mTexcoordAttrSlot = -1;
mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
@@ -519,8 +517,8 @@
// Avoid having to reallocate memory and render quad by quad
void FontRenderer::initVertexArrayBuffers() {
- uint32_t numIndicies = mMaxNumberOfQuads * 6;
- uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t);
+ uint32_t numIndices = mMaxNumberOfQuads * 6;
+ uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
// Four verts, two triangles , six indices per quad
@@ -544,7 +542,7 @@
free(indexBufferData);
- uint32_t coordSize = 3;
+ uint32_t coordSize = 2;
uint32_t uvSize = 2;
uint32_t vertsPerQuad = 4;
uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
@@ -579,12 +577,12 @@
// Iterate over all the cache lines and see which ones need to be updated
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
CacheTextureLine* cl = mCacheLines[i];
- if(cl->mDirty) {
+ if (cl->mDirty) {
uint32_t xOffset = 0;
uint32_t yOffset = cl->mCurrentRow;
uint32_t width = mCacheWidth;
uint32_t height = cl->mMaxHeight;
- void* textureData = mTextTexture + yOffset*width;
+ void* textureData = mTextTexture + yOffset * width;
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
@@ -599,51 +597,43 @@
void FontRenderer::issueDrawCommand() {
checkTextureUpdate();
- float* vtx = mTextMeshPtr;
- float* tex = vtx + 3;
-
- glVertexAttribPointer(mPositionAttrSlot, 3, GL_FLOAT, false, 20, vtx);
- glVertexAttribPointer(mTexcoordAttrSlot, 2, GL_FLOAT, false, 20, tex);
-
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
mDrawn = true;
}
-void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
- float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
- float x4, float y4, float z4, float u4, float v4) {
+void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
+ float x2, float y2, float u2, float v2,
+ float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4) {
+
if (mClip &&
(x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
return;
}
const uint32_t vertsPerQuad = 4;
- const uint32_t floatsPerVert = 5;
+ const uint32_t floatsPerVert = 4;
float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
(*currentPos++) = x1;
(*currentPos++) = y1;
- (*currentPos++) = z1;
(*currentPos++) = u1;
(*currentPos++) = v1;
(*currentPos++) = x2;
(*currentPos++) = y2;
- (*currentPos++) = z2;
(*currentPos++) = u2;
(*currentPos++) = v2;
(*currentPos++) = x3;
(*currentPos++) = y3;
- (*currentPos++) = z3;
(*currentPos++) = u3;
(*currentPos++) = v3;
(*currentPos++) = x4;
(*currentPos++) = y4;
- (*currentPos++) = z4;
(*currentPos++) = u4;
(*currentPos++) = v4;
@@ -762,11 +752,6 @@
return false;
}
- if (mPositionAttrSlot < 0 || mTexcoordAttrSlot < 0) {
- LOGE("Font renderer unable to draw, attribute slots undefined");
- return false;
- }
-
mDrawn = false;
mBounds = bounds;
mClip = clip;
@@ -914,9 +899,12 @@
void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
float *gaussian = new float[2 * radius + 1];
computeGaussianWeights(gaussian, radius);
+
uint8_t* scratch = new uint8_t[width * height];
+
horizontalBlur(gaussian, radius, image, scratch, width, height);
verticalBlur(gaussian, radius, scratch, image, width, height);
+
delete[] gaussian;
delete[] scratch;
}
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 1922812..f945873 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -178,9 +178,13 @@
mGammaTable = gammaTable;
}
- void setAttributeBindingSlots(int positionSlot, int texCoordSlot) {
- mPositionAttrSlot = positionSlot;
- mTexcoordAttrSlot = texCoordSlot;
+ inline float* getMeshBuffer() {
+ checkInit();
+ return mTextMeshPtr;
+ }
+
+ inline int getMeshTexCoordsOffset() const {
+ return 2;
}
void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
@@ -279,9 +283,10 @@
void precacheLatin(SkPaint* paint);
void issueDrawCommand();
- void appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, float y2,
- float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
- float x4, float y4, float z4, float u4, float v4);
+ void appendMeshQuad(float x1, float y1, float u1, float v1,
+ float x2, float y2, float u2, float v2,
+ float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4);
uint32_t mCacheWidth;
uint32_t mCacheHeight;
@@ -308,9 +313,6 @@
uint32_t mIndexBufferID;
- int32_t mPositionAttrSlot;
- int32_t mTexcoordAttrSlot;
-
const Rect* mClip;
Rect* mBounds;
bool mDrawn;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index aacf22a..a88a59a 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -171,8 +171,8 @@
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
- texture->setFilter(GL_LINEAR, GL_LINEAR);
- texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+ texture->setFilter(GL_LINEAR);
+ texture->setWrap(GL_CLAMP_TO_EDGE);
}
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 5298125..324765b 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -108,8 +108,8 @@
layer->generateTexture();
layer->bindTexture();
- layer->setFilter(GL_NEAREST, GL_NEAREST);
- layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false);
+ layer->setFilter(GL_NEAREST);
+ layer->setWrap(GL_CLAMP_TO_EDGE, false);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
#if DEBUG_LAYERS
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e2d9ea3..c30923f 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -233,7 +233,6 @@
layer->getTexture(), 0);
glDisable(GL_SCISSOR_TEST);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
@@ -459,6 +458,8 @@
}
error:
+ glEnable(GL_SCISSOR_TEST);
+
#if DEBUG_OPENGL
if (error != GL_NO_ERROR) {
LOGD("GL error while copying layer into bitmap = 0x%x", error);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1d7b99d..fcac053 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -133,8 +133,6 @@
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setViewport(int width, int height) {
- glDisable(GL_DITHER);
- glViewport(0, 0, width, height);
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
mWidth = width;
@@ -143,7 +141,10 @@
mFirstSnapshot->height = height;
mFirstSnapshot->viewport.set(0, 0, width, height);
- mDirtyClip = false;
+ glDisable(GL_DITHER);
+ glEnable(GL_SCISSOR_TEST);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glEnableVertexAttribArray(Program::kBindingPosition);
}
void OpenGLRenderer::prepare(bool opaque) {
@@ -156,17 +157,15 @@
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
mSnapshot->fbo = getTargetFbo();
-
mSaveCount = 1;
glViewport(0, 0, mWidth, mHeight);
-
- glEnable(GL_SCISSOR_TEST);
glScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
+
mSnapshot->setClip(left, top, right, bottom);
+ mDirtyClip = false;
if (!opaque) {
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
}
@@ -200,18 +199,18 @@
}
}
mCaches.unbindMeshBuffer();
+ mCaches.resetVertexPointers();
}
void OpenGLRenderer::resume() {
sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_SCISSOR_TEST);
dirtyClip();
- glDisable(GL_DITHER);
-
glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -556,7 +555,6 @@
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
dirtyClip();
@@ -911,10 +909,8 @@
setupDrawProgram();
setupDrawPureColorUniforms();
setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
+ setupDrawVertices(&mesh[0].position[0]);
- mCaches.unbindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gVertexStride, &mesh[0].position[0]);
glDrawArrays(GL_TRIANGLES, 0, count * 6);
glEnable(GL_SCISSOR_TEST);
@@ -1205,16 +1201,15 @@
}
void OpenGLRenderer::setupDrawSimpleMesh() {
- mCaches.bindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, 0);
+ bool force = mCaches.bindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0);
}
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
bindTexture(texture);
glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
- mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+ mTexCoordsSlot = mCaches.currentProgram->texCoords;
glEnableVertexAttribArray(mTexCoordsSlot);
}
@@ -1222,7 +1217,7 @@
bindExternalTexture(texture);
glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
- mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+ mTexCoordsSlot = mCaches.currentProgram->texCoords;
glEnableVertexAttribArray(mTexCoordsSlot);
}
@@ -1236,22 +1231,23 @@
}
void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
+ bool force = false;
if (!vertices) {
- mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+ force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
} else {
- mCaches.unbindMeshBuffer();
+ force = mCaches.unbindMeshBuffer();
}
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, vertices);
+
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
if (mTexCoordsSlot >= 0) {
- glVertexAttribPointer(mTexCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
+ mCaches.bindTexCoordsVertexPointer(force, mTexCoordsSlot, texCoords);
}
}
void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
- mCaches.unbindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gVertexStride, vertices);
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
+ vertices, gVertexStride);
}
/**
@@ -1267,17 +1263,22 @@
*/
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
GLvoid* lengthCoords, float boundaryWidthProportion) {
- mCaches.unbindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gAAVertexStride, vertices);
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
+ vertices, gAAVertexStride);
+ mCaches.resetTexCoordsVertexPointer();
+
int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
glEnableVertexAttribArray(widthSlot);
glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
+
int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
glEnableVertexAttribArray(lengthSlot);
glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
+
int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
glUniform1f(boundaryWidthSlot, boundaryWidthProportion);
+
// Setting the inverse value saves computations per-fragment in the shader
int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidthProportion));
@@ -2184,12 +2185,14 @@
#else
bool hasActiveLayer = false;
#endif
- mCaches.unbindMeshBuffer();
- // Tell font renderer the locations of position and texture coord
- // attributes so it can bind its data properly
- int positionSlot = mCaches.currentProgram->position;
- fontRenderer.setAttributeBindingSlots(positionSlot, mTexCoordsSlot);
+ float* buffer = fontRenderer.getMeshBuffer();
+ int offset = fontRenderer.getMeshTexCoordsOffset();
+
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, buffer);
+ mCaches.bindTexCoordsVertexPointer(force, mTexCoordsSlot, buffer + offset);
+
if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
hasActiveLayer ? &bounds : NULL)) {
#if RENDER_LAYERS_AS_REGIONS
@@ -2203,7 +2206,7 @@
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
+ glDisableVertexAttribArray(mCaches.currentProgram->texCoords);
drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
}
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 47a2c99..27f530c 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -197,7 +197,8 @@
}
if (verticesCount > 0) {
- Caches::getInstance().bindMeshBuffer(meshBuffer);
+ Caches& caches = Caches::getInstance();
+ caches.bindMeshBuffer(meshBuffer);
if (!mUploaded) {
glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
mVertices, GL_DYNAMIC_DRAW);
@@ -206,6 +207,7 @@
glBufferSubData(GL_ARRAY_BUFFER, 0,
sizeof(TextureVertex) * verticesCount, mVertices);
}
+ caches.resetVertexPointers();
}
PATCH_LOGD(" patch: new vertices count = %d", verticesCount);
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 972dd87..cbea843 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -25,80 +25,106 @@
// Base program
///////////////////////////////////////////////////////////////////////////////
-Program::Program(const char* vertex, const char* fragment) {
+// TODO: Program instance should be created from a factory method
+Program::Program(const ProgramDescription& description, const char* vertex, const char* fragment) {
mInitialized = false;
+ mHasColorUniform = false;
+ mUse = false;
- vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
- if (vertexShader) {
+ // No need to cache compiled shaders, rely instead on Android's
+ // persistent shaders cache
+ mVertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+ if (mVertexShader) {
+ mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+ if (mFragmentShader) {
+ mProgramId = glCreateProgram();
- fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
- if (fragmentShader) {
+ glAttachShader(mProgramId, mVertexShader);
+ glAttachShader(mProgramId, mFragmentShader);
- id = glCreateProgram();
- glAttachShader(id, vertexShader);
- glAttachShader(id, fragmentShader);
- glLinkProgram(id);
+ position = bindAttrib("position", kBindingPosition);
+ if (description.hasTexture || description.hasExternalTexture) {
+ texCoords = bindAttrib("texCoords", kBindingTexCoords);
+ } else {
+ texCoords = -1;
+ }
+
+ glLinkProgram(mProgramId);
GLint status;
- glGetProgramiv(id, GL_LINK_STATUS, &status);
+ glGetProgramiv(mProgramId, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
LOGE("Error while linking shaders:");
GLint infoLen = 0;
- glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
+ glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
GLchar log[infoLen];
- glGetProgramInfoLog(id, infoLen, 0, &log[0]);
+ glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
LOGE("%s", log);
}
- glDeleteShader(vertexShader);
- glDeleteShader(fragmentShader);
- glDeleteProgram(id);
+
+ glDetachShader(mProgramId, mVertexShader);
+ glDetachShader(mProgramId, mFragmentShader);
+
+ glDeleteShader(mVertexShader);
+ glDeleteShader(mFragmentShader);
+
+ glDeleteProgram(mProgramId);
} else {
mInitialized = true;
}
+ } else {
+ glDeleteShader(mVertexShader);
}
}
- mUse = false;
-
if (mInitialized) {
- position = addAttrib("position");
transform = addUniform("transform");
}
}
Program::~Program() {
if (mInitialized) {
- glDeleteShader(vertexShader);
- glDeleteShader(fragmentShader);
- glDeleteProgram(id);
+ glDetachShader(mProgramId, mVertexShader);
+ glDetachShader(mProgramId, mFragmentShader);
+
+ glDeleteShader(mVertexShader);
+ glDeleteShader(mFragmentShader);
+
+ glDeleteProgram(mProgramId);
}
}
int Program::addAttrib(const char* name) {
- int slot = glGetAttribLocation(id, name);
- attributes.add(name, slot);
+ int slot = glGetAttribLocation(mProgramId, name);
+ mAttributes.add(name, slot);
return slot;
}
+int Program::bindAttrib(const char* name, ShaderBindings bindingSlot) {
+ glBindAttribLocation(mProgramId, bindingSlot, name);
+ mAttributes.add(name, bindingSlot);
+ return bindingSlot;
+}
+
int Program::getAttrib(const char* name) {
- ssize_t index = attributes.indexOfKey(name);
+ ssize_t index = mAttributes.indexOfKey(name);
if (index >= 0) {
- return attributes.valueAt(index);
+ return mAttributes.valueAt(index);
}
return addAttrib(name);
}
int Program::addUniform(const char* name) {
- int slot = glGetUniformLocation(id, name);
- uniforms.add(name, slot);
+ int slot = glGetUniformLocation(mProgramId, name);
+ mUniforms.add(name, slot);
return slot;
}
int Program::getUniform(const char* name) {
- ssize_t index = uniforms.indexOfKey(name);
+ ssize_t index = mUniforms.indexOfKey(name);
if (index >= 0) {
- return uniforms.valueAt(index);
+ return mUniforms.valueAt(index);
}
return addUniform(name);
}
@@ -127,10 +153,11 @@
const mat4& transformMatrix, bool offset) {
mat4 t(projectionMatrix);
if (offset) {
- // offset screenspace xy by an amount that compensates for typical precision issues
- // in GPU hardware that tends to paint hor/vert lines in pixels shifted up and to the left.
- // This offset value is based on an assumption that some hardware may use as little
- // as 12.4 precision, so we offset by slightly more than 1/16.
+ // offset screenspace xy by an amount that compensates for typical precision
+ // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
+ // up and to the left.
+ // This offset value is based on an assumption that some hardware may use as
+ // little as 12.4 precision, so we offset by slightly more than 1/16.
t.translate(.375, .375, 0);
}
t.multiply(transformMatrix);
@@ -140,20 +167,20 @@
}
void Program::setColor(const float r, const float g, const float b, const float a) {
- glUniform4f(getUniform("color"), r, g, b, a);
+ if (!mHasColorUniform) {
+ mColorUniform = getUniform("color");
+ mHasColorUniform = true;
+ }
+ glUniform4f(mColorUniform, r, g, b, a);
}
void Program::use() {
- glUseProgram(id);
+ glUseProgram(mProgramId);
mUse = true;
-
- glEnableVertexAttribArray(position);
}
void Program::remove() {
mUse = false;
-
- glDisableVertexAttribArray(position);
}
}; // namespace uirenderer
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 764cb05..559c717 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -17,27 +17,280 @@
#ifndef ANDROID_HWUI_PROGRAM_H
#define ANDROID_HWUI_PROGRAM_H
+#include <utils/KeyedVector.h>
+
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
-#include <utils/KeyedVector.h>
+#include <SkXfermode.h>
#include "Matrix.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#if DEBUG_PROGRAMS
+ #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
+#else
+ #define PROGRAM_LOGD(...)
+#endif
+
+#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
+#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
+
+#define PROGRAM_KEY_TEXTURE 0x1
+#define PROGRAM_KEY_A8_TEXTURE 0x2
+#define PROGRAM_KEY_BITMAP 0x4
+#define PROGRAM_KEY_GRADIENT 0x8
+#define PROGRAM_KEY_BITMAP_FIRST 0x10
+#define PROGRAM_KEY_COLOR_MATRIX 0x20
+#define PROGRAM_KEY_COLOR_LIGHTING 0x40
+#define PROGRAM_KEY_COLOR_BLEND 0x80
+#define PROGRAM_KEY_BITMAP_NPOT 0x100
+#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
+
+#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
+
+// Encode the xfermodes on 6 bits
+#define PROGRAM_MAX_XFERMODE 0x1f
+#define PROGRAM_XFERMODE_SHADER_SHIFT 26
+#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
+#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
+
+#define PROGRAM_BITMAP_WRAPS_SHIFT 9
+#define PROGRAM_BITMAP_WRAPT_SHIFT 11
+
+#define PROGRAM_GRADIENT_TYPE_SHIFT 33
+#define PROGRAM_MODULATE_SHIFT 35
+
+#define PROGRAM_IS_POINT_SHIFT 36
+
+#define PROGRAM_HAS_AA_SHIFT 37
+
+#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
+#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
+
+///////////////////////////////////////////////////////////////////////////////
+// Types
+///////////////////////////////////////////////////////////////////////////////
+
+typedef uint64_t programid;
+
+///////////////////////////////////////////////////////////////////////////////
+// Program description
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Describe the features required for a given program. The features
+ * determine the generation of both the vertex and fragment shaders.
+ * A ProgramDescription must be used in conjunction with a ProgramCache.
+ */
+struct ProgramDescription {
+ enum ColorModifier {
+ kColorNone,
+ kColorMatrix,
+ kColorLighting,
+ kColorBlend
+ };
+
+ enum Gradient {
+ kGradientLinear,
+ kGradientCircular,
+ kGradientSweep
+ };
+
+ ProgramDescription() {
+ reset();
+ }
+
+ // Texturing
+ bool hasTexture;
+ bool hasAlpha8Texture;
+ bool hasExternalTexture;
+ bool hasTextureTransform;
+
+ // Modulate, this should only be set when setColor() return true
+ bool modulate;
+
+ // Shaders
+ bool hasBitmap;
+ bool isBitmapNpot;
+
+ bool isAA;
+
+ bool hasGradient;
+ Gradient gradientType;
+
+ SkXfermode::Mode shadersMode;
+
+ bool isBitmapFirst;
+ GLenum bitmapWrapS;
+ GLenum bitmapWrapT;
+
+ // Color operations
+ ColorModifier colorOp;
+ SkXfermode::Mode colorMode;
+
+ // Framebuffer blending (requires Extensions.hasFramebufferFetch())
+ // Ignored for all values < SkXfermode::kPlus_Mode
+ SkXfermode::Mode framebufferMode;
+ bool swapSrcDst;
+
+ bool isPoint;
+ float pointSize;
+
+ /**
+ * Resets this description. All fields are reset back to the default
+ * values they hold after building a new instance.
+ */
+ void reset() {
+ hasTexture = false;
+ hasAlpha8Texture = false;
+ hasExternalTexture = false;
+ hasTextureTransform = false;
+
+ isAA = false;
+
+ modulate = false;
+
+ hasBitmap = false;
+ isBitmapNpot = false;
+
+ hasGradient = false;
+ gradientType = kGradientLinear;
+
+ shadersMode = SkXfermode::kClear_Mode;
+
+ isBitmapFirst = false;
+ bitmapWrapS = GL_CLAMP_TO_EDGE;
+ bitmapWrapT = GL_CLAMP_TO_EDGE;
+
+ colorOp = kColorNone;
+ colorMode = SkXfermode::kClear_Mode;
+
+ framebufferMode = SkXfermode::kClear_Mode;
+ swapSrcDst = false;
+
+ isPoint = false;
+ pointSize = 0.0f;
+ }
+
+ /**
+ * Indicates, for a given color, whether color modulation is required in
+ * the fragment shader. When this method returns true, the program should
+ * be provided with a modulation color.
+ */
+ bool setColor(const float r, const float g, const float b, const float a) {
+ modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
+ g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
+ return modulate;
+ }
+
+ /**
+ * Indicates, for a given color, whether color modulation is required in
+ * the fragment shader. When this method returns true, the program should
+ * be provided with a modulation color.
+ */
+ bool setAlpha8Color(const float r, const float g, const float b, const float a) {
+ modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
+ g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
+ return modulate;
+ }
+
+ /**
+ * Computes the unique key identifying this program.
+ */
+ programid key() const {
+ programid key = 0;
+ if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
+ if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
+ if (hasBitmap) {
+ key |= PROGRAM_KEY_BITMAP;
+ if (isBitmapNpot) {
+ key |= PROGRAM_KEY_BITMAP_NPOT;
+ key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
+ key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
+ }
+ }
+ if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
+ key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
+ if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
+ if (hasBitmap && hasGradient) {
+ key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
+ }
+ switch (colorOp) {
+ case kColorMatrix:
+ key |= PROGRAM_KEY_COLOR_MATRIX;
+ break;
+ case kColorLighting:
+ key |= PROGRAM_KEY_COLOR_LIGHTING;
+ break;
+ case kColorBlend:
+ key |= PROGRAM_KEY_COLOR_BLEND;
+ key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
+ break;
+ case kColorNone:
+ break;
+ }
+ key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
+ if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
+ if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
+ if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
+ if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
+ if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
+ if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
+ return key;
+ }
+
+ /**
+ * Logs the specified message followed by the key identifying this program.
+ */
+ void log(const char* message) const {
+#if DEBUG_PROGRAMS
+ programid k = key();
+ PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
+ uint32_t(k & 0xffffffff));
+#endif
+ }
+
+private:
+ inline uint32_t getEnumForWrap(GLenum wrap) const {
+ switch (wrap) {
+ case GL_CLAMP_TO_EDGE:
+ return 0;
+ case GL_REPEAT:
+ return 1;
+ case GL_MIRRORED_REPEAT:
+ return 2;
+ }
+ return 0;
+ }
+
+}; // struct ProgramDescription
+
/**
* A program holds a vertex and a fragment shader. It offers several utility
* methods to query attributes and uniforms.
*/
class Program {
public:
+ enum ShaderBindings {
+ kBindingPosition,
+ kBindingTexCoords
+ };
+
/**
* Creates a new program with the specified vertex and fragment
* shaders sources.
*/
- Program(const char* vertex, const char* fragment);
+ Program(const ProgramDescription& description, const char* vertex, const char* fragment);
virtual ~Program();
/**
@@ -94,6 +347,11 @@
int position;
/**
+ * Name of the texCoords attribute if it exists, -1 otherwise.
+ */
+ int texCoords;
+
+ /**
* Name of the transform uniform.
*/
int transform;
@@ -107,6 +365,11 @@
int addAttrib(const char* name);
/**
+ * Binds the specified attribute name to the specified slot.
+ */
+ int bindAttrib(const char* name, ShaderBindings bindingSlot);
+
+ /**
* Adds a uniform with the specified name.
*
* @return The OpenGL name of the uniform.
@@ -121,19 +384,20 @@
*/
GLuint buildShader(const char* source, GLenum type);
- // Name of the OpenGL program
- GLuint id;
-
- // Name of the shaders
- GLuint vertexShader;
- GLuint fragmentShader;
+ // Name of the OpenGL program and shaders
+ GLuint mProgramId;
+ GLuint mVertexShader;
+ GLuint mFragmentShader;
// Keeps track of attributes and uniforms slots
- KeyedVector<const char*, int> attributes;
- KeyedVector<const char*, int> uniforms;
+ KeyedVector<const char*, int> mAttributes;
+ KeyedVector<const char*, int> mUniforms;
bool mUse;
bool mInitialized;
+
+ bool mHasColorUniform;
+ int mColorUniform;
}; // class Program
}; // namespace uirenderer
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index c2383f4..a7f1277 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -388,7 +388,7 @@
String8 vertexShader = generateVertexShader(description);
String8 fragmentShader = generateFragmentShader(description);
- Program* program = new Program(vertexShader.string(), fragmentShader.string());
+ Program* program = new Program(description, vertexShader.string(), fragmentShader.string());
return program;
}
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 5c7197b..e3ed79e 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -23,10 +23,9 @@
#include <GLES2/gl2.h>
-#include <SkXfermode.h>
-
#include "Debug.h"
#include "Program.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -42,243 +41,11 @@
#define PROGRAM_LOGD(...)
#endif
-// TODO: This should be set in properties
-#define PANEL_BIT_DEPTH 20
-#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
-#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
-
-#define PROGRAM_KEY_TEXTURE 0x1
-#define PROGRAM_KEY_A8_TEXTURE 0x2
-#define PROGRAM_KEY_BITMAP 0x4
-#define PROGRAM_KEY_GRADIENT 0x8
-#define PROGRAM_KEY_BITMAP_FIRST 0x10
-#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_LIGHTING 0x40
-#define PROGRAM_KEY_COLOR_BLEND 0x80
-#define PROGRAM_KEY_BITMAP_NPOT 0x100
-#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
-
-#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
-#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
-
-// Encode the xfermodes on 6 bits
-#define PROGRAM_MAX_XFERMODE 0x1f
-#define PROGRAM_XFERMODE_SHADER_SHIFT 26
-#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
-#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
-
-#define PROGRAM_BITMAP_WRAPS_SHIFT 9
-#define PROGRAM_BITMAP_WRAPT_SHIFT 11
-
-#define PROGRAM_GRADIENT_TYPE_SHIFT 33
-#define PROGRAM_MODULATE_SHIFT 35
-
-#define PROGRAM_IS_POINT_SHIFT 36
-
-#define PROGRAM_HAS_AA_SHIFT 37
-
-#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
-#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
-
-///////////////////////////////////////////////////////////////////////////////
-// Types
-///////////////////////////////////////////////////////////////////////////////
-
-typedef uint64_t programid;
-
///////////////////////////////////////////////////////////////////////////////
// Cache
///////////////////////////////////////////////////////////////////////////////
/**
- * Describe the features required for a given program. The features
- * determine the generation of both the vertex and fragment shaders.
- * A ProgramDescription must be used in conjunction with a ProgramCache.
- */
-struct ProgramDescription {
- enum ColorModifier {
- kColorNone,
- kColorMatrix,
- kColorLighting,
- kColorBlend
- };
-
- enum Gradient {
- kGradientLinear,
- kGradientCircular,
- kGradientSweep
- };
-
- ProgramDescription() {
- reset();
- }
-
- // Texturing
- bool hasTexture;
- bool hasAlpha8Texture;
- bool hasExternalTexture;
- bool hasTextureTransform;
-
- // Modulate, this should only be set when setColor() return true
- bool modulate;
-
- // Shaders
- bool hasBitmap;
- bool isBitmapNpot;
-
- bool isAA;
-
- bool hasGradient;
- Gradient gradientType;
-
- SkXfermode::Mode shadersMode;
-
- bool isBitmapFirst;
- GLenum bitmapWrapS;
- GLenum bitmapWrapT;
-
- // Color operations
- ColorModifier colorOp;
- SkXfermode::Mode colorMode;
-
- // Framebuffer blending (requires Extensions.hasFramebufferFetch())
- // Ignored for all values < SkXfermode::kPlus_Mode
- SkXfermode::Mode framebufferMode;
- bool swapSrcDst;
-
- bool isPoint;
- float pointSize;
-
- /**
- * Resets this description. All fields are reset back to the default
- * values they hold after building a new instance.
- */
- void reset() {
- hasTexture = false;
- hasAlpha8Texture = false;
- hasExternalTexture = false;
- hasTextureTransform = false;
-
- isAA = false;
-
- modulate = false;
-
- hasBitmap = false;
- isBitmapNpot = false;
-
- hasGradient = false;
- gradientType = kGradientLinear;
-
- shadersMode = SkXfermode::kClear_Mode;
-
- isBitmapFirst = false;
- bitmapWrapS = GL_CLAMP_TO_EDGE;
- bitmapWrapT = GL_CLAMP_TO_EDGE;
-
- colorOp = kColorNone;
- colorMode = SkXfermode::kClear_Mode;
-
- framebufferMode = SkXfermode::kClear_Mode;
- swapSrcDst = false;
-
- isPoint = false;
- pointSize = 0.0f;
- }
-
- /**
- * Indicates, for a given color, whether color modulation is required in
- * the fragment shader. When this method returns true, the program should
- * be provided with a modulation color.
- */
- bool setColor(const float r, const float g, const float b, const float a) {
- modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
- g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
- return modulate;
- }
-
- /**
- * Indicates, for a given color, whether color modulation is required in
- * the fragment shader. When this method returns true, the program should
- * be provided with a modulation color.
- */
- bool setAlpha8Color(const float r, const float g, const float b, const float a) {
- modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
- g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
- return modulate;
- }
-
- /**
- * Computes the unique key identifying this program.
- */
- programid key() const {
- programid key = 0;
- if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
- if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
- if (hasBitmap) {
- key |= PROGRAM_KEY_BITMAP;
- if (isBitmapNpot) {
- key |= PROGRAM_KEY_BITMAP_NPOT;
- key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
- key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
- }
- }
- if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
- key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
- if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
- if (hasBitmap && hasGradient) {
- key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
- }
- switch (colorOp) {
- case kColorMatrix:
- key |= PROGRAM_KEY_COLOR_MATRIX;
- break;
- case kColorLighting:
- key |= PROGRAM_KEY_COLOR_LIGHTING;
- break;
- case kColorBlend:
- key |= PROGRAM_KEY_COLOR_BLEND;
- key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
- break;
- case kColorNone:
- break;
- }
- key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
- if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
- if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
- if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
- if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
- if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
- if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
- return key;
- }
-
- /**
- * Logs the specified message followed by the key identifying this program.
- */
- void log(const char* message) const {
-#if DEBUG_PROGRAMS
- programid k = key();
- PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
- uint32_t(k & 0xffffffff));
-#endif
- }
-
-private:
- inline uint32_t getEnumForWrap(GLenum wrap) const {
- switch (wrap) {
- case GL_CLAMP_TO_EDGE:
- return 0;
- case GL_REPEAT:
- return 1;
- case GL_MIRRORED_REPEAT:
- return 2;
- }
- return 0;
- }
-
-}; // struct ProgramDescription
-
-/**
* Generates and caches program. Programs are generated based on
* ProgramDescriptions.
*/
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 8c01e3a..2eae0f1 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -73,6 +73,9 @@
#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold"
#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold"
+// TODO: This should be set by a system property
+#define PANEL_BIT_DEPTH 20
+
// Converts a number of mega-bytes into bytes
#define MB(s) s * 1024 * 1024
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index a3ee63b..bbefec6 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -137,8 +137,8 @@
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
- texture->setFilter(GL_LINEAR, GL_LINEAR);
- texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+ texture->setFilter(GL_LINEAR);
+ texture->setWrap(GL_CLAMP_TO_EDGE);
if (size < mMaxSize) {
if (mDebugEnabled) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index a4aed07..1adf2c7 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -49,7 +49,7 @@
GLenum renderTarget = GL_TEXTURE_2D) {
if (firstWrap || force || wrapS != this->wrapS || wrapT != this->wrapT) {
- firstWrap = true;
+ firstWrap = false;
this->wrapS = wrapS;
this->wrapT = wrapT;
diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java
index 939bd4a..7c1485d 100755
--- a/location/java/android/location/Country.java
+++ b/location/java/android/location/Country.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import java.util.Locale;
@@ -58,8 +59,14 @@
private final int mSource;
private int mHashCode;
+
/**
- *
+ * Time that this object was created (which we assume to be the time that the source was
+ * consulted). This time is in milliseconds since boot up.
+ */
+ private final long mTimestamp;
+
+ /**
* @param countryIso the ISO 3166-1 two letters country code.
* @param source where the countryIso came from, could be one of below
* values
@@ -78,11 +85,23 @@
}
mCountryIso = countryIso.toUpperCase(Locale.US);
mSource = source;
+ mTimestamp = SystemClock.elapsedRealtime();
+ }
+
+ private Country(final String countryIso, final int source, long timestamp) {
+ if (countryIso == null || source < COUNTRY_SOURCE_NETWORK
+ || source > COUNTRY_SOURCE_LOCALE) {
+ throw new IllegalArgumentException();
+ }
+ mCountryIso = countryIso.toUpperCase(Locale.US);
+ mSource = source;
+ mTimestamp = timestamp;
}
public Country(Country country) {
mCountryIso = country.mCountryIso;
mSource = country.mSource;
+ mTimestamp = country.mTimestamp;
}
/**
@@ -106,9 +125,17 @@
return mSource;
}
+ /**
+ * Returns the time that this object was created (which we assume to be the time that the source
+ * was consulted).
+ */
+ public final long getTimestamp() {
+ return mTimestamp;
+ }
+
public static final Parcelable.Creator<Country> CREATOR = new Parcelable.Creator<Country>() {
public Country createFromParcel(Parcel in) {
- return new Country(in.readString(), in.readInt());
+ return new Country(in.readString(), in.readInt(), in.readLong());
}
public Country[] newArray(int size) {
@@ -123,8 +150,14 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mCountryIso);
parcel.writeInt(mSource);
+ parcel.writeLong(mTimestamp);
}
+ /**
+ * Returns true if this {@link Country} is equivalent to the given object. This ignores
+ * the timestamp value and just checks for equivalence of countryIso and source values.
+ * Returns false otherwise.
+ */
@Override
public boolean equals(Object object) {
if (object == this) {
@@ -132,6 +165,7 @@
}
if (object instanceof Country) {
Country c = (Country) object;
+ // No need to check the equivalence of the timestamp
return mCountryIso.equals(c.getCountryIso()) && mSource == c.getSource();
}
return false;
@@ -150,8 +184,8 @@
}
/**
- * Compare the specified country to this country object ignoring the mSource
- * field, return true if the countryIso fields are equal
+ * Compare the specified country to this country object ignoring the source
+ * and timestamp fields, return true if the countryIso fields are equal
*
* @param country the country to compare
* @return true if the specified country's countryIso field is equal to this
@@ -160,4 +194,9 @@
public boolean equalsIgnoreSource(Country country) {
return country != null && mCountryIso.equals(country.getCountryIso());
}
+
+ @Override
+ public String toString() {
+ return "Country {ISO=" + mCountryIso + ", source=" + mSource + ", time=" + mTimestamp + "}";
+ }
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8405264..42f18d3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -335,11 +335,13 @@
return UNKNOWN_ERROR;
}
- dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
- if (mDecryptHandle != NULL) {
- CHECK(mDrmManagerClient);
- if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+ if (extractor->getDrmFlag()) {
+ dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+ if (mDecryptHandle != NULL) {
+ CHECK(mDrmManagerClient);
+ if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+ }
}
}
@@ -2103,6 +2105,7 @@
mWVMExtractor = new WVMExtractor(dataSource);
mWVMExtractor->setAdaptiveStreamingMode(true);
+ mWVMExtractor->setDrmFlag(true);
extractor = mWVMExtractor;
} else {
extractor = MediaExtractor::Create(
@@ -2113,12 +2116,14 @@
}
}
- dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+ if (extractor->getDrmFlag()) {
+ dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
- if (mDecryptHandle != NULL) {
- CHECK(mDrmManagerClient);
- if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+ if (mDecryptHandle != NULL) {
+ CHECK(mDrmManagerClient);
+ if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+ }
}
}
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 2171492..d65dc51 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -114,6 +114,9 @@
ret = new AVIExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
ret = new WVMExtractor(source);
+ if (ret != NULL) {
+ isDrm = true;
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
ret = new AACExtractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
index 6208581..02da243 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
index fe4d318..d645a3c 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
index 2536d92..9c117ae 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
index 44e3577..4f51201 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
index b375396..35d85e1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
index 54e3d1e..bc1628f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
Binary files differ
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 088146b..e3c0601 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -1306,8 +1306,11 @@
}
if (mFaceLockAreaView != null) {
+ int[] faceLockPosition;
+ faceLockPosition = new int[2];
+ mFaceLockAreaView.getLocationInWindow(faceLockPosition);
startFaceLock(mFaceLockAreaView.getWindowToken(),
- mFaceLockAreaView.getLeft(), mFaceLockAreaView.getTop(),
+ faceLockPosition[0], faceLockPosition[1],
mFaceLockAreaView.getWidth(), mFaceLockAreaView.getHeight());
}
}
@@ -1325,14 +1328,14 @@
};
// Tells the FaceLock service to start displaying its UI and perform recognition
- public void startFaceLock(IBinder windowToken, int x, int y, int h, int w)
+ public void startFaceLock(IBinder windowToken, int x, int y, int w, int h)
{
if (usingFaceLock()) {
synchronized (mFaceLockServiceRunningLock) {
if (!mFaceLockServiceRunning) {
if (DEBUG) Log.d(TAG, "Starting FaceLock");
try {
- mFaceLockService.startUi(windowToken, x, y, h, w);
+ mFaceLockService.startUi(windowToken, x, y, w, h);
} catch (RemoteException e) {
Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
return;
diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/java/com/android/server/CountryDetectorService.java
index 3081ebe..ab61a3c 100644
--- a/services/java/com/android/server/CountryDetectorService.java
+++ b/services/java/com/android/server/CountryDetectorService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.HashMap;
import com.android.server.location.ComprehensiveCountryDetector;
@@ -30,6 +32,8 @@
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
import android.util.Slog;
/**
@@ -75,7 +79,7 @@
}
}
- private final static String TAG = "CountryDetectorService";
+ private final static String TAG = "CountryDetector";
private final HashMap<IBinder, Receiver> mReceivers;
private final Context mContext;
@@ -201,4 +205,20 @@
boolean isSystemReady() {
return mSystemReady;
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ try {
+ final Printer p = new PrintWriterPrinter(fout);
+ p.println("CountryDetectorService state:");
+ p.println(" Number of listeners=" + mReceivers.keySet().size());
+ if (mCountryDetector == null) {
+ p.println(" ComprehensiveCountryDetector not initialized");
+ } else {
+ p.println(" " + mCountryDetector.toString());
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to dump CountryDetectorService: ", e);
+ }
+ }
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index cb291cef..016dc82 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -152,8 +152,12 @@
/* Wifi disabled due to airplane mode on */
private static final int WIFI_DISABLED_AIRPLANE_ON = 3;
- private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
+ /* Persisted state that tracks the wifi & airplane interaction from settings */
+ private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
+ /* Tracks current airplane mode state */
private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
+ /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
+ private boolean mWifiEnabled;
private boolean mIsReceiverRegistered = false;
@@ -373,8 +377,8 @@
mAirplaneModeOn.set(isAirplaneModeOn());
/* On airplane mode disable, restore wifi state if necessary */
if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
- mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
- persistWifiEnabled(true);
+ mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
+ persistWifiState(true);
}
updateWifiState();
}
@@ -391,7 +395,12 @@
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- // reset & clear notification on any wifi state change
+ int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_DISABLED);
+
+ mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
+
+ // reset & clear notification on any wifi state change
resetNotification();
} else if (intent.getAction().equals(
WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
@@ -435,7 +444,7 @@
*/
public void checkAndStartWifi() {
mAirplaneModeOn.set(isAirplaneModeOn());
- mWifiState.set(getPersistedWifiState());
+ mPersistWifiState.set(getPersistedWifiState());
/* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
@@ -472,29 +481,30 @@
private boolean shouldWifiBeEnabled() {
if (mAirplaneModeOn.get()) {
- return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+ return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
} else {
- return mWifiState.get() != WIFI_DISABLED;
+ return mPersistWifiState.get() != WIFI_DISABLED;
}
}
- private void persistWifiEnabled(boolean enabled) {
+ private void persistWifiState(boolean enabled) {
final ContentResolver cr = mContext.getContentResolver();
boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
if (enabled) {
if (airplane) {
- mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+ mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
} else {
- mWifiState.set(WIFI_ENABLED);
+ mPersistWifiState.set(WIFI_ENABLED);
}
} else {
if (airplane) {
- mWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
+ mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
} else {
- mWifiState.set(WIFI_DISABLED);
+ mPersistWifiState.set(WIFI_DISABLED);
}
}
- Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
+
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get());
}
@@ -545,7 +555,6 @@
*/
public synchronized boolean setWifiEnabled(boolean enable) {
enforceChangePermission();
-
if (DBG) {
Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
}
@@ -559,16 +568,20 @@
* Caller might not have WRITE_SECURE_SETTINGS,
* only CHANGE_WIFI_STATE is enforced
*/
- long ident = Binder.clearCallingIdentity();
- persistWifiEnabled(enable);
- Binder.restoreCallingIdentity(ident);
+
+ /* Avoids overriding of airplane state when wifi is already in the expected state */
+ if (enable != mWifiEnabled) {
+ long ident = Binder.clearCallingIdentity();
+ persistWifiState(enable);
+ Binder.restoreCallingIdentity(ident);
+ }
if (enable) {
if (!mIsReceiverRegistered) {
registerForBroadcasts();
mIsReceiverRegistered = true;
}
- } else if (mIsReceiverRegistered){
+ } else if (mIsReceiverRegistered) {
mContext.unregisterReceiver(mReceiver);
mIsReceiverRegistered = false;
}
@@ -663,7 +676,12 @@
*/
public List<WifiConfiguration> getConfiguredNetworks() {
enforceAccessPermission();
- return mWifiStateMachine.syncGetConfiguredNetworks();
+ if (mWifiStateMachineChannel != null) {
+ return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel);
+ } else {
+ Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ return null;
+ }
}
/**
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b1551a6..bc8ce7d 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -118,7 +118,7 @@
"192.168.48.2", "192.168.48.254",
};
- private String[] mDnsServers;
+ private String[] mDefaultDnsServers;
private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
@@ -171,9 +171,9 @@
updateConfiguration();
// TODO - remove and rely on real notifications of the current iface
- mDnsServers = new String[2];
- mDnsServers[0] = DNS_DEFAULT_SERVER1;
- mDnsServers[1] = DNS_DEFAULT_SERVER2;
+ mDefaultDnsServers = new String[2];
+ mDefaultDnsServers[0] = DNS_DEFAULT_SERVER1;
+ mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
}
void updateConfiguration() {
@@ -1244,7 +1244,7 @@
}
}
try {
- mNMService.setDnsForwarders(mDnsServers);
+ mNMService.setDnsForwarders(mDefaultDnsServers);
} catch (Exception e) {
transitionTo(mSetDnsForwardersErrorState);
return false;
@@ -1320,7 +1320,19 @@
try {
linkProperties = mConnService.getLinkProperties(upType);
} catch (RemoteException e) { }
- if (linkProperties != null) iface = linkProperties.getInterfaceName();
+ if (linkProperties != null) {
+ iface = linkProperties.getInterfaceName();
+ String[] dnsServers = mDefaultDnsServers;
+ Collection<InetAddress> dnses = linkProperties.getDnses();
+ if (dnses != null) {
+ dnsServers = NetworkUtils.makeStrings(dnses);
+ }
+ try {
+ mNMService.setDnsForwarders(dnsServers);
+ } catch (Exception e) {
+ transitionTo(mSetDnsForwardersErrorState);
+ }
+ }
}
notifyTetheredOfNewUpstreamIface(iface);
}
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 55e0678..72cf512 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -482,6 +482,7 @@
if (state.exists()) {
throw new IllegalStateException("Cannot delete the state");
}
+ new File("/data/misc/vpn/abort").delete();
// Check if we need to restart any of the daemons.
boolean restart = false;
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
index f068b44..2d6a148 100755
--- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
@@ -20,16 +20,19 @@
import android.location.Country;
import android.location.CountryListener;
import android.location.Geocoder;
+import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Slog;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.concurrent.ConcurrentLinkedQueue;
/**
* This class is used to detect the country where the user is. The sources of
@@ -55,10 +58,15 @@
*/
public class ComprehensiveCountryDetector extends CountryDetectorBase {
- private final static String TAG = "ComprehensiveCountryDetector";
+ private final static String TAG = "CountryDetector";
/* package */ static final boolean DEBUG = false;
/**
+ * Max length of logs to maintain for debugging.
+ */
+ private static final int MAX_LENGTH_DEBUG_LOGS = 20;
+
+ /**
* The refresh interval when the location based country was used
*/
private final static long LOCATION_REFRESH_INTERVAL = 1000 * 60 * 60 * 24; // 1 day
@@ -74,6 +82,52 @@
private PhoneStateListener mPhoneStateListener;
/**
+ * List of the most recent country state changes for debugging. This should have
+ * a max length of MAX_LENGTH_LOGS.
+ */
+ private final ConcurrentLinkedQueue<Country> mDebugLogs = new ConcurrentLinkedQueue<Country>();
+
+ /**
+ * Most recent {@link Country} result that was added to the debug logs {@link #mDebugLogs}.
+ * We keep track of this value to help prevent adding many of the same {@link Country} objects
+ * to the logs.
+ */
+ private Country mLastCountryAddedToLogs;
+
+ /**
+ * Object used to synchronize access to {@link #mLastCountryAddedToLogs}. Be careful if
+ * using it to synchronize anything else in this file.
+ */
+ private final Object mObject = new Object();
+
+ /**
+ * Start time of the current session for which the detector has been active.
+ */
+ private long mStartTime;
+
+ /**
+ * Stop time of the most recent session for which the detector was active.
+ */
+ private long mStopTime;
+
+ /**
+ * The sum of all the time intervals in which the detector was active.
+ */
+ private long mTotalTime;
+
+ /**
+ * Number of {@link PhoneStateListener#onServiceStateChanged(ServiceState state)} events that
+ * have occurred for the current session for which the detector has been active.
+ */
+ private int mCountServiceStateChanges;
+
+ /**
+ * Total number of {@link PhoneStateListener#onServiceStateChanged(ServiceState state)} events
+ * that have occurred for all time intervals in which the detector has been active.
+ */
+ private int mTotalCountServiceStateChanges;
+
+ /**
* The listener for receiving the notification from LocationBasedCountryDetector.
*/
private CountryListener mLocationBasedCountryDetectionListener = new CountryListener() {
@@ -124,9 +178,36 @@
if (result == null) {
result = getLocaleCountry();
}
+ addToLogs(result);
return result;
}
+ /**
+ * Attempt to add this {@link Country} to the debug logs.
+ */
+ private void addToLogs(Country country) {
+ if (country == null) {
+ return;
+ }
+ // If the country (ISO and source) are the same as before, then there is no
+ // need to add this country as another entry in the logs. Synchronize access to this
+ // variable since multiple threads could be calling this method.
+ synchronized (mObject) {
+ if (mLastCountryAddedToLogs != null && mLastCountryAddedToLogs.equals(country)) {
+ return;
+ }
+ mLastCountryAddedToLogs = country;
+ }
+ // Manually maintain a max limit for the list of logs
+ if (mDebugLogs.size() >= MAX_LENGTH_DEBUG_LOGS) {
+ mDebugLogs.poll();
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Slog.d(TAG, country.toString());
+ }
+ mDebugLogs.add(country);
+ }
+
private boolean isNetworkCountryCodeAvailable() {
// On CDMA TelephonyManager.getNetworkCountryIso() just returns SIM country. We don't want
// to prioritize it over location based country, so ignore it.
@@ -218,9 +299,14 @@
removePhoneStateListener();
stopLocationBasedDetector();
cancelLocationRefresh();
+ mStopTime = SystemClock.elapsedRealtime();
+ mTotalTime += mStopTime;
} else if (prevListener == null) {
addPhoneStateListener();
detectCountry(false, true);
+ mStartTime = SystemClock.elapsedRealtime();
+ mStopTime = 0;
+ mCountServiceStateChanges = 0;
}
}
@@ -308,9 +394,9 @@
private void notifyIfCountryChanged(final Country country, final Country detectedCountry) {
if (detectedCountry != null && mListener != null
&& (country == null || !country.equals(detectedCountry))) {
- Slog.d(TAG,
- "The country was changed from " + country != null ? country.getCountryIso() :
- country + " to " + detectedCountry.getCountryIso());
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Slog.d(TAG, "" + country + " --> " + detectedCountry);
+ }
notifyListener(detectedCountry);
}
}
@@ -352,6 +438,9 @@
mPhoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
+ mCountServiceStateChanges++;
+ mTotalCountServiceStateChanges++;
+
if (!isNetworkCountryCodeAvailable()) {
return;
}
@@ -374,4 +463,30 @@
protected boolean isGeoCoderImplemented() {
return Geocoder.isPresent();
}
+
+ @Override
+ public String toString() {
+ long currentTime = SystemClock.elapsedRealtime();
+ long currentSessionLength = 0;
+ StringBuilder sb = new StringBuilder();
+ sb.append("ComprehensiveCountryDetector{");
+ // The detector hasn't stopped yet --> still running
+ if (mStopTime == 0) {
+ currentSessionLength = currentTime - mStartTime;
+ sb.append("timeRunning=" + currentSessionLength + ", ");
+ } else {
+ // Otherwise, it has already stopped, so take the last session
+ sb.append("lastRunTimeLength=" + (mStopTime - mStartTime) + ", ");
+ }
+ sb.append("totalCountServiceStateChanges=" + mTotalCountServiceStateChanges + ", ");
+ sb.append("currentCountServiceStateChanges=" + mCountServiceStateChanges + ", ");
+ sb.append("totalTime=" + (mTotalTime + currentSessionLength) + ", ");
+ sb.append("currentTime=" + currentTime + ", ");
+ sb.append("countries=");
+ for (Country country : mDebugLogs) {
+ sb.append("\n " + country.toString());
+ }
+ sb.append("}");
+ return sb.toString();
+ }
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 871ed68..f660520 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -1060,8 +1060,10 @@
}
// clear UID from current stats snapshot
- mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
- mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
+ if (mLastPollUidSnapshot != null) {
+ mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
+ mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
+ }
// clear kernel stats associated with UID
resetKernelUidStats(uid);
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 568a485..d345411 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -22,6 +22,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
+import android.net.NetworkInfo.DetailedState;
import android.net.ProxyProperties;
import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration.IpAssignment;
@@ -31,6 +32,9 @@
import android.net.wifi.NetworkUpdateResult;
import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
import android.os.Environment;
+import android.os.Message;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Log;
@@ -50,6 +54,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This class provides the API to manage configured
@@ -136,6 +141,13 @@
private static final String EXCLUSION_LIST_KEY = "exclusionList";
private static final String EOS = "eos";
+ private static HandlerThread sDiskWriteHandlerThread;
+ private static DiskWriteHandler sDiskWriteHandler;
+ private static Object sDiskWriteHandlerSync = new Object();
+ /* Tracks multiple writes on the same thread */
+ private static int sWriteSequence = 0;
+ private static final int WRITE = 1;
+
/**
* Initialize context, fetch the list of configured networks
* and enable all stored networks in supplicant.
@@ -153,10 +165,8 @@
*/
static List<WifiConfiguration> getConfiguredNetworks() {
List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
- synchronized (sConfiguredNetworks) {
- for(WifiConfiguration config : sConfiguredNetworks.values()) {
- networks.add(new WifiConfiguration(config));
- }
+ for(WifiConfiguration config : sConfiguredNetworks.values()) {
+ networks.add(new WifiConfiguration(config));
}
return networks;
}
@@ -167,15 +177,13 @@
*/
static void enableAllNetworks() {
boolean networkEnabledStateChanged = false;
- synchronized (sConfiguredNetworks) {
- for(WifiConfiguration config : sConfiguredNetworks.values()) {
- if(config != null && config.status == Status.DISABLED) {
- if(WifiNative.enableNetworkCommand(config.networkId, false)) {
- networkEnabledStateChanged = true;
- config.status = Status.ENABLED;
- } else {
- loge("Enable network failed on " + config.networkId);
- }
+ for(WifiConfiguration config : sConfiguredNetworks.values()) {
+ if(config != null && config.status == Status.DISABLED) {
+ if(WifiNative.enableNetworkCommand(config.networkId, false)) {
+ networkEnabledStateChanged = true;
+ config.status = Status.ENABLED;
+ } else {
+ loge("Enable network failed on " + config.networkId);
}
}
}
@@ -226,12 +234,10 @@
static void selectNetwork(int netId) {
// Reset the priority of each network at start or if it goes too high.
if (sLastPriority == -1 || sLastPriority > 1000000) {
- synchronized (sConfiguredNetworks) {
- for(WifiConfiguration config : sConfiguredNetworks.values()) {
- if (config.networkId != INVALID_NETWORK_ID) {
- config.priority = 0;
- addOrUpdateNetworkNative(config);
- }
+ for(WifiConfiguration config : sConfiguredNetworks.values()) {
+ if (config.networkId != INVALID_NETWORK_ID) {
+ config.priority = 0;
+ addOrUpdateNetworkNative(config);
}
}
sLastPriority = 0;
@@ -264,15 +270,31 @@
/* enable a new network */
if (newNetwork && netId != INVALID_NETWORK_ID) {
WifiNative.enableNetworkCommand(netId, false);
- synchronized (sConfiguredNetworks) {
- sConfiguredNetworks.get(netId).status = Status.ENABLED;
- }
+ sConfiguredNetworks.get(netId).status = Status.ENABLED;
}
WifiNative.saveConfigCommand();
sendConfiguredNetworksChangedBroadcast();
return result;
}
+ static void updateStatus(int netId, DetailedState state) {
+ if (netId != INVALID_NETWORK_ID) {
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config == null) return;
+ switch (state) {
+ case CONNECTED:
+ config.status = Status.CURRENT;
+ break;
+ case DISCONNECTED:
+ config.status = Status.ENABLED;
+ break;
+ default:
+ //do nothing, retain the existing state
+ break;
+ }
+ }
+ }
+
/**
* Forget the specified network and save config
*
@@ -281,12 +303,10 @@
static void forgetNetwork(int netId) {
if (WifiNative.removeNetworkCommand(netId)) {
WifiNative.saveConfigCommand();
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) {
- sConfiguredNetworks.remove(netId);
- sNetworkIds.remove(configKey(config));
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null) {
+ sConfiguredNetworks.remove(netId);
+ sNetworkIds.remove(configKey(config));
}
writeIpAndProxyConfigurations();
sendConfiguredNetworksChangedBroadcast();
@@ -319,13 +339,11 @@
*/
static boolean removeNetwork(int netId) {
boolean ret = WifiNative.removeNetworkCommand(netId);
- synchronized (sConfiguredNetworks) {
- if (ret) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) {
- sConfiguredNetworks.remove(netId);
- sNetworkIds.remove(configKey(config));
- }
+ if (ret) {
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null) {
+ sConfiguredNetworks.remove(netId);
+ sNetworkIds.remove(configKey(config));
}
}
sendConfiguredNetworksChangedBroadcast();
@@ -349,10 +367,8 @@
static boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) {
boolean ret = WifiNative.enableNetworkCommand(netId, disableOthers);
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) config.status = Status.ENABLED;
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null) config.status = Status.ENABLED;
if (disableOthers) {
markAllNetworksDisabledExcept(netId);
@@ -375,13 +391,11 @@
*/
static boolean disableNetwork(int netId, int reason) {
boolean ret = WifiNative.disableNetworkCommand(netId);
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- /* Only change the reason if the network was not previously disabled */
- if (config != null && config.status != Status.DISABLED) {
- config.status = Status.DISABLED;
- config.disableReason = reason;
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ /* Only change the reason if the network was not previously disabled */
+ if (config != null && config.status != Status.DISABLED) {
+ config.status = Status.DISABLED;
+ config.disableReason = reason;
}
sendConfiguredNetworksChangedBroadcast();
return ret;
@@ -450,10 +464,8 @@
* Fetch the link properties for a given network id
*/
static LinkProperties getLinkProperties(int netId) {
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) return new LinkProperties(config.linkProperties);
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null) return new LinkProperties(config.linkProperties);
return null;
}
@@ -493,15 +505,13 @@
static void setIpConfiguration(int netId, DhcpInfoInternal dhcpInfo) {
LinkProperties linkProperties = dhcpInfo.makeLinkProperties();
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) {
- // add old proxy details
- if(config.linkProperties != null) {
- linkProperties.setHttpProxy(config.linkProperties.getHttpProxy());
- }
- config.linkProperties = linkProperties;
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null) {
+ // add old proxy details
+ if(config.linkProperties != null) {
+ linkProperties.setHttpProxy(config.linkProperties.getHttpProxy());
}
+ config.linkProperties = linkProperties;
}
}
@@ -509,14 +519,12 @@
* clear IP configuration for a given network id
*/
static void clearIpConfiguration(int netId) {
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null && config.linkProperties != null) {
- // Clear everything except proxy
- ProxyProperties proxy = config.linkProperties.getHttpProxy();
- config.linkProperties.clear();
- config.linkProperties.setHttpProxy(proxy);
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null && config.linkProperties != null) {
+ // Clear everything except proxy
+ ProxyProperties proxy = config.linkProperties.getHttpProxy();
+ config.linkProperties.clear();
+ config.linkProperties.setHttpProxy(proxy);
}
}
@@ -536,11 +544,9 @@
* Return if the specified network is using static IP
*/
static boolean isUsingStaticIp(int netId) {
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null && config.ipAssignment == IpAssignment.STATIC) {
- return true;
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null && config.ipAssignment == IpAssignment.STATIC) {
+ return true;
}
return false;
}
@@ -555,67 +561,62 @@
String listStr = WifiNative.listNetworksCommand();
sLastPriority = 0;
- synchronized (sConfiguredNetworks) {
- sConfiguredNetworks.clear();
- sNetworkIds.clear();
+ sConfiguredNetworks.clear();
+ sNetworkIds.clear();
- if (listStr == null)
- return;
+ if (listStr == null)
+ return;
- String[] lines = listStr.split("\n");
- // Skip the first line, which is a header
- for (int i = 1; i < lines.length; i++) {
- String[] result = lines[i].split("\t");
- // network-id | ssid | bssid | flags
- WifiConfiguration config = new WifiConfiguration();
- try {
- config.networkId = Integer.parseInt(result[0]);
- } catch(NumberFormatException e) {
- continue;
- }
- if (result.length > 3) {
- if (result[3].indexOf("[CURRENT]") != -1)
- config.status = WifiConfiguration.Status.CURRENT;
- else if (result[3].indexOf("[DISABLED]") != -1)
- config.status = WifiConfiguration.Status.DISABLED;
- else
- config.status = WifiConfiguration.Status.ENABLED;
- } else {
- config.status = WifiConfiguration.Status.ENABLED;
- }
- readNetworkVariables(config);
- if (config.priority > sLastPriority) {
- sLastPriority = config.priority;
- }
- sConfiguredNetworks.put(config.networkId, config);
- sNetworkIds.put(configKey(config), config.networkId);
+ String[] lines = listStr.split("\n");
+ // Skip the first line, which is a header
+ for (int i = 1; i < lines.length; i++) {
+ String[] result = lines[i].split("\t");
+ // network-id | ssid | bssid | flags
+ WifiConfiguration config = new WifiConfiguration();
+ try {
+ config.networkId = Integer.parseInt(result[0]);
+ } catch(NumberFormatException e) {
+ continue;
}
+ if (result.length > 3) {
+ if (result[3].indexOf("[CURRENT]") != -1)
+ config.status = WifiConfiguration.Status.CURRENT;
+ else if (result[3].indexOf("[DISABLED]") != -1)
+ config.status = WifiConfiguration.Status.DISABLED;
+ else
+ config.status = WifiConfiguration.Status.ENABLED;
+ } else {
+ config.status = WifiConfiguration.Status.ENABLED;
+ }
+ readNetworkVariables(config);
+ if (config.priority > sLastPriority) {
+ sLastPriority = config.priority;
+ }
+ sConfiguredNetworks.put(config.networkId, config);
+ sNetworkIds.put(configKey(config), config.networkId);
}
+
readIpAndProxyConfigurations();
sendConfiguredNetworksChangedBroadcast();
}
static void updateIpAndProxyFromWpsConfig(int netId, WpsInfo wpsConfig) {
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) {
- config.ipAssignment = wpsConfig.ipAssignment;
- config.proxySettings = wpsConfig.proxySettings;
- config.linkProperties = wpsConfig.linkProperties;
- writeIpAndProxyConfigurations();
- }
+ WifiConfiguration config = sConfiguredNetworks.get(netId);
+ if (config != null) {
+ config.ipAssignment = wpsConfig.ipAssignment;
+ config.proxySettings = wpsConfig.proxySettings;
+ config.linkProperties = wpsConfig.linkProperties;
+ writeIpAndProxyConfigurations();
}
}
/* Mark all networks except specified netId as disabled */
private static void markAllNetworksDisabledExcept(int netId) {
- synchronized (sConfiguredNetworks) {
- for(WifiConfiguration config : sConfiguredNetworks.values()) {
- if(config != null && config.networkId != netId) {
- if (config.status != Status.DISABLED) {
- config.status = Status.DISABLED;
- config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON;
- }
+ for(WifiConfiguration config : sConfiguredNetworks.values()) {
+ if(config != null && config.networkId != netId) {
+ if (config.status != Status.DISABLED) {
+ config.status = Status.DISABLED;
+ config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON;
}
}
}
@@ -627,15 +628,46 @@
private static void writeIpAndProxyConfigurations() {
- DataOutputStream out = null;
- try {
- out = new DataOutputStream(new BufferedOutputStream(
- new FileOutputStream(ipConfigFile)));
+ /* Make a copy */
+ List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
+ for(WifiConfiguration config : sConfiguredNetworks.values()) {
+ networks.add(new WifiConfiguration(config));
+ }
- out.writeInt(IPCONFIG_FILE_VERSION);
+ /* Do a delayed write to disk on a seperate handler thread */
+ synchronized (sDiskWriteHandlerSync) {
+ if (++sWriteSequence == 1) {
+ sDiskWriteHandlerThread = new HandlerThread("WifiConfigThread");
+ sDiskWriteHandlerThread.start();
+ sDiskWriteHandler = new DiskWriteHandler(sDiskWriteHandlerThread.getLooper());
+ }
+ }
- synchronized (sConfiguredNetworks) {
- for(WifiConfiguration config : sConfiguredNetworks.values()) {
+ sDiskWriteHandler.sendMessage(Message.obtain(sDiskWriteHandler, WRITE, networks));
+ }
+
+ private static class DiskWriteHandler extends Handler {
+
+ DiskWriteHandler(android.os.Looper l) {
+ super(l);
+ }
+
+ public void handleMessage(Message msg) {
+
+ if (msg.what != WRITE) {
+ throw new RuntimeException("Unsupported message in WifiConfigStore: " + msg);
+ }
+
+ List<WifiConfiguration> networks = (List<WifiConfiguration>) msg.obj;
+
+ DataOutputStream out = null;
+ try {
+ out = new DataOutputStream(new BufferedOutputStream(
+ new FileOutputStream(ipConfigFile)));
+
+ out.writeInt(IPCONFIG_FILE_VERSION);
+
+ for(WifiConfiguration config : networks) {
boolean writeToFile = false;
try {
@@ -720,17 +752,26 @@
}
out.writeUTF(EOS);
}
- }
- } catch (IOException e) {
- loge("Error writing data file");
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (Exception e) {}
+ } catch (IOException e) {
+ loge("Error writing data file");
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (Exception e) {}
+ }
+
+ //Quit if no more writes sent
+ synchronized (sDiskWriteHandlerSync) {
+ if (--sWriteSequence == 0) {
+ getLooper().quit();
+ sDiskWriteHandlerThread = null;
+ sDiskWriteHandler= null;
+ }
+ }
}
- }
+ }
}
private static void readIpAndProxyConfigurations() {
@@ -806,44 +847,42 @@
} while (true);
if (id != -1) {
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(
- sNetworkIds.get(id));
+ WifiConfiguration config = sConfiguredNetworks.get(
+ sNetworkIds.get(id));
- if (config == null) {
- loge("configuration found for missing network, ignored");
- } else {
- config.linkProperties = linkProperties;
- switch (ipAssignment) {
- case STATIC:
- case DHCP:
- config.ipAssignment = ipAssignment;
- break;
- case UNASSIGNED:
- //Ignore
- break;
- default:
- loge("Ignore invalid ip assignment while reading");
- break;
- }
+ if (config == null) {
+ loge("configuration found for missing network, ignored");
+ } else {
+ config.linkProperties = linkProperties;
+ switch (ipAssignment) {
+ case STATIC:
+ case DHCP:
+ config.ipAssignment = ipAssignment;
+ break;
+ case UNASSIGNED:
+ //Ignore
+ break;
+ default:
+ loge("Ignore invalid ip assignment while reading");
+ break;
+ }
- switch (proxySettings) {
- case STATIC:
- config.proxySettings = proxySettings;
- ProxyProperties proxyProperties =
- new ProxyProperties(proxyHost, proxyPort, exclusionList);
- linkProperties.setHttpProxy(proxyProperties);
- break;
- case NONE:
- config.proxySettings = proxySettings;
- break;
- case UNASSIGNED:
- //Ignore
- break;
- default:
- loge("Ignore invalid proxy settings while reading");
- break;
- }
+ switch (proxySettings) {
+ case STATIC:
+ config.proxySettings = proxySettings;
+ ProxyProperties proxyProperties =
+ new ProxyProperties(proxyHost, proxyPort, exclusionList);
+ linkProperties.setHttpProxy(proxyProperties);
+ break;
+ case NONE:
+ config.proxySettings = proxySettings;
+ break;
+ case UNASSIGNED:
+ //Ignore
+ break;
+ default:
+ loge("Ignore invalid proxy settings while reading");
+ break;
}
}
} else {
@@ -1061,10 +1100,7 @@
* when written. For example, wep key is stored as * irrespective
* of the value sent to the supplicant
*/
- WifiConfiguration sConfig;
- synchronized (sConfiguredNetworks) {
- sConfig = sConfiguredNetworks.get(netId);
- }
+ WifiConfiguration sConfig = sConfiguredNetworks.get(netId);
if (sConfig == null) {
sConfig = new WifiConfiguration();
sConfig.networkId = netId;
@@ -1072,10 +1108,8 @@
readNetworkVariables(sConfig);
- synchronized (sConfiguredNetworks) {
- sConfiguredNetworks.put(netId, sConfig);
- sNetworkIds.put(configKey(sConfig), netId);
- }
+ sConfiguredNetworks.put(netId, sConfig);
+ sNetworkIds.put(configKey(sConfig), netId);
NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(sConfig, config);
result.setNetworkId(netId);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 5437caa..71d7c01 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -276,6 +276,8 @@
static final int CMD_CLEAR_BLACKLIST = BASE + 58;
/* Save configuration */
static final int CMD_SAVE_CONFIG = BASE + 59;
+ /* Get configured networks*/
+ static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 60;
/* Supplicant commands after driver start*/
/* Initiate a scan */
@@ -847,8 +849,11 @@
return result;
}
- public List<WifiConfiguration> syncGetConfiguredNetworks() {
- return WifiConfigStore.getConfiguredNetworks();
+ public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) {
+ Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS);
+ List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
+ resultMsg.recycle();
+ return result;
}
/**
@@ -1637,8 +1642,10 @@
mWifiInfo.setRssi(MIN_RSSI);
mWifiInfo.setLinkSpeed(-1);
- /* send event to CM & network change broadcast */
setNetworkDetailedState(DetailedState.DISCONNECTED);
+ WifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
+
+ /* send event to CM & network change broadcast */
sendNetworkStateChangeBroadcast(mLastBssid);
/* Clear network properties */
@@ -1721,6 +1728,7 @@
} else {
configureLinkProperties();
setNetworkDetailedState(DetailedState.CONNECTED);
+ WifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
sendNetworkStateChangeBroadcast(mLastBssid);
}
}
@@ -1811,6 +1819,10 @@
case CMD_SAVE_CONFIG:
mReplyChannel.replyToMessage(message, message.what, FAILURE);
break;
+ case CMD_GET_CONFIGURED_NETWORKS:
+ mReplyChannel.replyToMessage(message, message.what,
+ WifiConfigStore.getConfiguredNetworks());
+ break;
case CMD_ENABLE_RSSI_POLL:
mEnableRssiPolling = (message.arg1 == 1);
break;